1 /* $NetBSD: nouveau_nvkm_subdev_bios_shadowpci.c,v 1.5 2021/12/18 23:45:38 riastradh Exp $ */
2
3 /*
4 * Copyright 2012 Red Hat Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 */
25 #include <sys/cdefs.h>
26 __KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_bios_shadowpci.c,v 1.5 2021/12/18 23:45:38 riastradh Exp $");
27
28 #include "priv.h"
29
30 #include <core/pci.h>
31
32 #ifdef __NetBSD__
33 # define __iomem __pci_rom_iomem
34 #endif
35
36 struct priv {
37 struct pci_dev *pdev;
38 void __iomem *rom;
39 size_t size;
40 };
41
42 static u32
pcirom_read(void * data,u32 offset,u32 length,struct nvkm_bios * bios)43 pcirom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
44 {
45 struct priv *priv = data;
46 if (offset + length <= priv->size) {
47 memcpy_fromio(bios->data + offset, priv->rom + offset, length);
48 return length;
49 }
50 return 0;
51 }
52
53 static void
pcirom_fini(void * data)54 pcirom_fini(void *data)
55 {
56 struct priv *priv = data;
57 pci_unmap_rom(priv->pdev, priv->rom);
58 pci_disable_rom(priv->pdev);
59 kfree(priv);
60 }
61
62 static void *
pcirom_init(struct nvkm_bios * bios,const char * name)63 pcirom_init(struct nvkm_bios *bios, const char *name)
64 {
65 struct nvkm_device *device = bios->subdev.device;
66 struct priv *priv = NULL;
67 struct pci_dev *pdev;
68 int ret;
69
70 if (device->func->pci)
71 pdev = device->func->pci(device)->pdev;
72 else
73 return ERR_PTR(-ENODEV);
74
75 if (!(ret = pci_enable_rom(pdev))) {
76 if (ret = -ENOMEM,
77 (priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
78 if (ret = -EFAULT,
79 (priv->rom = pci_map_rom(pdev, &priv->size))) {
80 priv->pdev = pdev;
81 return priv;
82 }
83 kfree(priv);
84 }
85 pci_disable_rom(pdev);
86 }
87
88 return ERR_PTR(ret);
89 }
90
91 const struct nvbios_source
92 nvbios_pcirom = {
93 .name = "PCIROM",
94 .init = pcirom_init,
95 .fini = pcirom_fini,
96 .read = pcirom_read,
97 .rw = true,
98 };
99
100 static void *
platform_init(struct nvkm_bios * bios,const char * name)101 platform_init(struct nvkm_bios *bios, const char *name)
102 {
103 struct nvkm_device *device = bios->subdev.device;
104 struct pci_dev *pdev;
105 struct priv *priv;
106 int ret = -ENOMEM;
107
108 if (device->func->pci)
109 pdev = device->func->pci(device)->pdev;
110 else
111 return ERR_PTR(-ENODEV);
112
113 if ((priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
114 if (ret = -ENODEV,
115 (priv->rom = pci_platform_rom(pdev, &priv->size)))
116 return priv;
117 kfree(priv);
118 }
119
120 return ERR_PTR(ret);
121 }
122
123 const struct nvbios_source
124 nvbios_platform = {
125 .name = "PLATFORM",
126 .init = platform_init,
127 .fini = (void(*)(void *))kfree,
128 .read = pcirom_read,
129 .rw = true,
130 };
131