aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-05-14 16:16:47 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2009-05-15 02:43:42 -0400
commitad892a63f64888a7b05eb2046febbcfbdd54dfcc (patch)
tree473fccb436ed94b3eb8fcab2378f6dbe523bdc4c /arch/powerpc/kernel
parentb173f03d7c48d3346541f26e0b29690dbadca279 (diff)
powerpc: Fix PCI ROM access
A couple of issues crept in since about 2.6.27 related to accessing PCI device ROMs on various powerpc machines. First, historically, we don't allocate the ROM resource in the resource tree. I'm not entirely certain of why, I susepct they often contained garbage on x86 but it's hard to tell. This causes the current generic code to always call pci_assign_resource() when trying to access the said ROM from sysfs, which will try to re-assign some new address regardless of what the ROM BAR was already set to at boot time. This can be a problem on hypervisor platforms like pSeries where we aren't supposed to move PCI devices around (and in fact probably can't). Second, our code that generates the PCI tree from the OF device-tree (instead of doing config space probing) which we mostly use on pseries at the moment, didn't set the (new) flag IORESOURCE_SIZEALIGN on any resource. That means that any attempt at re-assigning such a resource with pci_assign_resource() would fail due to resource_alignment() returning 0. This fixes this by doing these two things: - The code that calculates resource flags based on the OF device-node is improved to set IORESOURCE_SIZEALIGN on any valid BAR, and while at it also set IORESOURCE_READONLY for ROMs since we were lacking that too - We now allocate ROM resources as part of the resource tree. However to limit the chances of nasty conflicts due to busted firmwares, we only do it on the second pass of our two-passes allocation scheme, so that all valid and enabled BARs get precedence. This brings pSeries back the ability to access PCI ROMs via sysfs (and thus initialize various video cards from X etc...). Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/pci-common.c21
-rw-r--r--arch/powerpc/kernel/pci_64.c15
2 files changed, 26 insertions, 10 deletions
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index 9c69e7e145c5..4fee63cb53ff 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1366,12 +1366,17 @@ static void __init pcibios_allocate_resources(int pass)
1366 1366
1367 for_each_pci_dev(dev) { 1367 for_each_pci_dev(dev) {
1368 pci_read_config_word(dev, PCI_COMMAND, &command); 1368 pci_read_config_word(dev, PCI_COMMAND, &command);
1369 for (idx = 0; idx < 6; idx++) { 1369 for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
1370 r = &dev->resource[idx]; 1370 r = &dev->resource[idx];
1371 if (r->parent) /* Already allocated */ 1371 if (r->parent) /* Already allocated */
1372 continue; 1372 continue;
1373 if (!r->flags || (r->flags & IORESOURCE_UNSET)) 1373 if (!r->flags || (r->flags & IORESOURCE_UNSET))
1374 continue; /* Not assigned at all */ 1374 continue; /* Not assigned at all */
1375 /* We only allocate ROMs on pass 1 just in case they
1376 * have been screwed up by firmware
1377 */
1378 if (idx == PCI_ROM_RESOURCE )
1379 disabled = 1;
1375 if (r->flags & IORESOURCE_IO) 1380 if (r->flags & IORESOURCE_IO)
1376 disabled = !(command & PCI_COMMAND_IO); 1381 disabled = !(command & PCI_COMMAND_IO);
1377 else 1382 else
@@ -1382,17 +1387,19 @@ static void __init pcibios_allocate_resources(int pass)
1382 if (pass) 1387 if (pass)
1383 continue; 1388 continue;
1384 r = &dev->resource[PCI_ROM_RESOURCE]; 1389 r = &dev->resource[PCI_ROM_RESOURCE];
1385 if (r->flags & IORESOURCE_ROM_ENABLE) { 1390 if (r->flags) {
1386 /* Turn the ROM off, leave the resource region, 1391 /* Turn the ROM off, leave the resource region,
1387 * but keep it unregistered. 1392 * but keep it unregistered.
1388 */ 1393 */
1389 u32 reg; 1394 u32 reg;
1390 pr_debug("PCI: Switching off ROM of %s\n",
1391 pci_name(dev));
1392 r->flags &= ~IORESOURCE_ROM_ENABLE;
1393 pci_read_config_dword(dev, dev->rom_base_reg, &reg); 1395 pci_read_config_dword(dev, dev->rom_base_reg, &reg);
1394 pci_write_config_dword(dev, dev->rom_base_reg, 1396 if (reg & PCI_ROM_ADDRESS_ENABLE) {
1395 reg & ~PCI_ROM_ADDRESS_ENABLE); 1397 pr_debug("PCI: Switching off ROM of %s\n",
1398 pci_name(dev));
1399 r->flags &= ~IORESOURCE_ROM_ENABLE;
1400 pci_write_config_dword(dev, dev->rom_base_reg,
1401 reg & ~PCI_ROM_ADDRESS_ENABLE);
1402 }
1396 } 1403 }
1397 } 1404 }
1398} 1405}
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index be574fc0d92f..96edb6f8babb 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -64,7 +64,7 @@ static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
64 return def; 64 return def;
65} 65}
66 66
67static unsigned int pci_parse_of_flags(u32 addr0) 67static unsigned int pci_parse_of_flags(u32 addr0, int bridge)
68{ 68{
69 unsigned int flags = 0; 69 unsigned int flags = 0;
70 70
@@ -75,8 +75,17 @@ static unsigned int pci_parse_of_flags(u32 addr0)
75 if (addr0 & 0x40000000) 75 if (addr0 & 0x40000000)
76 flags |= IORESOURCE_PREFETCH 76 flags |= IORESOURCE_PREFETCH
77 | PCI_BASE_ADDRESS_MEM_PREFETCH; 77 | PCI_BASE_ADDRESS_MEM_PREFETCH;
78 /* Note: We don't know whether the ROM has been left enabled
79 * by the firmware or not. We mark it as disabled (ie, we do
80 * not set the IORESOURCE_ROM_ENABLE flag) for now rather than
81 * do a config space read, it will be force-enabled if needed
82 */
83 if (!bridge && (addr0 & 0xff) == 0x30)
84 flags |= IORESOURCE_READONLY;
78 } else if (addr0 & 0x01000000) 85 } else if (addr0 & 0x01000000)
79 flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO; 86 flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO;
87 if (flags)
88 flags |= IORESOURCE_SIZEALIGN;
80 return flags; 89 return flags;
81} 90}
82 91
@@ -95,7 +104,7 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
95 return; 104 return;
96 pr_debug(" parse addresses (%d bytes) @ %p\n", proplen, addrs); 105 pr_debug(" parse addresses (%d bytes) @ %p\n", proplen, addrs);
97 for (; proplen >= 20; proplen -= 20, addrs += 5) { 106 for (; proplen >= 20; proplen -= 20, addrs += 5) {
98 flags = pci_parse_of_flags(addrs[0]); 107 flags = pci_parse_of_flags(addrs[0], 0);
99 if (!flags) 108 if (!flags)
100 continue; 109 continue;
101 base = of_read_number(&addrs[1], 2); 110 base = of_read_number(&addrs[1], 2);
@@ -293,7 +302,7 @@ void __devinit of_scan_pci_bridge(struct device_node *node,
293 } 302 }
294 i = 1; 303 i = 1;
295 for (; len >= 32; len -= 32, ranges += 8) { 304 for (; len >= 32; len -= 32, ranges += 8) {
296 flags = pci_parse_of_flags(ranges[0]); 305 flags = pci_parse_of_flags(ranges[0], 1);
297 size = of_read_number(&ranges[6], 2); 306 size = of_read_number(&ranges[6], 2);
298 if (flags == 0 || size == 0) 307 if (flags == 0 || size == 0)
299 continue; 308 continue;