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 /arch/powerpc/platforms/iseries/pci.c | |
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>
Diffstat (limited to 'arch/powerpc/platforms/iseries/pci.c')
-rw-r--r-- | arch/powerpc/platforms/iseries/pci.c | 125 |
1 files changed, 68 insertions, 57 deletions
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); |