aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-12-19 22:54:55 -0500
committerPaul Mackerras <paulus@samba.org>2007-12-20 00:18:10 -0500
commit50c9bc2fc86fddd39eea6a12ceb81585bc2aafaa (patch)
treea6021e68bdc0477ada4bc81d04443e3316cdbb4f
parent3fd94c6b1a1158d3e0e505b0a00c3a707b5fcd40 (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.c16
-rw-r--r--arch/powerpc/kernel/pci_64.c19
-rw-r--r--arch/powerpc/platforms/iseries/pci.c125
-rw-r--r--arch/powerpc/platforms/iseries/pci.h4
-rw-r--r--arch/powerpc/platforms/iseries/setup.c37
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
62static unsigned long max_io_memory = BASE_IO_MEMORY; 66static unsigned long max_io_memory = BASE_IO_MEMORY;
63static long current_iomm_table_entry; 67static long current_iomm_table_entry;
@@ -68,7 +72,6 @@ static long current_iomm_table_entry;
68static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES]; 72static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES];
69static u8 iobar_table[IOMM_TABLE_MAX_ENTRIES]; 73static u8 iobar_table[IOMM_TABLE_MAX_ENTRIES];
70 74
71static const char pci_io_text[] = "iSeries PCI I/O";
72static DEFINE_SPINLOCK(iomm_table_lock); 75static 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 */
282static void __init iseries_device_information(struct pci_dev *pdev, int count, 285static 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 */
398void __init iSeries_pci_final_fixup(void) 401void __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 */
450void __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
46struct pci_dev;
47
46#ifdef CONFIG_PCI 48#ifdef CONFIG_PCI
47extern void iSeries_pcibios_init(void); 49extern void iSeries_pcibios_init(void);
48extern void iSeries_pci_final_fixup(void); 50extern void iSeries_pci_final_fixup(void);
51extern void iSeries_pcibios_fixup_resources(struct pci_dev *dev);
49#else 52#else
50static inline void iSeries_pcibios_init(void) { } 53static inline void iSeries_pcibios_init(void) { }
51static inline void iSeries_pci_final_fixup(void) { } 54static inline void iSeries_pci_final_fixup(void) { }
55static 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
641define_machine(iseries) { 641define_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