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 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 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 * 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 * 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