diff options
-rw-r--r-- | arch/powerpc/kernel/pci-common.c | 177 | ||||
-rw-r--r-- | arch/powerpc/kernel/pci_32.c | 114 | ||||
-rw-r--r-- | arch/powerpc/kernel/pci_64.c | 93 | ||||
-rw-r--r-- | include/asm-powerpc/pci-bridge.h | 3 |
4 files changed, 180 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 | */ | ||
499 | void __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 | } |
843 | EXPORT_SYMBOL(pci_device_from_OF_node); | 843 | EXPORT_SYMBOL(pci_device_from_OF_node); |
844 | 844 | ||
845 | void __init | ||
846 | pci_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 | ||
581 | void __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 | ||
diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index f139f2a44b19..8245e84836c9 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h | |||
@@ -37,6 +37,9 @@ struct pci_controller { | |||
37 | void *io_base_alloc; | 37 | void *io_base_alloc; |
38 | #endif | 38 | #endif |
39 | resource_size_t io_base_phys; | 39 | resource_size_t io_base_phys; |
40 | #ifndef CONFIG_PPC64 | ||
41 | resource_size_t pci_io_size; | ||
42 | #endif | ||
40 | 43 | ||
41 | /* Some machines (PReP) have a non 1:1 mapping of | 44 | /* Some machines (PReP) have a non 1:1 mapping of |
42 | * the PCI memory space in the CPU bus space | 45 | * the PCI memory space in the CPU bus space |