aboutsummaryrefslogtreecommitdiffstats
path: root/arch
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
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')
-rw-r--r--arch/powerpc/kernel/pci-common.c177
-rw-r--r--arch/powerpc/kernel/pci_32.c114
-rw-r--r--arch/powerpc/kernel/pci_64.c93
3 files changed, 177 insertions, 207 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}
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index a33c2820c200..20a1192de1a2 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -842,120 +842,6 @@ pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
842} 842}
843EXPORT_SYMBOL(pci_device_from_OF_node); 843EXPORT_SYMBOL(pci_device_from_OF_node);
844 844
845void __init
846pci_process_bridge_OF_ranges(struct pci_controller *hose,
847 struct device_node *dev, int primary)
848{
849 static unsigned int static_lc_ranges[256] __initdata;
850 const unsigned int *dt_ranges;
851 unsigned int *lc_ranges, *ranges, *prev, size;
852 int rlen = 0, orig_rlen;
853 int memno = 0;
854 struct resource *res;
855 int np, na = of_n_addr_cells(dev);
856 np = na + 5;
857
858 /* First we try to merge ranges to fix a problem with some pmacs
859 * that can have more than 3 ranges, fortunately using contiguous
860 * addresses -- BenH
861 */
862 dt_ranges = of_get_property(dev, "ranges", &rlen);
863 if (!dt_ranges)
864 return;
865 /* Sanity check, though hopefully that never happens */
866 if (rlen > sizeof(static_lc_ranges)) {
867 printk(KERN_WARNING "OF ranges property too large !\n");
868 rlen = sizeof(static_lc_ranges);
869 }
870 lc_ranges = static_lc_ranges;
871 memcpy(lc_ranges, dt_ranges, rlen);
872 orig_rlen = rlen;
873
874 /* Let's work on a copy of the "ranges" property instead of damaging
875 * the device-tree image in memory
876 */
877 ranges = lc_ranges;
878 prev = NULL;
879 while ((rlen -= np * sizeof(unsigned int)) >= 0) {
880 if (prev) {
881 if (prev[0] == ranges[0] && prev[1] == ranges[1] &&
882 (prev[2] + prev[na+4]) == ranges[2] &&
883 (prev[na+2] + prev[na+4]) == ranges[na+2]) {
884 prev[na+4] += ranges[na+4];
885 ranges[0] = 0;
886 ranges += np;
887 continue;
888 }
889 }
890 prev = ranges;
891 ranges += np;
892 }
893
894 /*
895 * The ranges property is laid out as an array of elements,
896 * each of which comprises:
897 * cells 0 - 2: a PCI address
898 * cells 3 or 3+4: a CPU physical address
899 * (size depending on dev->n_addr_cells)
900 * cells 4+5 or 5+6: the size of the range
901 */
902 ranges = lc_ranges;
903 rlen = orig_rlen;
904 while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) {
905 res = NULL;
906 size = ranges[na+4];
907 switch ((ranges[0] >> 24) & 0x3) {
908 case 1: /* I/O space */
909 if (ranges[2] != 0)
910 break;
911 hose->io_base_phys = ranges[na+2];
912 /* limit I/O space to 16MB */
913 if (size > 0x01000000)
914 size = 0x01000000;
915 hose->io_base_virt = ioremap(ranges[na+2], size);
916 if (primary)
917 isa_io_base = (unsigned long) hose->io_base_virt;
918 res = &hose->io_resource;
919 res->flags = IORESOURCE_IO;
920 res->start = ranges[2];
921 DBG("PCI: IO 0x%llx -> 0x%llx\n",
922 (u64)res->start, (u64)res->start + size - 1);
923 break;
924 case 2: /* memory space */
925 memno = 0;
926 if (ranges[1] == 0 && ranges[2] == 0
927 && ranges[na+4] <= (16 << 20)) {
928 /* 1st 16MB, i.e. ISA memory area */
929 if (primary)
930 isa_mem_base = ranges[na+2];
931 memno = 1;
932 }
933 while (memno < 3 && hose->mem_resources[memno].flags)
934 ++memno;
935 if (memno == 0)
936 hose->pci_mem_offset = ranges[na+2] - ranges[2];
937 if (memno < 3) {
938 res = &hose->mem_resources[memno];
939 res->flags = IORESOURCE_MEM;
940 if(ranges[0] & 0x40000000)
941 res->flags |= IORESOURCE_PREFETCH;
942 res->start = ranges[na+2];
943 DBG("PCI: MEM[%d] 0x%llx -> 0x%llx\n", memno,
944 (u64)res->start, (u64)res->start + size - 1);
945 }
946 break;
947 }
948 if (res != NULL) {
949 res->name = dev->full_name;
950 res->end = res->start + size - 1;
951 res->parent = NULL;
952 res->sibling = NULL;
953 res->child = NULL;
954 }
955 ranges += np;
956 }
957}
958
959/* We create the "pci-OF-bus-map" property now so it appears in the 845/* We create the "pci-OF-bus-map" property now so it appears in the
960 * /proc device tree 846 * /proc device tree
961 */ 847 */
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 6b9a8564e735..bf06926f677d 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -578,99 +578,6 @@ int pci_proc_domain(struct pci_bus *bus)
578 return hose->buid != 0; 578 return hose->buid != 0;
579} 579}
580 580
581void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
582 struct device_node *dev, int prim)
583{
584 const unsigned int *ranges;
585 unsigned int pci_space;
586 unsigned long size;
587 int rlen = 0;
588 int memno = 0;
589 struct resource *res;
590 int np, na = of_n_addr_cells(dev);
591 unsigned long pci_addr, cpu_phys_addr;
592
593 np = na + 5;
594
595 /* From "PCI Binding to 1275"
596 * The ranges property is laid out as an array of elements,
597 * each of which comprises:
598 * cells 0 - 2: a PCI address
599 * cells 3 or 3+4: a CPU physical address
600 * (size depending on dev->n_addr_cells)
601 * cells 4+5 or 5+6: the size of the range
602 */
603 ranges = of_get_property(dev, "ranges", &rlen);
604 if (ranges == NULL)
605 return;
606 hose->io_base_phys = 0;
607 while ((rlen -= np * sizeof(unsigned int)) >= 0) {
608 res = NULL;
609 pci_space = ranges[0];
610 pci_addr = ((unsigned long)ranges[1] << 32) | ranges[2];
611 cpu_phys_addr = of_translate_address(dev, &ranges[3]);
612 size = ((unsigned long)ranges[na+3] << 32) | ranges[na+4];
613 ranges += np;
614 if (size == 0)
615 continue;
616
617 /* Now consume following elements while they are contiguous */
618 while (rlen >= np * sizeof(unsigned int)) {
619 unsigned long addr, phys;
620
621 if (ranges[0] != pci_space)
622 break;
623 addr = ((unsigned long)ranges[1] << 32) | ranges[2];
624 phys = ranges[3];
625 if (na >= 2)
626 phys = (phys << 32) | ranges[4];
627 if (addr != pci_addr + size ||
628 phys != cpu_phys_addr + size)
629 break;
630
631 size += ((unsigned long)ranges[na+3] << 32)
632 | ranges[na+4];
633 ranges += np;
634 rlen -= np * sizeof(unsigned int);
635 }
636
637 switch ((pci_space >> 24) & 0x3) {
638 case 1: /* I/O space */
639 hose->io_base_phys = cpu_phys_addr - pci_addr;
640 /* handle from 0 to top of I/O window */
641 hose->pci_io_size = pci_addr + size;
642
643 res = &hose->io_resource;
644 res->flags = IORESOURCE_IO;
645 res->start = pci_addr;
646 DBG("phb%d: IO 0x%lx -> 0x%lx\n", hose->global_number,
647 res->start, res->start + size - 1);
648 break;
649 case 2: /* memory space */
650 memno = 0;
651 while (memno < 3 && hose->mem_resources[memno].flags)
652 ++memno;
653
654 if (memno == 0)
655 hose->pci_mem_offset = cpu_phys_addr - pci_addr;
656 if (memno < 3) {
657 res = &hose->mem_resources[memno];
658 res->flags = IORESOURCE_MEM;
659 res->start = cpu_phys_addr;
660 DBG("phb%d: MEM 0x%lx -> 0x%lx\n", hose->global_number,
661 res->start, res->start + size - 1);
662 }
663 break;
664 }
665 if (res != NULL) {
666 res->name = dev->full_name;
667 res->end = res->start + size - 1;
668 res->parent = NULL;
669 res->sibling = NULL;
670 res->child = NULL;
671 }
672 }
673}
674 581
675#ifdef CONFIG_HOTPLUG 582#ifdef CONFIG_HOTPLUG
676 583