1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * drivers/pci/rom.c 4 * 5 * (C) Copyright 2004 Jon Smirl <jonsmirl@yahoo.com> 6 * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <jbarnes@sgi.com> 7 * 8 * PCI ROM access routines 9 */ 10 #include <linux/kernel.h> 11 #include <linux/export.h> 12 #include <linux/pci.h> 13 #include <linux/slab.h> 14 15 #include "pci.h" 16 17 /** 18 * pci_enable_rom - enable ROM decoding for a PCI device 19 * @pdev: PCI device to enable 20 * 21 * Enable ROM decoding on @dev. This involves simply turning on the last 22 * bit of the PCI ROM BAR. Note that some cards may share address decoders 23 * between the ROM and other resources, so enabling it may disable access 24 * to MMIO registers or other card memory. 25 */ 26 int pci_enable_rom(struct pci_dev *pdev) 27 { 28 struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; 29 struct pci_bus_region region; 30 u32 rom_addr; 31 32 if (!res->flags) 33 return -1; 34 35 /* Nothing to enable if we're using a shadow copy in RAM */ 36 if (res->flags & IORESOURCE_ROM_SHADOW) 37 return 0; 38 39 /* 40 * Ideally pci_update_resource() would update the ROM BAR address, 41 * and we would only set the enable bit here. But apparently some 42 * devices have buggy ROM BARs that read as zero when disabled. 43 */ 44 pcibios_resource_to_bus(pdev->bus, ®ion, res); 45 pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr); 46 rom_addr &= ~PCI_ROM_ADDRESS_MASK; 47 rom_addr |= region.start | PCI_ROM_ADDRESS_ENABLE; 48 pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr); 49 return 0; 50 } 51 EXPORT_SYMBOL_GPL(pci_enable_rom); 52 53 /** 54 * pci_disable_rom - disable ROM decoding for a PCI device 55 * @pdev: PCI device to disable 56 * 57 * Disable ROM decoding on a PCI device by turning off the last bit in the 58 * ROM BAR. 59 */ 60 void pci_disable_rom(struct pci_dev *pdev) 61 { 62 struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; 63 u32 rom_addr; 64 65 if (res->flags & IORESOURCE_ROM_SHADOW) 66 return; 67 68 pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr); 69 rom_addr &= ~PCI_ROM_ADDRESS_ENABLE; 70 pci_write_config_dword(pdev, pdev->rom_base_reg, rom_addr); 71 } 72 EXPORT_SYMBOL_GPL(pci_disable_rom); 73 74 /** 75 * pci_get_rom_size - obtain the actual size of the ROM image 76 * @pdev: target PCI device 77 * @rom: kernel virtual pointer to image of ROM 78 * @size: size of PCI window 79 * return: size of actual ROM image 80 * 81 * Determine the actual length of the ROM image. 82 * The PCI window size could be much larger than the 83 * actual image size. 84 */ 85 size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) 86 { 87 void __iomem *image; 88 int last_image; 89 unsigned length; 90 91 image = rom; 92 do { 93 void __iomem *pds; 94 /* Standard PCI ROMs start out with these bytes 55 AA */ 95 if (readw(image) != 0xAA55) { 96 pci_info(pdev, "Invalid PCI ROM header signature: expecting 0xaa55, got %#06x\n", 97 readw(image)); 98 break; 99 } 100 /* get the PCI data structure and check its "PCIR" signature */ 101 pds = image + readw(image + 24); 102 if (readl(pds) != 0x52494350) { 103 pci_info(pdev, "Invalid PCI ROM data signature: expecting 0x52494350, got %#010x\n", 104 readl(pds)); 105 break; 106 } 107 last_image = readb(pds + 21) & 0x80; 108 length = readw(pds + 16); 109 image += length * 512; 110 /* Avoid iterating through memory outside the resource window */ 111 if (image > rom + size) 112 break; 113 } while (length && !last_image); 114 115 /* never return a size larger than the PCI resource window */ 116 /* there are known ROMs that get the size wrong */ 117 return min((size_t)(image - rom), size); 118 } 119 120 /** 121 * pci_map_rom - map a PCI ROM to kernel space 122 * @pdev: pointer to pci device struct 123 * @size: pointer to receive size of pci window over ROM 124 * 125 * Return: kernel virtual pointer to image of ROM 126 * 127 * Map a PCI ROM into kernel space. If ROM is boot video ROM, 128 * the shadow BIOS copy will be returned instead of the 129 * actual ROM. 130 */ 131 void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) 132 { 133 struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; 134 loff_t start; 135 void __iomem *rom; 136 137 /* assign the ROM an address if it doesn't have one */ 138 if (res->parent == NULL && pci_assign_resource(pdev, PCI_ROM_RESOURCE)) 139 return NULL; 140 141 start = pci_resource_start(pdev, PCI_ROM_RESOURCE); 142 *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); 143 if (*size == 0) 144 return NULL; 145 146 /* Enable ROM space decodes */ 147 if (pci_enable_rom(pdev)) 148 return NULL; 149 150 rom = ioremap(start, *size); 151 if (!rom) 152 goto err_ioremap; 153 154 /* 155 * Try to find the true size of the ROM since sometimes the PCI window 156 * size is much larger than the actual size of the ROM. 157 * True size is important if the ROM is going to be copied. 158 */ 159 *size = pci_get_rom_size(pdev, rom, *size); 160 if (!*size) 161 goto invalid_rom; 162 163 return rom; 164 165 invalid_rom: 166 iounmap(rom); 167 err_ioremap: 168 /* restore enable if ioremap fails */ 169 if (!(res->flags & IORESOURCE_ROM_ENABLE)) 170 pci_disable_rom(pdev); 171 return NULL; 172 } 173 EXPORT_SYMBOL(pci_map_rom); 174 175 /** 176 * pci_unmap_rom - unmap the ROM from kernel space 177 * @pdev: pointer to pci device struct 178 * @rom: virtual address of the previous mapping 179 * 180 * Remove a mapping of a previously mapped ROM 181 */ 182 void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom) 183 { 184 struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; 185 186 iounmap(rom); 187 188 /* Disable again before continuing */ 189 if (!(res->flags & IORESOURCE_ROM_ENABLE)) 190 pci_disable_rom(pdev); 191 } 192 EXPORT_SYMBOL(pci_unmap_rom); 193 194 /** 195 * pci_platform_rom - provides a pointer to any ROM image provided by the 196 * platform 197 * @pdev: pointer to pci device struct 198 * @size: pointer to receive size of pci window over ROM 199 */ 200 void __iomem *pci_platform_rom(struct pci_dev *pdev, size_t *size) 201 { 202 if (pdev->rom && pdev->romlen) { 203 *size = pdev->romlen; 204 return phys_to_virt((phys_addr_t)pdev->rom); 205 } 206 207 return NULL; 208 } 209 EXPORT_SYMBOL(pci_platform_rom); 210