diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2007-12-19 22:54:55 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-12-20 00:18:10 -0500 |
commit | 50c9bc2fc86fddd39eea6a12ceb81585bc2aafaa (patch) | |
tree | a6021e68bdc0477ada4bc81d04443e3316cdbb4f | |
parent | 3fd94c6b1a1158d3e0e505b0a00c3a707b5fcd40 (diff) |
[POWERPC] fix iSeries PCI resource management
The way iSeries manages PCI IO and Memory resources is a bit strange
and is based on overriding the content of those resources with home
cooked ones afterward.
This changes it a bit to better integrate with the new resource handling
so that the "virtual" tokens that iSeries replaces resources with are
done from the proper per-device fixup hook, and bridge resources are
set to enclose that token space. This fixes various things such as
the output of /proc/iomem & ioports, among others. This also fixes up
various boot messages as well.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/kernel/pci-common.c | 16 | ||||
-rw-r--r-- | arch/powerpc/kernel/pci_64.c | 19 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/pci.c | 125 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/pci.h | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/setup.c | 37 |
5 files changed, 122 insertions, 79 deletions
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index d804c8d0be00..f706b7e83d7e 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c | |||
@@ -190,6 +190,20 @@ int pci_read_irq_line(struct pci_dev *pci_dev) | |||
190 | struct of_irq oirq; | 190 | struct of_irq oirq; |
191 | unsigned int virq; | 191 | unsigned int virq; |
192 | 192 | ||
193 | /* The current device-tree that iSeries generates from the HV | ||
194 | * PCI informations doesn't contain proper interrupt routing, | ||
195 | * and all the fallback would do is print out crap, so we | ||
196 | * don't attempt to resolve the interrupts here at all, some | ||
197 | * iSeries specific fixup does it. | ||
198 | * | ||
199 | * In the long run, we will hopefully fix the generated device-tree | ||
200 | * instead. | ||
201 | */ | ||
202 | #ifdef CONFIG_PPC_ISERIES | ||
203 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
204 | return -1; | ||
205 | #endif | ||
206 | |||
193 | DBG("Try to map irq for %s...\n", pci_name(pci_dev)); | 207 | DBG("Try to map irq for %s...\n", pci_name(pci_dev)); |
194 | 208 | ||
195 | #ifdef DEBUG | 209 | #ifdef DEBUG |
@@ -946,7 +960,7 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) | |||
946 | || res->start > res->end) | 960 | || res->start > res->end) |
947 | continue; | 961 | continue; |
948 | if (bus->parent == NULL) | 962 | if (bus->parent == NULL) |
949 | pr = (res->flags & IORESOURCE_IO)? | 963 | pr = (res->flags & IORESOURCE_IO) ? |
950 | &ioport_resource : &iomem_resource; | 964 | &ioport_resource : &iomem_resource; |
951 | else { | 965 | else { |
952 | /* Don't bother with non-root busses when | 966 | /* Don't bother with non-root busses when |
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 794359d8686b..2ec040b314d4 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c | |||
@@ -359,7 +359,7 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
359 | int i, mode; | 359 | int i, mode; |
360 | struct resource *res; | 360 | struct resource *res; |
361 | 361 | ||
362 | DBG("Scanning PHB %s\n", node ? node->full_name : "<NO NAME>"); | 362 | DBG("PCI: Scanning PHB %s\n", node ? node->full_name : "<NO NAME>"); |
363 | 363 | ||
364 | /* Create an empty bus for the toplevel */ | 364 | /* Create an empty bus for the toplevel */ |
365 | bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node); | 365 | bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, node); |
@@ -375,9 +375,22 @@ void __devinit scan_phb(struct pci_controller *hose) | |||
375 | pcibios_map_io_space(bus); | 375 | pcibios_map_io_space(bus); |
376 | 376 | ||
377 | /* Wire up PHB bus resources */ | 377 | /* Wire up PHB bus resources */ |
378 | bus->resource[0] = res = &hose->io_resource; | 378 | if (hose->io_resource.flags) { |
379 | for (i = 0; i < 3; ++i) | 379 | DBG("PCI: PHB IO resource = %016lx-%016lx [%lx]\n", |
380 | hose->io_resource.start, hose->io_resource.end, | ||
381 | hose->io_resource.flags); | ||
382 | bus->resource[0] = res = &hose->io_resource; | ||
383 | } | ||
384 | for (i = 0; i < 3; ++i) { | ||
385 | DBG("PCI: PHB MEM resource %d = %016lx-%016lx [%lx]\n", i, | ||
386 | hose->mem_resources[i].start, | ||
387 | hose->mem_resources[i].end, | ||
388 | hose->mem_resources[i].flags); | ||
380 | bus->resource[i+1] = &hose->mem_resources[i]; | 389 | bus->resource[i+1] = &hose->mem_resources[i]; |
390 | } | ||
391 | DBG("PCI: PHB MEM offset = %016lx\n", hose->pci_mem_offset); | ||
392 | DBG("PCI: PHB IO offset = %08lx\n", | ||
393 | (unsigned long)hose->io_base_virt - _IO_BASE); | ||
381 | 394 | ||
382 | /* Get probe mode and perform scan */ | 395 | /* Get probe mode and perform scan */ |
383 | mode = PCI_PROBE_NORMAL; | 396 | mode = PCI_PROBE_NORMAL; |
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index 68f248b4c696..30e3d992dc0d 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c | |||
@@ -20,6 +20,9 @@ | |||
20 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
22 | */ | 22 | */ |
23 | |||
24 | #undef DEBUG | ||
25 | |||
23 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
24 | #include <linux/list.h> | 27 | #include <linux/list.h> |
25 | #include <linux/string.h> | 28 | #include <linux/string.h> |
@@ -58,6 +61,7 @@ static int limit_pci_retries = 1; /* Set Retry Error on. */ | |||
58 | #define IOMM_TABLE_MAX_ENTRIES 1024 | 61 | #define IOMM_TABLE_MAX_ENTRIES 1024 |
59 | #define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL | 62 | #define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL |
60 | #define BASE_IO_MEMORY 0xE000000000000000UL | 63 | #define BASE_IO_MEMORY 0xE000000000000000UL |
64 | #define END_IO_MEMORY 0xEFFFFFFFFFFFFFFFUL | ||
61 | 65 | ||
62 | static unsigned long max_io_memory = BASE_IO_MEMORY; | 66 | static unsigned long max_io_memory = BASE_IO_MEMORY; |
63 | static long current_iomm_table_entry; | 67 | static long current_iomm_table_entry; |
@@ -68,7 +72,6 @@ static long current_iomm_table_entry; | |||
68 | static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES]; | 72 | static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES]; |
69 | static u8 iobar_table[IOMM_TABLE_MAX_ENTRIES]; | 73 | static u8 iobar_table[IOMM_TABLE_MAX_ENTRIES]; |
70 | 74 | ||
71 | static const char pci_io_text[] = "iSeries PCI I/O"; | ||
72 | static DEFINE_SPINLOCK(iomm_table_lock); | 75 | static DEFINE_SPINLOCK(iomm_table_lock); |
73 | 76 | ||
74 | /* | 77 | /* |
@@ -279,8 +282,8 @@ out_free: | |||
279 | * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet | 282 | * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet |
280 | * controller | 283 | * controller |
281 | */ | 284 | */ |
282 | static void __init iseries_device_information(struct pci_dev *pdev, int count, | 285 | static void __init iseries_device_information(struct pci_dev *pdev, |
283 | u16 bus, HvSubBusNumber subbus) | 286 | u16 bus, HvSubBusNumber subbus) |
284 | { | 287 | { |
285 | u8 frame = 0; | 288 | u8 frame = 0; |
286 | char card[4]; | 289 | char card[4]; |
@@ -290,10 +293,9 @@ static void __init iseries_device_information(struct pci_dev *pdev, int count, | |||
290 | ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)); | 293 | ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)); |
291 | 294 | ||
292 | if (iseries_get_location_code(bus, agent, &frame, card)) { | 295 | if (iseries_get_location_code(bus, agent, &frame, card)) { |
293 | printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, " | 296 | printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, " |
294 | "Card %4s 0x%04X\n", count, bus, | 297 | "Card %4s 0x%04X\n", pci_name(pdev), pdev->vendor, |
295 | PCI_SLOT(pdev->devfn), pdev->vendor, frame, | 298 | frame, card, (int)(pdev->class >> 8)); |
296 | card, (int)(pdev->class >> 8)); | ||
297 | } | 299 | } |
298 | } | 300 | } |
299 | 301 | ||
@@ -323,7 +325,6 @@ static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) | |||
323 | * Set Resource values. | 325 | * Set Resource values. |
324 | */ | 326 | */ |
325 | spin_lock(&iomm_table_lock); | 327 | spin_lock(&iomm_table_lock); |
326 | bar_res->name = pci_io_text; | ||
327 | bar_res->start = BASE_IO_MEMORY + | 328 | bar_res->start = BASE_IO_MEMORY + |
328 | IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; | 329 | IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; |
329 | bar_res->end = bar_res->start + bar_size - 1; | 330 | bar_res->end = bar_res->start + bar_size - 1; |
@@ -393,61 +394,63 @@ static struct device_node *find_device_node(int bus, int devfn) | |||
393 | } | 394 | } |
394 | 395 | ||
395 | /* | 396 | /* |
396 | * iSeries_pci_final_fixup(void) | 397 | * iSeries_pcibios_fixup_resources |
398 | * | ||
399 | * Fixes up all resources for devices | ||
397 | */ | 400 | */ |
398 | void __init iSeries_pci_final_fixup(void) | 401 | void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev) |
399 | { | 402 | { |
400 | struct pci_dev *pdev = NULL; | 403 | const u32 *agent; |
404 | const u32 *sub_bus; | ||
405 | unsigned char bus = pdev->bus->number; | ||
401 | struct device_node *node; | 406 | struct device_node *node; |
402 | int num_dev = 0; | 407 | int i; |
403 | 408 | ||
404 | /* Fix up at the device node and pci_dev relationship */ | 409 | node = find_device_node(bus, pdev->devfn); |
405 | mf_display_src(0xC9000100); | 410 | pr_debug("PCI: iSeries %s, pdev %p, node %p\n", |
406 | 411 | pci_name(pdev), pdev, node); | |
407 | printk("pcibios_final_fixup\n"); | 412 | if (!node) { |
408 | for_each_pci_dev(pdev) { | 413 | printk("PCI: %s disabled, device tree entry not found !\n", |
409 | const u32 *agent; | 414 | pci_name(pdev)); |
410 | const u32 *sub_bus; | 415 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) |
411 | unsigned char bus = pdev->bus->number; | 416 | pdev->resource[i].flags = 0; |
412 | 417 | return; | |
413 | node = find_device_node(bus, pdev->devfn); | 418 | } |
414 | printk("pci dev %p (%x.%x), node %p\n", pdev, bus, | 419 | sub_bus = of_get_property(node, "linux,subbus", NULL); |
415 | pdev->devfn, node); | 420 | agent = of_get_property(node, "linux,agent-id", NULL); |
416 | if (!node) { | 421 | if (agent && sub_bus) { |
417 | printk("PCI: Device Tree not found for 0x%016lX\n", | 422 | u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus); |
418 | (unsigned long)pdev); | 423 | int err; |
419 | continue; | 424 | |
420 | } | 425 | err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq); |
421 | 426 | if (err) | |
422 | agent = of_get_property(node, "linux,agent-id", NULL); | 427 | pci_log_error("Connect Bus Unit", |
423 | sub_bus = of_get_property(node, "linux,subbus", NULL); | 428 | bus, *sub_bus, *agent, err); |
424 | if (agent && sub_bus) { | 429 | else { |
425 | u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus); | 430 | err = HvCallPci_configStore8(bus, *sub_bus, |
426 | int err; | ||
427 | |||
428 | err = HvCallXm_connectBusUnit(bus, *sub_bus, | ||
429 | *agent, irq); | ||
430 | if (err) | ||
431 | pci_log_error("Connect Bus Unit", | ||
432 | bus, *sub_bus, *agent, err); | ||
433 | else { | ||
434 | err = HvCallPci_configStore8(bus, *sub_bus, | ||
435 | *agent, PCI_INTERRUPT_LINE, irq); | 431 | *agent, PCI_INTERRUPT_LINE, irq); |
436 | if (err) | 432 | if (err) |
437 | pci_log_error("PciCfgStore Irq Failed!", | 433 | pci_log_error("PciCfgStore Irq Failed!", |
438 | bus, *sub_bus, *agent, err); | 434 | bus, *sub_bus, *agent, err); |
439 | else | 435 | else |
440 | pdev->irq = irq; | 436 | pdev->irq = irq; |
441 | } | ||
442 | } | 437 | } |
443 | |||
444 | num_dev++; | ||
445 | pdev->sysdata = node; | ||
446 | PCI_DN(node)->pcidev = pdev; | ||
447 | allocate_device_bars(pdev); | ||
448 | iseries_device_information(pdev, num_dev, bus, *sub_bus); | ||
449 | iommu_devnode_init_iSeries(pdev, node); | ||
450 | } | 438 | } |
439 | |||
440 | pdev->sysdata = node; | ||
441 | PCI_DN(node)->pcidev = pdev; | ||
442 | allocate_device_bars(pdev); | ||
443 | iseries_device_information(pdev, bus, *sub_bus); | ||
444 | iommu_devnode_init_iSeries(pdev, node); | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * iSeries_pci_final_fixup(void) | ||
449 | */ | ||
450 | void __init iSeries_pci_final_fixup(void) | ||
451 | { | ||
452 | /* Fix up at the device node and pci_dev relationship */ | ||
453 | mf_display_src(0xC9000100); | ||
451 | iSeries_activate_IRQs(); | 454 | iSeries_activate_IRQs(); |
452 | mf_display_src(0xC9000200); | 455 | mf_display_src(0xC9000200); |
453 | } | 456 | } |
@@ -894,10 +897,18 @@ void __init iSeries_pcibios_init(void) | |||
894 | /* All legacy iSeries PHBs are in domain zero */ | 897 | /* All legacy iSeries PHBs are in domain zero */ |
895 | phb->global_number = 0; | 898 | phb->global_number = 0; |
896 | 899 | ||
897 | phb->pci_mem_offset = bus; | ||
898 | phb->first_busno = bus; | 900 | phb->first_busno = bus; |
899 | phb->last_busno = bus; | 901 | phb->last_busno = bus; |
900 | phb->ops = &iSeries_pci_ops; | 902 | phb->ops = &iSeries_pci_ops; |
903 | phb->io_base_virt = (void __iomem *)_IO_BASE; | ||
904 | phb->io_resource.flags = IORESOURCE_IO; | ||
905 | phb->io_resource.start = BASE_IO_MEMORY; | ||
906 | phb->io_resource.end = END_IO_MEMORY; | ||
907 | phb->io_resource.name = "iSeries PCI IO"; | ||
908 | phb->mem_resources[0].flags = IORESOURCE_MEM; | ||
909 | phb->mem_resources[0].start = BASE_IO_MEMORY; | ||
910 | phb->mem_resources[0].end = END_IO_MEMORY; | ||
911 | phb->mem_resources[0].name = "Series PCI MEM"; | ||
901 | } | 912 | } |
902 | 913 | ||
903 | of_node_put(root); | 914 | of_node_put(root); |
diff --git a/arch/powerpc/platforms/iseries/pci.h b/arch/powerpc/platforms/iseries/pci.h index 180aa74afb2d..d9cf974c2718 100644 --- a/arch/powerpc/platforms/iseries/pci.h +++ b/arch/powerpc/platforms/iseries/pci.h | |||
@@ -43,12 +43,16 @@ | |||
43 | #define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7) | 43 | #define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7) |
44 | #define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7) | 44 | #define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7) |
45 | 45 | ||
46 | struct pci_dev; | ||
47 | |||
46 | #ifdef CONFIG_PCI | 48 | #ifdef CONFIG_PCI |
47 | extern void iSeries_pcibios_init(void); | 49 | extern void iSeries_pcibios_init(void); |
48 | extern void iSeries_pci_final_fixup(void); | 50 | extern void iSeries_pci_final_fixup(void); |
51 | extern void iSeries_pcibios_fixup_resources(struct pci_dev *dev); | ||
49 | #else | 52 | #else |
50 | static inline void iSeries_pcibios_init(void) { } | 53 | static inline void iSeries_pcibios_init(void) { } |
51 | static inline void iSeries_pci_final_fixup(void) { } | 54 | static inline void iSeries_pci_final_fixup(void) { } |
55 | static inline void iSeries_pcibios_fixup_resources(struct pci_dev *dev) {} | ||
52 | #endif | 56 | #endif |
53 | 57 | ||
54 | #endif /* _PLATFORMS_ISERIES_PCI_H */ | 58 | #endif /* _PLATFORMS_ISERIES_PCI_H */ |
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 5616219a20d5..b72120751bbe 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c | |||
@@ -639,24 +639,25 @@ static int __init iseries_probe(void) | |||
639 | } | 639 | } |
640 | 640 | ||
641 | define_machine(iseries) { | 641 | define_machine(iseries) { |
642 | .name = "iSeries", | 642 | .name = "iSeries", |
643 | .setup_arch = iSeries_setup_arch, | 643 | .setup_arch = iSeries_setup_arch, |
644 | .show_cpuinfo = iSeries_show_cpuinfo, | 644 | .show_cpuinfo = iSeries_show_cpuinfo, |
645 | .init_IRQ = iSeries_init_IRQ, | 645 | .init_IRQ = iSeries_init_IRQ, |
646 | .get_irq = iSeries_get_irq, | 646 | .get_irq = iSeries_get_irq, |
647 | .init_early = iSeries_init_early, | 647 | .init_early = iSeries_init_early, |
648 | .pcibios_fixup = iSeries_pci_final_fixup, | 648 | .pcibios_fixup = iSeries_pci_final_fixup, |
649 | .restart = mf_reboot, | 649 | .pcibios_fixup_resources= iSeries_pcibios_fixup_resources, |
650 | .power_off = mf_power_off, | 650 | .restart = mf_reboot, |
651 | .halt = mf_power_off, | 651 | .power_off = mf_power_off, |
652 | .get_boot_time = iSeries_get_boot_time, | 652 | .halt = mf_power_off, |
653 | .set_rtc_time = iSeries_set_rtc_time, | 653 | .get_boot_time = iSeries_get_boot_time, |
654 | .get_rtc_time = iSeries_get_rtc_time, | 654 | .set_rtc_time = iSeries_set_rtc_time, |
655 | .calibrate_decr = generic_calibrate_decr, | 655 | .get_rtc_time = iSeries_get_rtc_time, |
656 | .progress = iSeries_progress, | 656 | .calibrate_decr = generic_calibrate_decr, |
657 | .probe = iseries_probe, | 657 | .progress = iSeries_progress, |
658 | .ioremap = iseries_ioremap, | 658 | .probe = iseries_probe, |
659 | .iounmap = iseries_iounmap, | 659 | .ioremap = iseries_ioremap, |
660 | .iounmap = iseries_iounmap, | ||
660 | /* XXX Implement enable_pmcs for iSeries */ | 661 | /* XXX Implement enable_pmcs for iSeries */ |
661 | }; | 662 | }; |
662 | 663 | ||