diff options
author | John Keller <jpk@sgi.com> | 2007-07-09 14:42:24 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2007-07-09 16:37:18 -0400 |
commit | d7ad2254fa7cc11aec3faeba076c1243f6adeb47 (patch) | |
tree | 900c05b11a3a44f19618701172ffb5f51ecdeb99 | |
parent | 83ce6ef8408bbc7d9322ab50ba592f83012dea94 (diff) |
[IA64] SN: Correct ROM resource length for BIOS copy
On SN systems, when setting the IORESOURCE_ROM_BIOS_COPY resource flag,
the resource length should be set to the actual size of the ROM image
so that a call to pci_map_rom() returns the correct size.
Signed-off-by: John Keller <jpk@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Tony Luck <tony.luck@intel.com>
-rw-r--r-- | arch/ia64/sn/kernel/io_acpi_init.c | 17 | ||||
-rw-r--r-- | arch/ia64/sn/kernel/io_init.c | 20 | ||||
-rw-r--r-- | drivers/pci/rom.c | 73 | ||||
-rw-r--r-- | include/linux/pci.h | 1 |
4 files changed, 70 insertions, 41 deletions
diff --git a/arch/ia64/sn/kernel/io_acpi_init.c b/arch/ia64/sn/kernel/io_acpi_init.c index c6216f454ffb..3c7178f5dce8 100644 --- a/arch/ia64/sn/kernel/io_acpi_init.c +++ b/arch/ia64/sn/kernel/io_acpi_init.c | |||
@@ -418,7 +418,7 @@ sn_acpi_slot_fixup(struct pci_dev *dev) | |||
418 | void __iomem *addr; | 418 | void __iomem *addr; |
419 | struct pcidev_info *pcidev_info = NULL; | 419 | struct pcidev_info *pcidev_info = NULL; |
420 | struct sn_irq_info *sn_irq_info = NULL; | 420 | struct sn_irq_info *sn_irq_info = NULL; |
421 | size_t size; | 421 | size_t image_size, size; |
422 | 422 | ||
423 | if (sn_acpi_get_pcidev_info(dev, &pcidev_info, &sn_irq_info)) { | 423 | if (sn_acpi_get_pcidev_info(dev, &pcidev_info, &sn_irq_info)) { |
424 | panic("%s: Failure obtaining pcidev_info for %s\n", | 424 | panic("%s: Failure obtaining pcidev_info for %s\n", |
@@ -428,17 +428,16 @@ sn_acpi_slot_fixup(struct pci_dev *dev) | |||
428 | if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) { | 428 | if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) { |
429 | /* | 429 | /* |
430 | * A valid ROM image exists and has been shadowed by the | 430 | * A valid ROM image exists and has been shadowed by the |
431 | * PROM. Setup the pci_dev ROM resource to point to | 431 | * PROM. Setup the pci_dev ROM resource with the address |
432 | * the shadowed copy. | 432 | * of the shadowed copy, and the actual length of the ROM image. |
433 | */ | 433 | */ |
434 | size = dev->resource[PCI_ROM_RESOURCE].end - | 434 | size = pci_resource_len(dev, PCI_ROM_RESOURCE); |
435 | dev->resource[PCI_ROM_RESOURCE].start; | 435 | addr = ioremap(pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE], |
436 | addr = | 436 | size); |
437 | ioremap(pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE], | 437 | image_size = pci_get_rom_size(addr, size); |
438 | size); | ||
439 | dev->resource[PCI_ROM_RESOURCE].start = (unsigned long) addr; | 438 | dev->resource[PCI_ROM_RESOURCE].start = (unsigned long) addr; |
440 | dev->resource[PCI_ROM_RESOURCE].end = | 439 | dev->resource[PCI_ROM_RESOURCE].end = |
441 | (unsigned long) addr + size; | 440 | (unsigned long) addr + image_size - 1; |
442 | dev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_BIOS_COPY; | 441 | dev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_BIOS_COPY; |
443 | } | 442 | } |
444 | sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info); | 443 | sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info); |
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c index 6b10e5d28488..906b93674b76 100644 --- a/arch/ia64/sn/kernel/io_init.c +++ b/arch/ia64/sn/kernel/io_init.c | |||
@@ -259,9 +259,23 @@ sn_io_slot_fixup(struct pci_dev *dev) | |||
259 | insert_resource(&ioport_resource, &dev->resource[idx]); | 259 | insert_resource(&ioport_resource, &dev->resource[idx]); |
260 | else | 260 | else |
261 | insert_resource(&iomem_resource, &dev->resource[idx]); | 261 | insert_resource(&iomem_resource, &dev->resource[idx]); |
262 | /* If ROM, mark as shadowed in PROM */ | 262 | /* |
263 | if (idx == PCI_ROM_RESOURCE) | 263 | * If ROM, set the actual ROM image size, and mark as |
264 | dev->resource[idx].flags |= IORESOURCE_ROM_BIOS_COPY; | 264 | * shadowed in PROM. |
265 | */ | ||
266 | if (idx == PCI_ROM_RESOURCE) { | ||
267 | size_t image_size; | ||
268 | void __iomem *rom; | ||
269 | |||
270 | rom = ioremap(pci_resource_start(dev, PCI_ROM_RESOURCE), | ||
271 | size + 1); | ||
272 | image_size = pci_get_rom_size(rom, size + 1); | ||
273 | dev->resource[PCI_ROM_RESOURCE].end = | ||
274 | dev->resource[PCI_ROM_RESOURCE].start + | ||
275 | image_size - 1; | ||
276 | dev->resource[PCI_ROM_RESOURCE].flags |= | ||
277 | IORESOURCE_ROM_BIOS_COPY; | ||
278 | } | ||
265 | } | 279 | } |
266 | /* Create a pci_window in the pci_controller struct for | 280 | /* Create a pci_window in the pci_controller struct for |
267 | * each device resource. | 281 | * each device resource. |
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index d087e0817715..dbbcc04abd1a 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c | |||
@@ -54,6 +54,49 @@ static void pci_disable_rom(struct pci_dev *pdev) | |||
54 | } | 54 | } |
55 | 55 | ||
56 | /** | 56 | /** |
57 | * pci_get_rom_size - obtain the actual size of the ROM image | ||
58 | * @rom: kernel virtual pointer to image of ROM | ||
59 | * @size: size of PCI window | ||
60 | * return: size of actual ROM image | ||
61 | * | ||
62 | * Determine the actual length of the ROM image. | ||
63 | * The PCI window size could be much larger than the | ||
64 | * actual image size. | ||
65 | */ | ||
66 | size_t pci_get_rom_size(void __iomem *rom, size_t size) | ||
67 | { | ||
68 | void __iomem *image; | ||
69 | int last_image; | ||
70 | |||
71 | image = rom; | ||
72 | do { | ||
73 | void __iomem *pds; | ||
74 | /* Standard PCI ROMs start out with these bytes 55 AA */ | ||
75 | if (readb(image) != 0x55) | ||
76 | break; | ||
77 | if (readb(image + 1) != 0xAA) | ||
78 | break; | ||
79 | /* get the PCI data structure and check its signature */ | ||
80 | pds = image + readw(image + 24); | ||
81 | if (readb(pds) != 'P') | ||
82 | break; | ||
83 | if (readb(pds + 1) != 'C') | ||
84 | break; | ||
85 | if (readb(pds + 2) != 'I') | ||
86 | break; | ||
87 | if (readb(pds + 3) != 'R') | ||
88 | break; | ||
89 | last_image = readb(pds + 21) & 0x80; | ||
90 | /* this length is reliable */ | ||
91 | image += readw(pds + 16) * 512; | ||
92 | } while (!last_image); | ||
93 | |||
94 | /* never return a size larger than the PCI resource window */ | ||
95 | /* there are known ROMs that get the size wrong */ | ||
96 | return min((size_t)(image - rom), size); | ||
97 | } | ||
98 | |||
99 | /** | ||
57 | * pci_map_rom - map a PCI ROM to kernel space | 100 | * pci_map_rom - map a PCI ROM to kernel space |
58 | * @pdev: pointer to pci device struct | 101 | * @pdev: pointer to pci device struct |
59 | * @size: pointer to receive size of pci window over ROM | 102 | * @size: pointer to receive size of pci window over ROM |
@@ -68,8 +111,6 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) | |||
68 | struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; | 111 | struct resource *res = &pdev->resource[PCI_ROM_RESOURCE]; |
69 | loff_t start; | 112 | loff_t start; |
70 | void __iomem *rom; | 113 | void __iomem *rom; |
71 | void __iomem *image; | ||
72 | int last_image; | ||
73 | 114 | ||
74 | /* | 115 | /* |
75 | * IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy | 116 | * IORESOURCE_ROM_SHADOW set on x86, x86_64 and IA64 supports legacy |
@@ -117,33 +158,7 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size) | |||
117 | * size is much larger than the actual size of the ROM. | 158 | * size is much larger than the actual size of the ROM. |
118 | * True size is important if the ROM is going to be copied. | 159 | * True size is important if the ROM is going to be copied. |
119 | */ | 160 | */ |
120 | image = rom; | 161 | *size = pci_get_rom_size(rom, *size); |
121 | do { | ||
122 | void __iomem *pds; | ||
123 | /* Standard PCI ROMs start out with these bytes 55 AA */ | ||
124 | if (readb(image) != 0x55) | ||
125 | break; | ||
126 | if (readb(image + 1) != 0xAA) | ||
127 | break; | ||
128 | /* get the PCI data structure and check its signature */ | ||
129 | pds = image + readw(image + 24); | ||
130 | if (readb(pds) != 'P') | ||
131 | break; | ||
132 | if (readb(pds + 1) != 'C') | ||
133 | break; | ||
134 | if (readb(pds + 2) != 'I') | ||
135 | break; | ||
136 | if (readb(pds + 3) != 'R') | ||
137 | break; | ||
138 | last_image = readb(pds + 21) & 0x80; | ||
139 | /* this length is reliable */ | ||
140 | image += readw(pds + 16) * 512; | ||
141 | } while (!last_image); | ||
142 | |||
143 | /* never return a size larger than the PCI resource window */ | ||
144 | /* there are known ROMs that get the size wrong */ | ||
145 | *size = min((size_t)(image - rom), *size); | ||
146 | |||
147 | return rom; | 162 | return rom; |
148 | } | 163 | } |
149 | 164 | ||
diff --git a/include/linux/pci.h b/include/linux/pci.h index 086a0e5a6318..acb9387c0364 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -560,6 +560,7 @@ void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size); | |||
560 | void __iomem __must_check *pci_map_rom_copy(struct pci_dev *pdev, size_t *size); | 560 | void __iomem __must_check *pci_map_rom_copy(struct pci_dev *pdev, size_t *size); |
561 | void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom); | 561 | void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom); |
562 | void pci_remove_rom(struct pci_dev *pdev); | 562 | void pci_remove_rom(struct pci_dev *pdev); |
563 | size_t pci_get_rom_size(void __iomem *rom, size_t size); | ||
563 | 564 | ||
564 | /* Power management related routines */ | 565 | /* Power management related routines */ |
565 | int pci_save_state(struct pci_dev *dev); | 566 | int pci_save_state(struct pci_dev *dev); |