powerpc/powernv/pci: Use the device-tree to get available range of M64's
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Fri, 8 Jul 2016 06:37:16 +0000 (16:37 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Sun, 17 Jul 2016 06:42:48 +0000 (16:42 +1000)
M64's are the configurable 64-bit windows that cover the 64-bit MMIO
space. We used to hard code 16 windows. Newer chips might have a
variable number and might need to reserve some as well (for example
on PHB4/POWER9, M32 and M64 are actually unified and we use M64#0
to map the 32-bit space).

So newer OPALs will provide a property we can use to know what range
of windows is available. The property is named so that it can
eventually support multiple ranges but we only use the first one for
now.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/platforms/powernv/pci-ioda.c

index d7502f2265bc4d87da68226c7f0b08261c8743fc..ed27f4cb28cac3822224f1ffff397a76279423c2 100644 (file)
@@ -191,9 +191,6 @@ static int pnv_ioda2_init_m64(struct pnv_phb *phb)
                goto fail;
        }
 
-       /* Mark the M64 BAR assigned */
-       set_bit(phb->ioda.m64_bar_idx, &phb->ioda.m64_bar_alloc);
-
        /*
         * Exclude the segments for reserved and root bus PE, which
         * are first or last two PEs.
@@ -404,6 +401,7 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
        struct pci_controller *hose = phb->hose;
        struct device_node *dn = hose->dn;
        struct resource *res;
+       u32 m64_range[2], i;
        const u32 *r;
        u64 pci_addr;
 
@@ -424,6 +422,30 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
                return;
        }
 
+       /*
+        * Find the available M64 BAR range and pickup the last one for
+        * covering the whole 64-bits space. We support only one range.
+        */
+       if (of_property_read_u32_array(dn, "ibm,opal-available-m64-ranges",
+                                      m64_range, 2)) {
+               /* In absence of the property, assume 0..15 */
+               m64_range[0] = 0;
+               m64_range[1] = 16;
+       }
+       /* We only support 64 bits in our allocator */
+       if (m64_range[1] > 63) {
+               pr_warn("%s: Limiting M64 range to 63 (from %d) on PHB#%x\n",
+                       __func__, m64_range[1], phb->hose->global_number);
+               m64_range[1] = 63;
+       }
+       /* Empty range, no m64 */
+       if (m64_range[1] <= m64_range[0]) {
+               pr_warn("%s: M64 empty, disabling M64 usage on PHB#%x\n",
+                       __func__, phb->hose->global_number);
+               return;
+       }
+
+       /* Configure M64 informations */
        res = &hose->mem_resources[1];
        res->name = dn->full_name;
        res->start = of_translate_address(dn, r + 2);
@@ -436,11 +458,28 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
        phb->ioda.m64_segsize = phb->ioda.m64_size / phb->ioda.total_pe_num;
        phb->ioda.m64_base = pci_addr;
 
-       pr_info(" MEM64 0x%016llx..0x%016llx -> 0x%016llx\n",
-                       res->start, res->end, pci_addr);
+       /* This lines up nicely with the display from processing OF ranges */
+       pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx (M64 #%d..%d)\n",
+               res->start, res->end, pci_addr, m64_range[0],
+               m64_range[0] + m64_range[1] - 1);
+
+       /* Mark all M64 used up by default */
+       phb->ioda.m64_bar_alloc = (unsigned long)-1;
 
        /* Use last M64 BAR to cover M64 window */
-       phb->ioda.m64_bar_idx = 15;
+       m64_range[1]--;
+       phb->ioda.m64_bar_idx = m64_range[0] + m64_range[1];
+
+       pr_info(" Using M64 #%d as default window\n", phb->ioda.m64_bar_idx);
+
+       /* Mark remaining ones free */
+       for (i = m64_range[0]; i < m64_range[1]; i++)
+               clear_bit(i, &phb->ioda.m64_bar_alloc);
+
+       /*
+        * Setup init functions for M64 based on IODA version, IODA3 uses
+        * the IODA2 code.
+        */
        if (phb->type == PNV_PHB_IODA1)
                phb->init_m64 = pnv_ioda1_init_m64;
        else