aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/pci-common.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-12-10 22:48:18 -0500
committerPaul Mackerras <paulus@samba.org>2007-12-10 23:43:35 -0500
commit13dccb9e65dc0fa4de83e5bd5639f7a7f3f6fb9e (patch)
treee072ef034d6021359993253d1101ba7a03609760 /arch/powerpc/kernel/pci-common.c
parent25e81f925d4be0a0f60520e1c3c1b5af744404e1 (diff)
[POWERPC] Merge pci_process_bridge_OF_ranges()
This merges the 32-bit and 64-bit implementations of pci_process_bridge_OF_ranges(). The new function is cleaner than both the old ones, and supports 64 bits ranges on ppc32 which is necessary for the 4xx port. It also adds some better (hopefully) output to the kernel log which should help diagnose problems and makes better use of existing OF parsing helpers (avoiding a few bugs of both implementations along the way). There are still a few unfortunate ifdef's but there is no way around these for now at least not until some other bits of the PCI code are made common. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/pci-common.c')
-rw-r--r--arch/powerpc/kernel/pci-common.c177
1 files changed, 177 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index bea11df0a79b..9979c43cc8c7 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -462,3 +462,180 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
462 *start = rsrc->start - offset; 462 *start = rsrc->start - offset;
463 *end = rsrc->end - offset; 463 *end = rsrc->end - offset;
464} 464}
465
466/**
467 * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
468 * @hose: newly allocated pci_controller to be setup
469 * @dev: device node of the host bridge
470 * @primary: set if primary bus (32 bits only, soon to be deprecated)
471 *
472 * This function will parse the "ranges" property of a PCI host bridge device
473 * node and setup the resource mapping of a pci controller based on its
474 * content.
475 *
476 * Life would be boring if it wasn't for a few issues that we have to deal
477 * with here:
478 *
479 * - We can only cope with one IO space range and up to 3 Memory space
480 * ranges. However, some machines (thanks Apple !) tend to split their
481 * space into lots of small contiguous ranges. So we have to coalesce.
482 *
483 * - We can only cope with all memory ranges having the same offset
484 * between CPU addresses and PCI addresses. Unfortunately, some bridges
485 * are setup for a large 1:1 mapping along with a small "window" which
486 * maps PCI address 0 to some arbitrary high address of the CPU space in
487 * order to give access to the ISA memory hole.
488 * The way out of here that I've chosen for now is to always set the
489 * offset based on the first resource found, then override it if we
490 * have a different offset and the previous was set by an ISA hole.
491 *
492 * - Some busses have IO space not starting at 0, which causes trouble with
493 * the way we do our IO resource renumbering. The code somewhat deals with
494 * it for 64 bits but I would expect problems on 32 bits.
495 *
496 * - Some 32 bits platforms such as 4xx can have physical space larger than
497 * 32 bits so we need to use 64 bits values for the parsing
498 */
499void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
500 struct device_node *dev,
501 int primary)
502{
503 const u32 *ranges;
504 int rlen;
505 int pna = of_n_addr_cells(dev);
506 int np = pna + 5;
507 int memno = 0, isa_hole = -1;
508 u32 pci_space;
509 unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
510 unsigned long long isa_mb = 0;
511 struct resource *res;
512
513 printk(KERN_INFO "PCI host bridge %s %s ranges:\n",
514 dev->full_name, primary ? "(primary)" : "");
515
516 /* Get ranges property */
517 ranges = of_get_property(dev, "ranges", &rlen);
518 if (ranges == NULL)
519 return;
520
521 /* Parse it */
522 while ((rlen -= np * 4) >= 0) {
523 /* Read next ranges element */
524 pci_space = ranges[0];
525 pci_addr = of_read_number(ranges + 1, 2);
526 cpu_addr = of_translate_address(dev, ranges + 3);
527 size = of_read_number(ranges + pna + 3, 2);
528 ranges += np;
529 if (cpu_addr == OF_BAD_ADDR || size == 0)
530 continue;
531
532 /* Now consume following elements while they are contiguous */
533 for (; rlen >= np * sizeof(u32);
534 ranges += np, rlen -= np * 4) {
535 if (ranges[0] != pci_space)
536 break;
537 pci_next = of_read_number(ranges + 1, 2);
538 cpu_next = of_translate_address(dev, ranges + 3);
539 if (pci_next != pci_addr + size ||
540 cpu_next != cpu_addr + size)
541 break;
542 size += of_read_number(ranges + pna + 3, 2);
543 }
544
545 /* Act based on address space type */
546 res = NULL;
547 switch ((pci_space >> 24) & 0x3) {
548 case 1: /* PCI IO space */
549 printk(KERN_INFO
550 " IO 0x%016llx..0x%016llx -> 0x%016llx\n",
551 cpu_addr, cpu_addr + size - 1, pci_addr);
552
553 /* We support only one IO range */
554 if (hose->pci_io_size) {
555 printk(KERN_INFO
556 " \\--> Skipped (too many) !\n");
557 continue;
558 }
559#ifdef CONFIG_PPC32
560 /* On 32 bits, limit I/O space to 16MB */
561 if (size > 0x01000000)
562 size = 0x01000000;
563
564 /* 32 bits needs to map IOs here */
565 hose->io_base_virt = ioremap(cpu_addr, size);
566
567 /* Expect trouble if pci_addr is not 0 */
568 if (primary)
569 isa_io_base =
570 (unsigned long)hose->io_base_virt;
571#endif /* CONFIG_PPC32 */
572 /* pci_io_size and io_base_phys always represent IO
573 * space starting at 0 so we factor in pci_addr
574 */
575 hose->pci_io_size = pci_addr + size;
576 hose->io_base_phys = cpu_addr - pci_addr;
577
578 /* Build resource */
579 res = &hose->io_resource;
580 res->flags = IORESOURCE_IO;
581 res->start = pci_addr;
582 break;
583 case 2: /* PCI Memory space */
584 printk(KERN_INFO
585 " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
586 cpu_addr, cpu_addr + size - 1, pci_addr,
587 (pci_space & 0x40000000) ? "Prefetch" : "");
588
589 /* We support only 3 memory ranges */
590 if (memno >= 3) {
591 printk(KERN_INFO
592 " \\--> Skipped (too many) !\n");
593 continue;
594 }
595 /* Handles ISA memory hole space here */
596 if (pci_addr == 0) {
597 isa_mb = cpu_addr;
598 isa_hole = memno;
599 if (primary || isa_mem_base == 0)
600 isa_mem_base = cpu_addr;
601 }
602
603 /* We get the PCI/Mem offset from the first range or
604 * the, current one if the offset came from an ISA
605 * hole. If they don't match, bugger.
606 */
607 if (memno == 0 ||
608 (isa_hole >= 0 && pci_addr != 0 &&
609 hose->pci_mem_offset == isa_mb))
610 hose->pci_mem_offset = cpu_addr - pci_addr;
611 else if (pci_addr != 0 &&
612 hose->pci_mem_offset != cpu_addr - pci_addr) {
613 printk(KERN_INFO
614 " \\--> Skipped (offset mismatch) !\n");
615 continue;
616 }
617
618 /* Build resource */
619 res = &hose->mem_resources[memno++];
620 res->flags = IORESOURCE_MEM;
621 if (pci_space & 0x40000000)
622 res->flags |= IORESOURCE_PREFETCH;
623 res->start = cpu_addr;
624 break;
625 }
626 if (res != NULL) {
627 res->name = dev->full_name;
628 res->end = res->start + size - 1;
629 res->parent = NULL;
630 res->sibling = NULL;
631 res->child = NULL;
632 }
633 }
634
635 /* Out of paranoia, let's put the ISA hole last if any */
636 if (isa_hole >= 0 && memno > 0 && isa_hole != (memno-1)) {
637 struct resource tmp = hose->mem_resources[isa_hole];
638 hose->mem_resources[isa_hole] = hose->mem_resources[memno-1];
639 hose->mem_resources[memno-1] = tmp;
640 }
641}