powerpc/powernv: Supports PHB3
authorGavin Shan <shangw@linux.vnet.ibm.com>
Thu, 25 Apr 2013 19:20:57 +0000 (19:20 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 26 Apr 2013 06:08:27 +0000 (16:08 +1000)
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>
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/powernv/pci.h

index a5c5f15242baeb48357605339e71ee96c97c5a6e..3d4e9588a6955e1bbd49acf1664dbdc847b86c12 100644 (file)
@@ -852,18 +852,19 @@ static u32 pnv_ioda_bdfn_to_pe(struct pnv_phb *phb, struct pci_bus *bus,
        return phb->ioda.pe_rmap[(bus->number << 8) | devfn];
 }
 
-void __init pnv_pci_init_ioda1_phb(struct device_node *np)
+void __init pnv_pci_init_ioda_phb(struct device_node *np, int ioda_type)
 {
        struct pci_controller *hose;
        static int primary = 1;
        struct pnv_phb *phb;
        unsigned long size, m32map_off, iomap_off, pemap_off;
        const u64 *prop64;
+       const u32 *prop32;
        u64 phb_id;
        void *aux;
        long rc;
 
-       pr_info(" Initializing IODA OPAL PHB %s\n", np->full_name);
+       pr_info(" Initializing IODA%d OPAL PHB %s\n", ioda_type, np->full_name);
 
        prop64 = of_get_property(np, "ibm,opal-phbid", NULL);
        if (!prop64) {
@@ -890,37 +891,34 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np)
        hose->last_busno = 0xff;
        hose->private_data = phb;
        phb->opal_id = phb_id;
-       phb->type = PNV_PHB_IODA1;
+       phb->type = ioda_type;
 
        /* Detect specific models for error handling */
        if (of_device_is_compatible(np, "ibm,p7ioc-pciex"))
                phb->model = PNV_PHB_MODEL_P7IOC;
+       else if (of_device_is_compatible(np, "ibm,p8-pciex"))
+               phb->model = PNV_PHB_MODEL_PHB3;
        else
                phb->model = PNV_PHB_MODEL_UNKNOWN;
 
-       /* We parse "ranges" now since we need to deduce the register base
-        * from the IO base
-        */
+       /* Parse 32-bit and IO ranges (if any) */
        pci_process_bridge_OF_ranges(phb->hose, np, primary);
        primary = 0;
 
-       /* Magic formula from Milton */
+       /* Get registers */
        phb->regs = of_iomap(np, 0);
        if (phb->regs == NULL)
                pr_err("  Failed to map registers !\n");
 
-
-       /* XXX This is hack-a-thon. This needs to be changed so that:
-        *  - we obtain stuff like PE# etc... from device-tree
-        *  - we properly re-allocate M32 ourselves
-        *    (the OFW one isn't very good)
-        */
-
        /* Initialize more IODA stuff */
-       phb->ioda.total_pe = 128;
+       prop32 = of_get_property(np, "ibm,opal-num-pes", NULL);
+       if (!prop32)
+               phb->ioda.total_pe = 1;
+       else
+               phb->ioda.total_pe = *prop32;
 
        phb->ioda.m32_size = resource_size(&hose->mem_resources[0]);
-       /* OFW Has already off top 64k of M32 space (MSI space) */
+       /* FW Has already off top 64k of M32 space (MSI space) */
        phb->ioda.m32_size += 0x10000;
 
        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)
        phb->ioda.io_segsize = phb->ioda.io_size / phb->ioda.total_pe;
        phb->ioda.io_pci_base = 0; /* XXX calculate this ? */
 
-       /* Allocate aux data & arrays */
+       /* Allocate aux data & arrays
+        *
+        * XXX TODO: Don't allocate io segmap on PHB3
+        */
        size = _ALIGN_UP(phb->ioda.total_pe / 8, sizeof(unsigned long));
        m32map_off = size;
        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)
        hose->mem_resources[2].start = 0;
        hose->mem_resources[2].end = 0;
 
-#if 0
+#if 0 /* We should really do that ... */
        rc = opal_pci_set_phb_mem_window(opal->phb_id,
                                         window_type,
                                         window_num,
@@ -974,16 +975,6 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np)
                phb->ioda.m32_size, phb->ioda.m32_segsize,
                phb->ioda.io_size, phb->ioda.io_segsize);
 
-       if (phb->regs)  {
-               pr_devel(" BUID     = 0x%016llx\n", in_be64(phb->regs + 0x100));
-               pr_devel(" PHB2_CR  = 0x%016llx\n", in_be64(phb->regs + 0x160));
-               pr_devel(" IO_BAR   = 0x%016llx\n", in_be64(phb->regs + 0x170));
-               pr_devel(" IO_BAMR  = 0x%016llx\n", in_be64(phb->regs + 0x178));
-               pr_devel(" IO_SAR   = 0x%016llx\n", in_be64(phb->regs + 0x180));
-               pr_devel(" M32_BAR  = 0x%016llx\n", in_be64(phb->regs + 0x190));
-               pr_devel(" M32_BAMR = 0x%016llx\n", in_be64(phb->regs + 0x198));
-               pr_devel(" M32_SAR  = 0x%016llx\n", in_be64(phb->regs + 0x1a0));
-       }
        phb->hose->ops = &pnv_pci_ops;
 
        /* Setup RID -> PE mapping function */
@@ -1011,7 +1002,18 @@ void __init pnv_pci_init_ioda1_phb(struct device_node *np)
        rc = opal_pci_reset(phb_id, OPAL_PCI_IODA_TABLE_RESET, OPAL_ASSERT_RESET);
        if (rc)
                pr_warning("  OPAL Error %ld performing IODA table reset !\n", rc);
-       opal_pci_set_pe(phb_id, 0, 0, 7, 1, 1 , OPAL_MAP_PE);
+
+       /*
+        * On IODA1 map everything to PE#0, on IODA2 we assume the IODA reset
+        * has cleared the RTT which has the same effect
+        */
+       if (ioda_type == PNV_PHB_IODA1)
+               opal_pci_set_pe(phb_id, 0, 0, 7, 1, 1 , OPAL_MAP_PE);
+}
+
+void pnv_pci_init_ioda2_phb(struct device_node *np)
+{
+       pnv_pci_init_ioda_phb(np, PNV_PHB_IODA2);
 }
 
 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)
        for_each_child_of_node(np, phbn) {
                /* Look for IODA1 PHBs */
                if (of_device_is_compatible(phbn, "ibm,ioda-phb"))
-                       pnv_pci_init_ioda1_phb(phbn);
+                       pnv_pci_init_ioda_phb(phbn, PNV_PHB_IODA1);
        }
 }
index 42eee93ca9c38bff7a068a2fa473b32ca54c6b3a..a11b5a60c91eb6b9a2851bd2ec4e39bb1a690459 100644 (file)
@@ -492,7 +492,7 @@ static void pnv_pci_dma_dev_setup(struct pci_dev *pdev)
                pnv_pci_dma_fallback_setup(hose, pdev);
 }
 
-/* Fixup wrong class code in p7ioc root complex */
+/* Fixup wrong class code in p7ioc and p8 root complex */
 static void pnv_p7ioc_rc_quirk(struct pci_dev *dev)
 {
        dev->class = PCI_CLASS_BRIDGE_PCI << 8;
@@ -558,6 +558,10 @@ void __init pnv_pci_init(void)
                if (!found_ioda)
                        for_each_compatible_node(np, NULL, "ibm,p5ioc2")
                                pnv_pci_init_p5ioc2_hub(np);
+
+               /* Look for ioda2 built-in PHB3's */
+               for_each_compatible_node(np, NULL, "ibm,ioda2-phb")
+                       pnv_pci_init_ioda2_phb(np);
        }
 
        /* Setup the linkage between OF nodes and PHBs */
index 42ddfba796514a7eb7547ee3d9ffcb469054f450..f6314d65c4d98ec23ee132e0dc0713f5cf8e75f9 100644 (file)
@@ -4,9 +4,9 @@
 struct pci_dn;
 
 enum pnv_phb_type {
-       PNV_PHB_P5IOC2,
-       PNV_PHB_IODA1,
-       PNV_PHB_IODA2,
+       PNV_PHB_P5IOC2  = 0,
+       PNV_PHB_IODA1   = 1,
+       PNV_PHB_IODA2   = 2,
 };
 
 /* Precise PHB model for error management */
@@ -14,6 +14,7 @@ enum pnv_phb_model {
        PNV_PHB_MODEL_UNKNOWN,
        PNV_PHB_MODEL_P5IOC2,
        PNV_PHB_MODEL_P7IOC,
+       PNV_PHB_MODEL_PHB3,
 };
 
 #define PNV_PCI_DIAG_BUF_SIZE  4096
@@ -148,6 +149,7 @@ extern void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
                                      u64 dma_offset);
 extern void pnv_pci_init_p5ioc2_hub(struct device_node *np);
 extern void pnv_pci_init_ioda_hub(struct device_node *np);
+extern void pnv_pci_init_ioda2_phb(struct device_node *np);
 
 
 #endif /* __POWERNV_PCI_H */