aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/powermac/pci.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-12-19 22:55:02 -0500
committerPaul Mackerras <paulus@samba.org>2007-12-20 00:18:14 -0500
commitd0264ce796e4e3d77fdadf72d6625f8e6c1c96bd (patch)
tree3b06b866c224c978b04673103ec35373d49b2408 /arch/powerpc/platforms/powermac/pci.c
parent444532d44aa6bc4d6e3ca74d8ad99c36f3b4d9f0 (diff)
[POWERPC] Improve resource setup of PowerMac G5 HT bridge
The device node for the HT bridge on G5s doesn't contain useful ranges. We used to give it a bunch of the known PCI space and then punch a "hole" in it based on where the AGP or PCIe region was. This reworks it to use the actual register in the bridge that controls the decoding instead. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/powermac/pci.c')
-rw-r--r--arch/powerpc/platforms/powermac/pci.c142
1 files changed, 64 insertions, 78 deletions
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index 6c93e7c0da15..1c58db9d42cb 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -40,8 +40,6 @@
40static int has_uninorth; 40static int has_uninorth;
41#ifdef CONFIG_PPC64 41#ifdef CONFIG_PPC64
42static struct pci_controller *u3_agp; 42static struct pci_controller *u3_agp;
43static struct pci_controller *u4_pcie;
44static struct pci_controller *u3_ht;
45#else 43#else
46static int has_second_ohare; 44static int has_second_ohare;
47#endif /* CONFIG_PPC64 */ 45#endif /* CONFIG_PPC64 */
@@ -779,16 +777,50 @@ static void __init setup_u4_pcie(struct pci_controller* hose)
779 */ 777 */
780 hose->first_busno = 0x00; 778 hose->first_busno = 0x00;
781 hose->last_busno = 0xff; 779 hose->last_busno = 0xff;
782 u4_pcie = hose; 780}
781
782static void __init parse_region_decode(struct pci_controller *hose,
783 u32 decode)
784{
785 unsigned long base, end, next = -1;
786 int i, cur = -1;
787
788 /* Iterate through all bits. We ignore the last bit as this region is
789 * reserved for the ROM among other niceties
790 */
791 for (i = 0; i < 31; i++) {
792 if ((decode & (0x80000000 >> i)) == 0)
793 continue;
794 if (i < 16) {
795 base = 0xf0000000 | (((u32)i) << 24);
796 end = base + 0x00ffffff;
797 } else {
798 base = ((u32)i-16) << 28;
799 end = base + 0x0fffffff;
800 }
801 if (base != next) {
802 if (++cur >= 3) {
803 printk(KERN_WARNING "PCI: Too many ranges !\n");
804 break;
805 }
806 hose->mem_resources[cur].flags = IORESOURCE_MEM;
807 hose->mem_resources[cur].name = hose->dn->full_name;
808 hose->mem_resources[cur].start = base;
809 hose->mem_resources[cur].end = end;
810 DBG(" %d: 0x%08lx-0x%08lx\n", cur, base, end);
811 } else {
812 DBG(" : -0x%08lx\n", end);
813 hose->mem_resources[cur].end = end;
814 }
815 next = end + 1;
816 }
783} 817}
784 818
785static void __init setup_u3_ht(struct pci_controller* hose) 819static void __init setup_u3_ht(struct pci_controller* hose)
786{ 820{
787 struct device_node *np = hose->dn; 821 struct device_node *np = hose->dn;
788 struct pci_controller *other = NULL;
789 struct resource cfg_res, self_res; 822 struct resource cfg_res, self_res;
790 int i, cur; 823 u32 decode;
791
792 824
793 hose->ops = &u3_ht_pci_ops; 825 hose->ops = &u3_ht_pci_ops;
794 826
@@ -808,12 +840,9 @@ static void __init setup_u3_ht(struct pci_controller* hose)
808 self_res.end - self_res.start + 1); 840 self_res.end - self_res.start + 1);
809 841
810 /* 842 /*
811 * /ht node doesn't expose a "ranges" property, so we "remove" 843 * /ht node doesn't expose a "ranges" property, we read the register
812 * regions that have been allocated to AGP. So far, this version of 844 * that controls the decoding logic and use that for memory regions.
813 * the code doesn't assign any of the 0xfxxxxxxx "fine" memory regions 845 * The IO region is hard coded since it is fixed in HW as well.
814 * to /ht. We need to fix that sooner or later by either parsing all
815 * child "ranges" properties or figuring out the U3 address space
816 * decoding logic and then read its configuration register (if any).
817 */ 846 */
818 hose->io_base_phys = 0xf4000000; 847 hose->io_base_phys = 0xf4000000;
819 hose->pci_io_size = 0x00400000; 848 hose->pci_io_size = 0x00400000;
@@ -824,76 +853,33 @@ static void __init setup_u3_ht(struct pci_controller* hose)
824 hose->pci_mem_offset = 0; 853 hose->pci_mem_offset = 0;
825 hose->first_busno = 0; 854 hose->first_busno = 0;
826 hose->last_busno = 0xef; 855 hose->last_busno = 0xef;
827 hose->mem_resources[0].name = np->full_name;
828 hose->mem_resources[0].start = 0x80000000;
829 hose->mem_resources[0].end = 0xefffffff;
830 hose->mem_resources[0].flags = IORESOURCE_MEM;
831
832 u3_ht = hose;
833 856
834 if (u3_agp != NULL) 857 /* Note: fix offset when cfg_addr becomes a void * */
835 other = u3_agp; 858 decode = in_be32(hose->cfg_addr + 0x80);
836 else if (u4_pcie != NULL)
837 other = u4_pcie;
838
839 if (other == NULL) {
840 DBG("U3/4 has no AGP/PCIE, using full resource range\n");
841 return;
842 }
843 859
844 /* Fixup bus range vs. PCIE */ 860 DBG("PCI: Apple HT bridge decode register: 0x%08x\n", decode);
845 if (u4_pcie)
846 hose->last_busno = u4_pcie->first_busno - 1;
847 861
848 /* We "remove" the AGP resources from the resources allocated to HT, 862 /* NOTE: The decode register setup is a bit weird... region
849 * that is we create "holes". However, that code does assumptions 863 * 0xf8000000 for example is marked as enabled in there while it's
850 * that so far happen to be true (cross fingers...), typically that 864 & actually the memory controller registers.
851 * resources in the AGP node are properly ordered 865 * That means that we are incorrectly attributing it to HT.
866 *
867 * In a similar vein, region 0xf4000000 is actually the HT IO space but
868 * also marked as enabled in here and 0xf9000000 is used by some other
869 * internal bits of the northbridge.
870 *
871 * Unfortunately, we can't just mask out those bit as we would end
872 * up with more regions than we can cope (linux can only cope with
873 * 3 memory regions for a PHB at this stage).
874 *
875 * So for now, we just do a little hack. We happen to -know- that
876 * Apple firmware doesn't assign things below 0xfa000000 for that
877 * bridge anyway so we mask out all bits we don't want.
852 */ 878 */
853 cur = 0; 879 decode &= 0x003fffff;
854 for (i=0; i<3; i++) { 880
855 struct resource *res = &other->mem_resources[i]; 881 /* Now parse the resulting bits and build resources */
856 if (res->flags != IORESOURCE_MEM) 882 parse_region_decode(hose, decode);
857 continue;
858 /* We don't care about "fine" resources */
859 if (res->start >= 0xf0000000)
860 continue;
861 /* Check if it's just a matter of "shrinking" us in one
862 * direction
863 */
864 if (hose->mem_resources[cur].start == res->start) {
865 DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n",
866 cur, hose->mem_resources[cur].start,
867 res->end + 1);
868 hose->mem_resources[cur].start = res->end + 1;
869 continue;
870 }
871 if (hose->mem_resources[cur].end == res->end) {
872 DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n",
873 cur, hose->mem_resources[cur].end,
874 res->start - 1);
875 hose->mem_resources[cur].end = res->start - 1;
876 continue;
877 }
878 /* No, it's not the case, we need a hole */
879 if (cur == 2) {
880 /* not enough resources for a hole, we drop part
881 * of the range
882 */
883 printk(KERN_WARNING "Running out of resources"
884 " for /ht host !\n");
885 hose->mem_resources[cur].end = res->start - 1;
886 continue;
887 }
888 cur++;
889 DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n",
890 cur-1, res->start - 1, cur, res->end + 1);
891 hose->mem_resources[cur].name = np->full_name;
892 hose->mem_resources[cur].flags = IORESOURCE_MEM;
893 hose->mem_resources[cur].start = res->end + 1;
894 hose->mem_resources[cur].end = hose->mem_resources[cur-1].end;
895 hose->mem_resources[cur-1].end = res->start - 1;
896 }
897} 883}
898#endif /* CONFIG_PPC64 */ 884#endif /* CONFIG_PPC64 */
899 885