Commit 547b5246 authored by Matthew Garrett's avatar Matthew Garrett Committed by Linus Torvalds

PCI: Use ROM images from firmware only if no other ROM source available

Mantas Mikulėnas reported that his graphics hardware failed to
initialise after commit f9a37be0 ("x86: Use PCI setup data").

The aim of this commit was to ensure that ROM images were available on
some Apple systems that don't expose the GPU ROM via any other source.
In this case, UEFI appears to have provided a broken ROM image that we
were using even though there was a perfectly valid ROM available via
other sources.  The simplest way to handle this seems to be to just
re-order pci_map_rom() and leave any firmare-supplied ROM to last.
Signed-off-by: default avatarMatthew Garrett <matthew.garrett@nebula.com>
Tested-by: default avatarMantas Mikulėnas <grawity@gmail.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 5c7c3361
...@@ -100,6 +100,27 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) ...@@ -100,6 +100,27 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size)
return min((size_t)(image - rom), size); return min((size_t)(image - rom), size);
} }
static loff_t pci_find_rom(struct pci_dev *pdev, size_t *size)
{
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
loff_t start;
/* assign the ROM an address if it doesn't have one */
if (res->parent == NULL && pci_assign_resource(pdev, PCI_ROM_RESOURCE))
return 0;
start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
*size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
if (*size == 0)
return 0;
/* Enable ROM space decodes */
if (pci_enable_rom(pdev))
return 0;
return start;
}
/** /**
* pci_map_rom - map a PCI ROM to kernel space * pci_map_rom - map a PCI ROM to kernel space
* @pdev: pointer to pci device struct * @pdev: pointer to pci device struct
...@@ -114,21 +135,15 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) ...@@ -114,21 +135,15 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size)
void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
{ {
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
loff_t start; loff_t start = 0;
void __iomem *rom; void __iomem *rom;
/*
* Some devices may provide ROMs via a source other than the BAR
*/
if (pdev->rom && pdev->romlen) {
*size = pdev->romlen;
return phys_to_virt(pdev->rom);
/* /*
* IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy * IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy
* memory map if the VGA enable bit of the Bridge Control register is * memory map if the VGA enable bit of the Bridge Control register is
* set for embedded VGA. * set for embedded VGA.
*/ */
} else if (res->flags & IORESOURCE_ROM_SHADOW) { if (res->flags & IORESOURCE_ROM_SHADOW) {
/* primary video rom always starts here */ /* primary video rom always starts here */
start = (loff_t)0xC0000; start = (loff_t)0xC0000;
*size = 0x20000; /* cover C000:0 through E000:0 */ *size = 0x20000; /* cover C000:0 through E000:0 */
...@@ -139,21 +154,21 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) ...@@ -139,21 +154,21 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
return (void __iomem *)(unsigned long) return (void __iomem *)(unsigned long)
pci_resource_start(pdev, PCI_ROM_RESOURCE); pci_resource_start(pdev, PCI_ROM_RESOURCE);
} else { } else {
/* assign the ROM an address if it doesn't have one */ start = pci_find_rom(pdev, size);
if (res->parent == NULL &&
pci_assign_resource(pdev,PCI_ROM_RESOURCE))
return NULL;
start = pci_resource_start(pdev, PCI_ROM_RESOURCE);
*size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
if (*size == 0)
return NULL;
/* Enable ROM space decodes */
if (pci_enable_rom(pdev))
return NULL;
} }
} }
/*
* Some devices may provide ROMs via a source other than the BAR
*/
if (!start && pdev->rom && pdev->romlen) {
*size = pdev->romlen;
return phys_to_virt(pdev->rom);
}
if (!start)
return NULL;
rom = ioremap(start, *size); rom = ioremap(start, *size);
if (!rom) { if (!rom) {
/* restore enable if ioremap fails */ /* restore enable if ioremap fails */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment