diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-06-21 21:18:47 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-06-24 02:15:07 -0400 |
commit | e87dc35020bc555969810452f44bceaf8394eafa (patch) | |
tree | b58f14d41f8e147f6ddc2d9657a88813fdb73bdf /arch/sparc64/kernel/pci_sun4v.c | |
parent | aaf7cec2769942035985716452107fc5ba0b11f6 (diff) |
[SPARC64]: Use in-kernel OBP device tree for PCI controller probing.
It can be pushed even further down, but this is a first step.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/pci_sun4v.c')
-rw-r--r-- | arch/sparc64/kernel/pci_sun4v.c | 144 |
1 files changed, 65 insertions, 79 deletions
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 5419480edf41..b63b2834133f 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <asm/pstate.h> | 18 | #include <asm/pstate.h> |
19 | #include <asm/oplib.h> | 19 | #include <asm/oplib.h> |
20 | #include <asm/hypervisor.h> | 20 | #include <asm/hypervisor.h> |
21 | #include <asm/prom.h> | ||
21 | 22 | ||
22 | #include "pci_impl.h" | 23 | #include "pci_impl.h" |
23 | #include "iommu_common.h" | 24 | #include "iommu_common.h" |
@@ -646,35 +647,37 @@ static int pdev_htab_add(u32 devhandle, unsigned int bus, unsigned int device, u | |||
646 | /* Recursively descend into the OBP device tree, rooted at toplevel_node, | 647 | /* Recursively descend into the OBP device tree, rooted at toplevel_node, |
647 | * looking for a PCI device matching bus and devfn. | 648 | * looking for a PCI device matching bus and devfn. |
648 | */ | 649 | */ |
649 | static int obp_find(struct linux_prom_pci_registers *pregs, int toplevel_node, unsigned int bus, unsigned int devfn) | 650 | static int obp_find(struct device_node *toplevel_node, unsigned int bus, unsigned int devfn) |
650 | { | 651 | { |
651 | toplevel_node = prom_getchild(toplevel_node); | 652 | toplevel_node = toplevel_node->child; |
652 | 653 | ||
653 | while (toplevel_node != 0) { | 654 | while (toplevel_node != NULL) { |
654 | int ret = obp_find(pregs, toplevel_node, bus, devfn); | 655 | struct linux_prom_pci_registers *regs; |
656 | struct property *prop; | ||
657 | int ret; | ||
655 | 658 | ||
659 | ret = obp_find(toplevel_node, bus, devfn); | ||
656 | if (ret != 0) | 660 | if (ret != 0) |
657 | return ret; | 661 | return ret; |
658 | 662 | ||
659 | ret = prom_getproperty(toplevel_node, "reg", (char *) pregs, | 663 | prop = of_find_property(toplevel_node, "reg", NULL); |
660 | sizeof(*pregs) * PROMREG_MAX); | 664 | if (!prop) |
661 | if (ret == 0 || ret == -1) | ||
662 | goto next_sibling; | 665 | goto next_sibling; |
663 | 666 | ||
664 | if (((pregs[0].phys_hi >> 16) & 0xff) == bus && | 667 | regs = prop->value; |
665 | ((pregs[0].phys_hi >> 8) & 0xff) == devfn) | 668 | if (((regs->phys_hi >> 16) & 0xff) == bus && |
669 | ((regs->phys_hi >> 8) & 0xff) == devfn) | ||
666 | break; | 670 | break; |
667 | 671 | ||
668 | next_sibling: | 672 | next_sibling: |
669 | toplevel_node = prom_getsibling(toplevel_node); | 673 | toplevel_node = toplevel_node->sibling; |
670 | } | 674 | } |
671 | 675 | ||
672 | return toplevel_node; | 676 | return toplevel_node != NULL; |
673 | } | 677 | } |
674 | 678 | ||
675 | static int pdev_htab_populate(struct pci_pbm_info *pbm) | 679 | static int pdev_htab_populate(struct pci_pbm_info *pbm) |
676 | { | 680 | { |
677 | struct linux_prom_pci_registers pr[PROMREG_MAX]; | ||
678 | u32 devhandle = pbm->devhandle; | 681 | u32 devhandle = pbm->devhandle; |
679 | unsigned int bus; | 682 | unsigned int bus; |
680 | 683 | ||
@@ -685,7 +688,7 @@ static int pdev_htab_populate(struct pci_pbm_info *pbm) | |||
685 | unsigned int device = PCI_SLOT(devfn); | 688 | unsigned int device = PCI_SLOT(devfn); |
686 | unsigned int func = PCI_FUNC(devfn); | 689 | unsigned int func = PCI_FUNC(devfn); |
687 | 690 | ||
688 | if (obp_find(pr, pbm->prom_node, bus, devfn)) { | 691 | if (obp_find(pbm->prom_node, bus, devfn)) { |
689 | int err = pdev_htab_add(devhandle, bus, | 692 | int err = pdev_htab_add(devhandle, bus, |
690 | device, func); | 693 | device, func); |
691 | if (err) | 694 | if (err) |
@@ -812,7 +815,7 @@ static void pbm_scan_bus(struct pci_controller_info *p, | |||
812 | pbm->pci_bus->self->sysdata = cookie; | 815 | pbm->pci_bus->self->sysdata = cookie; |
813 | #endif | 816 | #endif |
814 | pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, | 817 | pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, |
815 | pbm->prom_node); | 818 | pbm->prom_node->node); |
816 | pci_record_assignments(pbm, pbm->pci_bus); | 819 | pci_record_assignments(pbm, pbm->pci_bus); |
817 | pci_assign_unassigned(pbm, pbm->pci_bus); | 820 | pci_assign_unassigned(pbm, pbm->pci_bus); |
818 | pci_fixup_irq(pbm, pbm->pci_bus); | 821 | pci_fixup_irq(pbm, pbm->pci_bus); |
@@ -822,15 +825,18 @@ static void pbm_scan_bus(struct pci_controller_info *p, | |||
822 | 825 | ||
823 | static void pci_sun4v_scan_bus(struct pci_controller_info *p) | 826 | static void pci_sun4v_scan_bus(struct pci_controller_info *p) |
824 | { | 827 | { |
825 | if (p->pbm_A.prom_node) { | 828 | struct property *prop; |
826 | p->pbm_A.is_66mhz_capable = | 829 | struct device_node *dp; |
827 | prom_getbool(p->pbm_A.prom_node, "66mhz-capable"); | 830 | |
831 | if ((dp = p->pbm_A.prom_node) != NULL) { | ||
832 | prop = of_find_property(dp, "66mhz-capable", NULL); | ||
833 | p->pbm_A.is_66mhz_capable = (prop != NULL); | ||
828 | 834 | ||
829 | pbm_scan_bus(p, &p->pbm_A); | 835 | pbm_scan_bus(p, &p->pbm_A); |
830 | } | 836 | } |
831 | if (p->pbm_B.prom_node) { | 837 | if ((dp = p->pbm_B.prom_node) != NULL) { |
832 | p->pbm_B.is_66mhz_capable = | 838 | prop = of_find_property(dp, "66mhz-capable", NULL); |
833 | prom_getbool(p->pbm_B.prom_node, "66mhz-capable"); | 839 | p->pbm_B.is_66mhz_capable = (prop != NULL); |
834 | 840 | ||
835 | pbm_scan_bus(p, &p->pbm_B); | 841 | pbm_scan_bus(p, &p->pbm_B); |
836 | } | 842 | } |
@@ -993,13 +999,18 @@ static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, | |||
993 | static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) | 999 | static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) |
994 | { | 1000 | { |
995 | struct pci_iommu *iommu = pbm->iommu; | 1001 | struct pci_iommu *iommu = pbm->iommu; |
1002 | struct property *prop; | ||
996 | unsigned long num_tsb_entries, sz; | 1003 | unsigned long num_tsb_entries, sz; |
997 | u32 vdma[2], dma_mask, dma_offset; | 1004 | u32 vdma[2], dma_mask, dma_offset; |
998 | int err, tsbsize; | 1005 | int tsbsize; |
1006 | |||
1007 | prop = of_find_property(pbm->prom_node, "virtual-dma", NULL); | ||
1008 | if (prop) { | ||
1009 | u32 *val = prop->value; | ||
999 | 1010 | ||
1000 | err = prom_getproperty(pbm->prom_node, "virtual-dma", | 1011 | vdma[0] = val[0]; |
1001 | (char *)&vdma[0], sizeof(vdma)); | 1012 | vdma[1] = val[1]; |
1002 | if (err == 0 || err == -1) { | 1013 | } else { |
1003 | /* No property, use default values. */ | 1014 | /* No property, use default values. */ |
1004 | vdma[0] = 0x80000000; | 1015 | vdma[0] = 0x80000000; |
1005 | vdma[1] = 0x80000000; | 1016 | vdma[1] = 0x80000000; |
@@ -1058,27 +1069,23 @@ static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) | |||
1058 | 1069 | ||
1059 | static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm) | 1070 | static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm) |
1060 | { | 1071 | { |
1061 | unsigned int busrange[2]; | 1072 | struct property *prop; |
1062 | int prom_node = pbm->prom_node; | 1073 | unsigned int *busrange; |
1063 | int err; | 1074 | |
1064 | 1075 | prop = of_find_property(pbm->prom_node, "bus-range", NULL); | |
1065 | err = prom_getproperty(prom_node, "bus-range", | 1076 | |
1066 | (char *)&busrange[0], | 1077 | busrange = prop->value; |
1067 | sizeof(busrange)); | ||
1068 | if (err == 0 || err == -1) { | ||
1069 | prom_printf("%s: Fatal error, no bus-range.\n", pbm->name); | ||
1070 | prom_halt(); | ||
1071 | } | ||
1072 | 1078 | ||
1073 | pbm->pci_first_busno = busrange[0]; | 1079 | pbm->pci_first_busno = busrange[0]; |
1074 | pbm->pci_last_busno = busrange[1]; | 1080 | pbm->pci_last_busno = busrange[1]; |
1075 | 1081 | ||
1076 | } | 1082 | } |
1077 | 1083 | ||
1078 | static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 devhandle) | 1084 | static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle) |
1079 | { | 1085 | { |
1080 | struct pci_pbm_info *pbm; | 1086 | struct pci_pbm_info *pbm; |
1081 | int err, i; | 1087 | struct property *prop; |
1088 | int len, i; | ||
1082 | 1089 | ||
1083 | if (devhandle & 0x40) | 1090 | if (devhandle & 0x40) |
1084 | pbm = &p->pbm_B; | 1091 | pbm = &p->pbm_B; |
@@ -1086,32 +1093,19 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 | |||
1086 | pbm = &p->pbm_A; | 1093 | pbm = &p->pbm_A; |
1087 | 1094 | ||
1088 | pbm->parent = p; | 1095 | pbm->parent = p; |
1089 | pbm->prom_node = prom_node; | 1096 | pbm->prom_node = dp; |
1090 | pbm->pci_first_slot = 1; | 1097 | pbm->pci_first_slot = 1; |
1091 | 1098 | ||
1092 | pbm->devhandle = devhandle; | 1099 | pbm->devhandle = devhandle; |
1093 | 1100 | ||
1094 | sprintf(pbm->name, "SUN4V-PCI%d PBM%c", | 1101 | pbm->name = dp->full_name; |
1095 | p->index, (pbm == &p->pbm_A ? 'A' : 'B')); | ||
1096 | |||
1097 | printk("%s: devhandle[%x] prom_node[%x:%x]\n", | ||
1098 | pbm->name, pbm->devhandle, | ||
1099 | pbm->prom_node, prom_getchild(pbm->prom_node)); | ||
1100 | 1102 | ||
1101 | prom_getstring(prom_node, "name", | 1103 | printk("%s: SUN4V PCI Bus Module\n", pbm->name); |
1102 | pbm->prom_name, sizeof(pbm->prom_name)); | ||
1103 | |||
1104 | err = prom_getproperty(prom_node, "ranges", | ||
1105 | (char *) pbm->pbm_ranges, | ||
1106 | sizeof(pbm->pbm_ranges)); | ||
1107 | if (err == 0 || err == -1) { | ||
1108 | prom_printf("%s: Fatal error, no ranges property.\n", | ||
1109 | pbm->name); | ||
1110 | prom_halt(); | ||
1111 | } | ||
1112 | 1104 | ||
1105 | prop = of_find_property(dp, "ranges", &len); | ||
1106 | pbm->pbm_ranges = prop->value; | ||
1113 | pbm->num_pbm_ranges = | 1107 | pbm->num_pbm_ranges = |
1114 | (err / sizeof(struct linux_prom_pci_ranges)); | 1108 | (len / sizeof(struct linux_prom_pci_ranges)); |
1115 | 1109 | ||
1116 | /* Mask out the top 8 bits of the ranges, leaving the real | 1110 | /* Mask out the top 8 bits of the ranges, leaving the real |
1117 | * physical address. | 1111 | * physical address. |
@@ -1122,24 +1116,13 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 | |||
1122 | pci_sun4v_determine_mem_io_space(pbm); | 1116 | pci_sun4v_determine_mem_io_space(pbm); |
1123 | pbm_register_toplevel_resources(p, pbm); | 1117 | pbm_register_toplevel_resources(p, pbm); |
1124 | 1118 | ||
1125 | err = prom_getproperty(prom_node, "interrupt-map", | 1119 | prop = of_find_property(dp, "interrupt-map", &len); |
1126 | (char *)pbm->pbm_intmap, | 1120 | pbm->pbm_intmap = prop->value; |
1127 | sizeof(pbm->pbm_intmap)); | 1121 | pbm->num_pbm_intmap = |
1128 | if (err == 0 || err == -1) { | 1122 | (len / sizeof(struct linux_prom_pci_intmap)); |
1129 | prom_printf("%s: Fatal error, no interrupt-map property.\n", | ||
1130 | pbm->name); | ||
1131 | prom_halt(); | ||
1132 | } | ||
1133 | 1123 | ||
1134 | pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); | 1124 | prop = of_find_property(dp, "interrupt-map-mask", NULL); |
1135 | err = prom_getproperty(prom_node, "interrupt-map-mask", | 1125 | pbm->pbm_intmask = prop->value; |
1136 | (char *)&pbm->pbm_intmask, | ||
1137 | sizeof(pbm->pbm_intmask)); | ||
1138 | if (err == 0 || err == -1) { | ||
1139 | prom_printf("%s: Fatal error, no interrupt-map-mask.\n", | ||
1140 | pbm->name); | ||
1141 | prom_halt(); | ||
1142 | } | ||
1143 | 1126 | ||
1144 | pci_sun4v_get_bus_range(pbm); | 1127 | pci_sun4v_get_bus_range(pbm); |
1145 | pci_sun4v_iommu_init(pbm); | 1128 | pci_sun4v_iommu_init(pbm); |
@@ -1147,16 +1130,19 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, int prom_node, u32 | |||
1147 | pdev_htab_populate(pbm); | 1130 | pdev_htab_populate(pbm); |
1148 | } | 1131 | } |
1149 | 1132 | ||
1150 | void sun4v_pci_init(int node, char *model_name) | 1133 | void sun4v_pci_init(struct device_node *dp, char *model_name) |
1151 | { | 1134 | { |
1152 | struct pci_controller_info *p; | 1135 | struct pci_controller_info *p; |
1153 | struct pci_iommu *iommu; | 1136 | struct pci_iommu *iommu; |
1154 | struct linux_prom64_registers regs; | 1137 | struct property *prop; |
1138 | struct linux_prom64_registers *regs; | ||
1155 | u32 devhandle; | 1139 | u32 devhandle; |
1156 | int i; | 1140 | int i; |
1157 | 1141 | ||
1158 | prom_getproperty(node, "reg", (char *)®s, sizeof(regs)); | 1142 | prop = of_find_property(dp, "reg", NULL); |
1159 | devhandle = (regs.phys_addr >> 32UL) & 0x0fffffff; | 1143 | regs = prop->value; |
1144 | |||
1145 | devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff; | ||
1160 | 1146 | ||
1161 | for (p = pci_controller_root; p; p = p->next) { | 1147 | for (p = pci_controller_root; p; p = p->next) { |
1162 | struct pci_pbm_info *pbm; | 1148 | struct pci_pbm_info *pbm; |
@@ -1169,7 +1155,7 @@ void sun4v_pci_init(int node, char *model_name) | |||
1169 | &p->pbm_B); | 1155 | &p->pbm_B); |
1170 | 1156 | ||
1171 | if (pbm->devhandle == (devhandle ^ 0x40)) { | 1157 | if (pbm->devhandle == (devhandle ^ 0x40)) { |
1172 | pci_sun4v_pbm_init(p, node, devhandle); | 1158 | pci_sun4v_pbm_init(p, dp, devhandle); |
1173 | return; | 1159 | return; |
1174 | } | 1160 | } |
1175 | } | 1161 | } |
@@ -1220,7 +1206,7 @@ void sun4v_pci_init(int node, char *model_name) | |||
1220 | */ | 1206 | */ |
1221 | pci_memspace_mask = 0x7fffffffUL; | 1207 | pci_memspace_mask = 0x7fffffffUL; |
1222 | 1208 | ||
1223 | pci_sun4v_pbm_init(p, node, devhandle); | 1209 | pci_sun4v_pbm_init(p, dp, devhandle); |
1224 | return; | 1210 | return; |
1225 | 1211 | ||
1226 | fatal_memory_error: | 1212 | fatal_memory_error: |