Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: Add PCI ROM helper for platform-provided ROM images

It turns out that some UEFI systems provide apparently an apparently valid
PCI ROM BAR that turns out to contain garbage, so the attempt in 547b52463
to prefer the ROM from the BAR actually breaks a different set of machines.
As Linus pointed out, the graphics drivers are probably in the best
position to make this judgement, so this basically reverts 547b52463 and
f9a37be0f and adds a new helper function. Followup patches will add support
to nouveau and radeon for probing this ROM source if they can't find a ROM
from some other source.

[bhelgaas: added reporter and bugzilla pointers, s/f4eb5ff05/547b52463]
Reference: https://bugzilla.redhat.com/show_bug.cgi?id=927451
Reference: http://lkml.kernel.org/r/kg69ef$vdb$1@ger.gmane.org
Reported-by: Mantas Mikulėnas <grawity@gmail.com>
Reported-by: Chris Murphy <bugzilla@colorremedies.com>
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>

authored by

Matthew Garrett and committed by
Bjorn Helgaas
fffe01f7 8bb96604

+32 -36
+31 -36
drivers/pci/rom.c
··· 100 100 return min((size_t)(image - rom), size); 101 101 } 102 102 103 - static loff_t pci_find_rom(struct pci_dev *pdev, size_t *size) 104 - { 105 - struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; 106 - loff_t start; 107 - 108 - /* assign the ROM an address if it doesn't have one */ 109 - if (res->parent == NULL && pci_assign_resource(pdev, PCI_ROM_RESOURCE)) 110 - return 0; 111 - start = pci_resource_start(pdev, PCI_ROM_RESOURCE); 112 - *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); 113 - 114 - if (*size == 0) 115 - return 0; 116 - 117 - /* Enable ROM space decodes */ 118 - if (pci_enable_rom(pdev)) 119 - return 0; 120 - 121 - return start; 122 - } 123 - 124 103 /** 125 104 * pci_map_rom - map a PCI ROM to kernel space 126 105 * @pdev: pointer to pci device struct ··· 114 135 void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) 115 136 { 116 137 struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; 117 - loff_t start = 0; 138 + loff_t start; 118 139 void __iomem *rom; 119 140 120 141 /* ··· 133 154 return (void __iomem *)(unsigned long) 134 155 pci_resource_start(pdev, PCI_ROM_RESOURCE); 135 156 } else { 136 - start = pci_find_rom(pdev, size); 157 + /* assign the ROM an address if it doesn't have one */ 158 + if (res->parent == NULL && 159 + pci_assign_resource(pdev,PCI_ROM_RESOURCE)) 160 + return NULL; 161 + start = pci_resource_start(pdev, PCI_ROM_RESOURCE); 162 + *size = pci_resource_len(pdev, PCI_ROM_RESOURCE); 163 + if (*size == 0) 164 + return NULL; 165 + 166 + /* Enable ROM space decodes */ 167 + if (pci_enable_rom(pdev)) 168 + return NULL; 137 169 } 138 170 } 139 - 140 - /* 141 - * Some devices may provide ROMs via a source other than the BAR 142 - */ 143 - if (!start && pdev->rom && pdev->romlen) { 144 - *size = pdev->romlen; 145 - return phys_to_virt(pdev->rom); 146 - } 147 - 148 - if (!start) 149 - return NULL; 150 171 151 172 rom = ioremap(start, *size); 152 173 if (!rom) { ··· 181 202 if (res->flags & (IORESOURCE_ROM_COPY | IORESOURCE_ROM_BIOS_COPY)) 182 203 return; 183 204 184 - if (!pdev->rom || !pdev->romlen) 185 - iounmap(rom); 205 + iounmap(rom); 186 206 187 207 /* Disable again before continuing, leave enabled if pci=rom */ 188 208 if (!(res->flags & (IORESOURCE_ROM_ENABLE | IORESOURCE_ROM_SHADOW))) ··· 205 227 } 206 228 } 207 229 230 + /** 231 + * pci_platform_rom - provides a pointer to any ROM image provided by the 232 + * platform 233 + * @pdev: pointer to pci device struct 234 + * @size: pointer to receive size of pci window over ROM 235 + */ 236 + void __iomem *pci_platform_rom(struct pci_dev *pdev, size_t *size) 237 + { 238 + if (pdev->rom && pdev->romlen) { 239 + *size = pdev->romlen; 240 + return phys_to_virt((phys_addr_t)pdev->rom); 241 + } 242 + 243 + return NULL; 244 + } 245 + 208 246 EXPORT_SYMBOL(pci_map_rom); 209 247 EXPORT_SYMBOL(pci_unmap_rom); 210 248 EXPORT_SYMBOL_GPL(pci_enable_rom); 211 249 EXPORT_SYMBOL_GPL(pci_disable_rom); 250 + EXPORT_SYMBOL(pci_platform_rom);
+1
include/linux/pci.h
··· 916 916 void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size); 917 917 void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom); 918 918 size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size); 919 + void __iomem __must_check *pci_platform_rom(struct pci_dev *pdev, size_t *size); 919 920 920 921 /* Power management related routines */ 921 922 int pci_save_state(struct pci_dev *dev);