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