diff options
author | Gavin Shan <shangw@linux.vnet.ibm.com> | 2013-04-25 15:20:57 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-04-26 02:08:27 -0400 |
commit | aa0c033f99d9c32a8dd6b1e07d41caf1fced0e1a (patch) | |
tree | b9a3bb8f380ec942856acef7962a00efb653952c /arch/powerpc/platforms | |
parent | a485c70989fc6e1b002ea8c323bc3fc2f1eab722 (diff) |
powerpc/powernv: Supports PHB3
The patch intends to initialize PHB3 during system boot stage. The
flag "PNV_PHB_MODEL_PHB3" is introduced to differentiate IODA2
compatible PHB3 from other types of PHBs.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r-- | arch/powerpc/platforms/powernv/pci-ioda.c | 62 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/powernv/pci.h | 8 |
3 files changed, 42 insertions, 34 deletions
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index a5c5f15242ba..3d4e9588a695 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c | |||
@@ -852,18 +852,19 @@ static u32 pnv_ioda_bdfn_to_pe(struct pnv_phb *phb, struct pci_bus *bus, | |||
852 | return phb->ioda.pe_rmap[(bus->number << 8) | devfn]; | 852 | return phb->ioda.pe_rmap[(bus->number << 8) | devfn]; |
853 | } | 853 | } |
854 | 854 | ||
855 | void __init pnv_pci_init_ioda1_phb(struct device_node *np) | 855 | void __init pnv_pci_init_ioda_phb(struct device_node *np, int ioda_type) |
856 | { | 856 | { |
857 | struct pci_controller *hose; | 857 | struct pci_controller *hose; |
858 | static int primary = 1; | 858 | static int primary = 1; |
859 | struct pnv_phb *phb; | 859 | struct pnv_phb *phb; |
860 | unsigned long size, m32map_off, iomap_off, pemap_off; | 860 | unsigned long size, m32map_off, iomap_off, pemap_off; |
861 | const u64 *prop64; | 861 | const u64 *prop64; |
862 | const u32 *prop32; | ||
862 | u64 phb_id; | 863 | u64 phb_id; |
863 | void *aux; | 864 | void *aux; |
864 | long rc; | 865 | long rc; |
865 | 866 | ||
866 | pr_info(" Initializing IODA OPAL PHB %s\n", np->full_name); | 867 | pr_info(" Initializing IODA%d OPAL PHB %s\n", ioda_type, np->full_name); |
867 | 868 | ||
868 | prop64 = of_get_property(np, "ibm,opal-phbid", NULL); | 869 | prop64 = of_get_property(np, "ibm,opal-phbid", NULL); |
869 | if (!prop64) { | 870 | if (!prop64) { |
@@ -890,37 +891,34 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np) | |||
890 | hose->last_busno = 0xff; | 891 | hose->last_busno = 0xff; |
891 | hose->private_data = phb; | 892 | hose->private_data = phb; |
892 | phb->opal_id = phb_id; | 893 | phb->opal_id = phb_id; |
893 | phb->type = PNV_PHB_IODA1; | 894 | phb->type = ioda_type; |
894 | 895 | ||
895 | /* Detect specific models for error handling */ | 896 | /* Detect specific models for error handling */ |
896 | if (of_device_is_compatible(np, "ibm,p7ioc-pciex")) | 897 | if (of_device_is_compatible(np, "ibm,p7ioc-pciex")) |
897 | phb->model = PNV_PHB_MODEL_P7IOC; | 898 | phb->model = PNV_PHB_MODEL_P7IOC; |
899 | else if (of_device_is_compatible(np, "ibm,p8-pciex")) | ||
900 | phb->model = PNV_PHB_MODEL_PHB3; | ||
898 | else | 901 | else |
899 | phb->model = PNV_PHB_MODEL_UNKNOWN; | 902 | phb->model = PNV_PHB_MODEL_UNKNOWN; |
900 | 903 | ||
901 | /* We parse "ranges" now since we need to deduce the register base | 904 | /* Parse 32-bit and IO ranges (if any) */ |
902 | * from the IO base | ||
903 | */ | ||
904 | pci_process_bridge_OF_ranges(phb->hose, np, primary); | 905 | pci_process_bridge_OF_ranges(phb->hose, np, primary); |
905 | primary = 0; | 906 | primary = 0; |
906 | 907 | ||
907 | /* Magic formula from Milton */ | 908 | /* Get registers */ |
908 | phb->regs = of_iomap(np, 0); | 909 | phb->regs = of_iomap(np, 0); |
909 | if (phb->regs == NULL) | 910 | if (phb->regs == NULL) |
910 | pr_err(" Failed to map registers !\n"); | 911 | pr_err(" Failed to map registers !\n"); |
911 | 912 | ||
912 | |||
913 | /* XXX This is hack-a-thon. This needs to be changed so that: | ||
914 | * - we obtain stuff like PE# etc... from device-tree | ||
915 | * - we properly re-allocate M32 ourselves | ||
916 | * (the OFW one isn't very good) | ||
917 | */ | ||
918 | |||
919 | /* Initialize more IODA stuff */ | 913 | /* Initialize more IODA stuff */ |
920 | phb->ioda.total_pe = 128; | 914 | prop32 = of_get_property(np, "ibm,opal-num-pes", NULL); |
915 | if (!prop32) | ||
916 | phb->ioda.total_pe = 1; | ||
917 | else | ||
918 | phb->ioda.total_pe = *prop32; | ||
921 | 919 | ||
922 | phb->ioda.m32_size = resource_size(&hose->mem_resources[0]); | 920 | phb->ioda.m32_size = resource_size(&hose->mem_resources[0]); |
923 | /* OFW Has already off top 64k of M32 space (MSI space) */ | 921 | /* FW Has already off top 64k of M32 space (MSI space) */ |
924 | phb->ioda.m32_size += 0x10000; | 922 | phb->ioda.m32_size += 0x10000; |
925 | 923 | ||
926 | phb->ioda.m32_segsize = phb->ioda.m32_size / phb->ioda.total_pe; | 924 | phb->ioda.m32_segsize = phb->ioda.m32_size / phb->ioda.total_pe; |
@@ -930,7 +928,10 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np) | |||
930 | phb->ioda.io_segsize = phb->ioda.io_size / phb->ioda.total_pe; | 928 | phb->ioda.io_segsize = phb->ioda.io_size / phb->ioda.total_pe; |
931 | phb->ioda.io_pci_base = 0; /* XXX calculate this ? */ | 929 | phb->ioda.io_pci_base = 0; /* XXX calculate this ? */ |
932 | 930 | ||
933 | /* Allocate aux data & arrays */ | 931 | /* Allocate aux data & arrays |
932 | * | ||
933 | * XXX TODO: Don't allocate io segmap on PHB3 | ||
934 | */ | ||
934 | size = _ALIGN_UP(phb->ioda.total_pe / 8, sizeof(unsigned long)); | 935 | size = _ALIGN_UP(phb->ioda.total_pe / 8, sizeof(unsigned long)); |
935 | m32map_off = size; | 936 | m32map_off = size; |
936 | size += phb->ioda.total_pe * sizeof(phb->ioda.m32_segmap[0]); | 937 | size += phb->ioda.total_pe * sizeof(phb->ioda.m32_segmap[0]); |
@@ -960,7 +961,7 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np) | |||
960 | hose->mem_resources[2].start = 0; | 961 | hose->mem_resources[2].start = 0; |
961 | hose->mem_resources[2].end = 0; | 962 | hose->mem_resources[2].end = 0; |
962 | 963 | ||
963 | #if 0 | 964 | #if 0 /* We should really do that ... */ |
964 | rc = opal_pci_set_phb_mem_window(opal->phb_id, | 965 | rc = opal_pci_set_phb_mem_window(opal->phb_id, |
965 | window_type, | 966 | window_type, |
966 | window_num, | 967 | window_num, |
@@ -974,16 +975,6 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np) | |||
974 | phb->ioda.m32_size, phb->ioda.m32_segsize, | 975 | phb->ioda.m32_size, phb->ioda.m32_segsize, |
975 | phb->ioda.io_size, phb->ioda.io_segsize); | 976 | phb->ioda.io_size, phb->ioda.io_segsize); |
976 | 977 | ||
977 | if (phb->regs) { | ||
978 | pr_devel(" BUID = 0x%016llx\n", in_be64(phb->regs + 0x100)); | ||
979 | pr_devel(" PHB2_CR = 0x%016llx\n", in_be64(phb->regs + 0x160)); | ||
980 | pr_devel(" IO_BAR = 0x%016llx\n", in_be64(phb->regs + 0x170)); | ||
981 | pr_devel(" IO_BAMR = 0x%016llx\n", in_be64(phb->regs + 0x178)); | ||
982 | pr_devel(" IO_SAR = 0x%016llx\n", in_be64(phb->regs + 0x180)); | ||
983 | pr_devel(" M32_BAR = 0x%016llx\n", in_be64(phb->regs + 0x190)); | ||
984 | pr_devel(" M32_BAMR = 0x%016llx\n", in_be64(phb->regs + 0x198)); | ||
985 | pr_devel(" M32_SAR = 0x%016llx\n", in_be64(phb->regs + 0x1a0)); | ||
986 | } | ||
987 | phb->hose->ops = &pnv_pci_ops; | 978 | phb->hose->ops = &pnv_pci_ops; |
988 | 979 | ||
989 | /* Setup RID -> PE mapping function */ | 980 | /* Setup RID -> PE mapping function */ |
@@ -1011,7 +1002,18 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np) | |||
1011 | rc = opal_pci_reset(phb_id, OPAL_PCI_IODA_TABLE_RESET, OPAL_ASSERT_RESET); | 1002 | rc = opal_pci_reset(phb_id, OPAL_PCI_IODA_TABLE_RESET, OPAL_ASSERT_RESET); |
1012 | if (rc) | 1003 | if (rc) |
1013 | pr_warning(" OPAL Error %ld performing IODA table reset !\n", rc); | 1004 | pr_warning(" OPAL Error %ld performing IODA table reset !\n", rc); |
1014 | opal_pci_set_pe(phb_id, 0, 0, 7, 1, 1 , OPAL_MAP_PE); | 1005 | |
1006 | /* | ||
1007 | * On IODA1 map everything to PE#0, on IODA2 we assume the IODA reset | ||
1008 | * has cleared the RTT which has the same effect | ||
1009 | */ | ||
1010 | if (ioda_type == PNV_PHB_IODA1) | ||
1011 | opal_pci_set_pe(phb_id, 0, 0, 7, 1, 1 , OPAL_MAP_PE); | ||
1012 | } | ||
1013 | |||
1014 | void pnv_pci_init_ioda2_phb(struct device_node *np) | ||
1015 | { | ||
1016 | pnv_pci_init_ioda_phb(np, PNV_PHB_IODA2); | ||
1015 | } | 1017 | } |
1016 | 1018 | ||
1017 | void __init pnv_pci_init_ioda_hub(struct device_node *np) | 1019 | void __init pnv_pci_init_ioda_hub(struct device_node *np) |
@@ -1034,6 +1036,6 @@ void __init pnv_pci_init_ioda_hub(struct device_node *np) | |||
1034 | for_each_child_of_node(np, phbn) { | 1036 | for_each_child_of_node(np, phbn) { |
1035 | /* Look for IODA1 PHBs */ | 1037 | /* Look for IODA1 PHBs */ |
1036 | if (of_device_is_compatible(phbn, "ibm,ioda-phb")) | 1038 | if (of_device_is_compatible(phbn, "ibm,ioda-phb")) |
1037 | pnv_pci_init_ioda1_phb(phbn); | 1039 | pnv_pci_init_ioda_phb(phbn, PNV_PHB_IODA1); |
1038 | } | 1040 | } |
1039 | } | 1041 | } |
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 42eee93ca9c3..a11b5a60c91e 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c | |||
@@ -492,7 +492,7 @@ static void pnv_pci_dma_dev_setup(struct pci_dev *pdev) | |||
492 | pnv_pci_dma_fallback_setup(hose, pdev); | 492 | pnv_pci_dma_fallback_setup(hose, pdev); |
493 | } | 493 | } |
494 | 494 | ||
495 | /* Fixup wrong class code in p7ioc root complex */ | 495 | /* Fixup wrong class code in p7ioc and p8 root complex */ |
496 | static void pnv_p7ioc_rc_quirk(struct pci_dev *dev) | 496 | static void pnv_p7ioc_rc_quirk(struct pci_dev *dev) |
497 | { | 497 | { |
498 | dev->class = PCI_CLASS_BRIDGE_PCI << 8; | 498 | dev->class = PCI_CLASS_BRIDGE_PCI << 8; |
@@ -558,6 +558,10 @@ void __init pnv_pci_init(void) | |||
558 | if (!found_ioda) | 558 | if (!found_ioda) |
559 | for_each_compatible_node(np, NULL, "ibm,p5ioc2") | 559 | for_each_compatible_node(np, NULL, "ibm,p5ioc2") |
560 | pnv_pci_init_p5ioc2_hub(np); | 560 | pnv_pci_init_p5ioc2_hub(np); |
561 | |||
562 | /* Look for ioda2 built-in PHB3's */ | ||
563 | for_each_compatible_node(np, NULL, "ibm,ioda2-phb") | ||
564 | pnv_pci_init_ioda2_phb(np); | ||
561 | } | 565 | } |
562 | 566 | ||
563 | /* Setup the linkage between OF nodes and PHBs */ | 567 | /* Setup the linkage between OF nodes and PHBs */ |
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 42ddfba79651..f6314d65c4d9 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h | |||
@@ -4,9 +4,9 @@ | |||
4 | struct pci_dn; | 4 | struct pci_dn; |
5 | 5 | ||
6 | enum pnv_phb_type { | 6 | enum pnv_phb_type { |
7 | PNV_PHB_P5IOC2, | 7 | PNV_PHB_P5IOC2 = 0, |
8 | PNV_PHB_IODA1, | 8 | PNV_PHB_IODA1 = 1, |
9 | PNV_PHB_IODA2, | 9 | PNV_PHB_IODA2 = 2, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | /* Precise PHB model for error management */ | 12 | /* Precise PHB model for error management */ |
@@ -14,6 +14,7 @@ enum pnv_phb_model { | |||
14 | PNV_PHB_MODEL_UNKNOWN, | 14 | PNV_PHB_MODEL_UNKNOWN, |
15 | PNV_PHB_MODEL_P5IOC2, | 15 | PNV_PHB_MODEL_P5IOC2, |
16 | PNV_PHB_MODEL_P7IOC, | 16 | PNV_PHB_MODEL_P7IOC, |
17 | PNV_PHB_MODEL_PHB3, | ||
17 | }; | 18 | }; |
18 | 19 | ||
19 | #define PNV_PCI_DIAG_BUF_SIZE 4096 | 20 | #define PNV_PCI_DIAG_BUF_SIZE 4096 |
@@ -148,6 +149,7 @@ extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl, | |||
148 | u64 dma_offset); | 149 | u64 dma_offset); |
149 | extern void pnv_pci_init_p5ioc2_hub(struct device_node *np); | 150 | extern void pnv_pci_init_p5ioc2_hub(struct device_node *np); |
150 | extern void pnv_pci_init_ioda_hub(struct device_node *np); | 151 | extern void pnv_pci_init_ioda_hub(struct device_node *np); |
152 | extern void pnv_pci_init_ioda2_phb(struct device_node *np); | ||
151 | 153 | ||
152 | 154 | ||
153 | #endif /* __POWERNV_PCI_H */ | 155 | #endif /* __POWERNV_PCI_H */ |