powerpc/pci: Support per-aperture memory offset
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 6 May 2013 03:40:40 +0000 (13:40 +1000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 6 May 2013 03:40:40 +0000 (13:40 +1000)
The PCI core supports an offset per aperture nowadays but our arch
code still has a single offset per host bridge representing the
difference betwen CPU memory addresses and PCI MMIO addresses.

This is a problem as new machines and hypervisor versions are
coming out where the 64-bit windows will have a different offset
(basically mapped 1:1) from the 32-bit windows.

This fixes it by using separate offsets. In the long run, we probably
want to get rid of that intermediary struct pci_controller and have
those directly stored into the pci_host_bridge as they are parsed
but this will be a more invasive change.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/pci-bridge.h
arch/powerpc/kernel/pci-common.c
arch/powerpc/kernel/pci_32.c
arch/powerpc/kernel/pci_64.c
arch/powerpc/platforms/embedded6xx/mpc10x.h
arch/powerpc/platforms/powermac/pci.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/wsp/wsp_pci.c
arch/powerpc/sysdev/fsl_pci.c
arch/powerpc/sysdev/ppc4xx_pci.c

index 0694f73..8b11b5b 100644 (file)
@@ -39,11 +39,6 @@ struct pci_controller {
        resource_size_t io_base_phys;
        resource_size_t pci_io_size;
 
-       /* Some machines (PReP) have a non 1:1 mapping of
-        * the PCI memory space in the CPU bus space
-        */
-       resource_size_t pci_mem_offset;
-
        /* Some machines have a special region to forward the ISA
         * "memory" cycles such as VGA memory regions. Left to 0
         * if unsupported
@@ -86,6 +81,7 @@ struct pci_controller {
         */
        struct resource io_resource;
        struct resource mem_resources[3];
+       resource_size_t mem_offset[3];
        int global_number;              /* PCI domain number */
 
        resource_size_t dma_window_base_cur;
index cf00588..f5c5c90 100644 (file)
@@ -786,22 +786,8 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
                                hose->isa_mem_size = size;
                        }
 
-                       /* We get the PCI/Mem offset from the first range or
-                        * the, current one if the offset came from an ISA
-                        * hole. If they don't match, bugger.
-                        */
-                       if (memno == 0 ||
-                           (isa_hole >= 0 && pci_addr != 0 &&
-                            hose->pci_mem_offset == isa_mb))
-                               hose->pci_mem_offset = cpu_addr - pci_addr;
-                       else if (pci_addr != 0 &&
-                                hose->pci_mem_offset != cpu_addr - pci_addr) {
-                               printk(KERN_INFO
-                                      " \\--> Skipped (offset mismatch) !\n");
-                               continue;
-                       }
-
                        /* Build resource */
+                       hose->mem_offset[memno] = cpu_addr - pci_addr;
                        res = &hose->mem_resources[memno++];
                        res->flags = IORESOURCE_MEM;
                        if (pci_space & 0x40000000)
@@ -817,20 +803,6 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
                        res->child = NULL;
                }
        }
-
-       /* If there's an ISA hole and the pci_mem_offset is -not- matching
-        * the ISA hole offset, then we need to remove the ISA hole from
-        * the resource list for that brige
-        */
-       if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
-               unsigned int next = isa_hole + 1;
-               printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb);
-               if (next < memno)
-                       memmove(&hose->mem_resources[isa_hole],
-                               &hose->mem_resources[next],
-                               sizeof(struct resource) * (memno - next));
-               hose->mem_resources[--memno].flags = 0;
-       }
 }
 
 /* Decide whether to display the domain number in /proc */
@@ -916,6 +888,7 @@ static int pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
        struct pci_controller *hose = pci_bus_to_host(bus);
        struct pci_dev *dev = bus->self;
        resource_size_t offset;
+       struct pci_bus_region region;
        u16 command;
        int i;
 
@@ -925,10 +898,10 @@ static int pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
 
        /* Job is a bit different between memory and IO */
        if (res->flags & IORESOURCE_MEM) {
-               /* If the BAR is non-0 (res != pci_mem_offset) then it's probably been
-                * initialized by somebody
-                */
-               if (res->start != hose->pci_mem_offset)
+               pcibios_resource_to_bus(dev, &region, res);
+
+               /* If the BAR is non-0 then it's probably been initialized */
+               if (region.start != 0)
                        return 0;
 
                /* The BAR is 0, let's check if memory decoding is enabled on
@@ -940,11 +913,11 @@ static int pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
 
                /* Memory decoding is enabled and the BAR is 0. If any of the bridge
                 * resources covers that starting address (0 then it's good enough for
-                * us for memory
+                * us for memory space)
                 */
                for (i = 0; i < 3; i++) {
                        if ((hose->mem_resources[i].flags & IORESOURCE_MEM) &&
-                           hose->mem_resources[i].start == hose->pci_mem_offset)
+                           hose->mem_resources[i].start == hose->mem_offset[i])
                                return 0;
                }
 
@@ -1381,10 +1354,9 @@ static void __init pcibios_reserve_legacy_regions(struct pci_bus *bus)
 
  no_io:
        /* Check for memory */
-       offset = hose->pci_mem_offset;
-       pr_debug("hose mem offset: %016llx\n", (unsigned long long)offset);
        for (i = 0; i < 3; i++) {
                pres = &hose->mem_resources[i];
+               offset = hose->mem_offset[i];
                if (!(pres->flags & IORESOURCE_MEM))
                        continue;
                pr_debug("hose mem res: %pR\n", pres);
@@ -1524,6 +1496,7 @@ static void pcibios_setup_phb_resources(struct pci_controller *hose,
                                        struct list_head *resources)
 {
        struct resource *res;
+       resource_size_t offset;
        int i;
 
        /* Hookup PHB IO resource */
@@ -1533,51 +1506,37 @@ static void pcibios_setup_phb_resources(struct pci_controller *hose,
                printk(KERN_WARNING "PCI: I/O resource not set for host"
                       " bridge %s (domain %d)\n",
                       hose->dn->full_name, hose->global_number);
-#ifdef CONFIG_PPC32
-               /* Workaround for lack of IO resource only on 32-bit */
-               res->start = (unsigned long)hose->io_base_virt - isa_io_base;
-               res->end = res->start + IO_SPACE_LIMIT;
-               res->flags = IORESOURCE_IO;
-#endif /* CONFIG_PPC32 */
-       }
-       if (res->flags) {
-               pr_debug("PCI: PHB IO resource    = %016llx-%016llx [%lx]\n",
+       } else {
+               offset = pcibios_io_space_offset(hose);
+
+               pr_debug("PCI: PHB IO resource    = %08llx-%08llx [%lx] off 0x%08llx\n",
                         (unsigned long long)res->start,
                         (unsigned long long)res->end,
-                        (unsigned long)res->flags);
-               pci_add_resource_offset(resources, res, pcibios_io_space_offset(hose));
-
-               pr_debug("PCI: PHB IO  offset     = %08lx\n",
-                        (unsigned long)hose->io_base_virt - _IO_BASE);
+                        (unsigned long)res->flags,
+                        (unsigned long long)offset);
+               pci_add_resource_offset(resources, res, offset);
        }
 
        /* Hookup PHB Memory resources */
        for (i = 0; i < 3; ++i) {
                res = &hose->mem_resources[i];
                if (!res->flags) {
-                       if (i > 0)
-                               continue;
                        printk(KERN_ERR "PCI: Memory resource 0 not set for "
                               "host bridge %s (domain %d)\n",
                               hose->dn->full_name, hose->global_number);
-#ifdef CONFIG_PPC32
-                       /* Workaround for lack of MEM resource only on 32-bit */
-                       res->start = hose->pci_mem_offset;
-                       res->end = (resource_size_t)-1LL;
-                       res->flags = IORESOURCE_MEM;
-#endif /* CONFIG_PPC32 */
-               }
-               if (res->flags) {
-                       pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n", i,
-                                (unsigned long long)res->start,
-                                (unsigned long long)res->end,
-                                (unsigned long)res->flags);
-                       pci_add_resource_offset(resources, res, hose->pci_mem_offset);
+                       continue;
                }
-       }
+               offset = hose->mem_offset[i];
 
-       pr_debug("PCI: PHB MEM offset     = %016llx\n",
-                (unsigned long long)hose->pci_mem_offset);
+
+               pr_debug("PCI: PHB MEM resource %d = %08llx-%08llx [%lx] off 0x%08llx\n", i,
+                        (unsigned long long)res->start,
+                        (unsigned long long)res->end,
+                        (unsigned long)res->flags,
+                        (unsigned long long)offset);
+
+               pci_add_resource_offset(resources, res, offset);
+       }
 }
 
 /*
index e37c215..432459c 100644 (file)
@@ -295,7 +295,7 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
        case IOBASE_BRIDGE_NUMBER:
                return (long)hose->first_busno;
        case IOBASE_MEMORY:
-               return (long)hose->pci_mem_offset;
+               return (long)hose->mem_offset[0];
        case IOBASE_IO:
                return (long)hose->io_base_phys;
        case IOBASE_ISA_IO:
index 51a133a..873050d 100644 (file)
@@ -246,7 +246,7 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
        case IOBASE_BRIDGE_NUMBER:
                return (long)hose->first_busno;
        case IOBASE_MEMORY:
-               return (long)hose->pci_mem_offset;
+               return (long)hose->mem_offset[0];
        case IOBASE_IO:
                return (long)hose->io_base_phys;
        case IOBASE_ISA_IO:
index b30a6a3..b290b63 100644 (file)
 #define        MPC10X_MAPB_PCI_MEM_OFFSET      (MPC10X_MAPB_ISA_MEM_BASE -     \
                                         MPC10X_MAPB_PCI_MEM_START)
 
-/* Set hose members to values appropriate for the mem map used */
-#define        MPC10X_SETUP_HOSE(hose, map) {                                  \
-       (hose)->pci_mem_offset = MPC10X_MAP##map##_PCI_MEM_OFFSET;      \
-       (hose)->io_space.start = MPC10X_MAP##map##_PCI_IO_START;        \
-       (hose)->io_space.end = MPC10X_MAP##map##_PCI_IO_END;            \
-       (hose)->mem_space.start = MPC10X_MAP##map##_PCI_MEM_START;      \
-       (hose)->mem_space.end = MPC10X_MAP##map##_PCI_MEM_END;          \
-       (hose)->io_base_virt = (void *)MPC10X_MAP##map##_ISA_IO_BASE;   \
-}
-
-
 /* Miscellaneous Configuration register offsets */
 #define        MPC10X_CFG_PIR_REG              0x09
 #define        MPC10X_CFG_PIR_HOST_BRIDGE      0x00
index 2b8af75..cf7009b 100644 (file)
@@ -824,6 +824,7 @@ static void __init parse_region_decode(struct pci_controller *hose,
                        hose->mem_resources[cur].name = hose->dn->full_name;
                        hose->mem_resources[cur].start = base;
                        hose->mem_resources[cur].end = end;
+                       hose->mem_offset[cur] = 0;
                        DBG("  %d: 0x%08lx-0x%08lx\n", cur, base, end);
                } else {
                        DBG("   :           -0x%08lx\n", end);
@@ -866,7 +867,6 @@ static void __init setup_u3_ht(struct pci_controller* hose)
        hose->io_resource.start = 0;
        hose->io_resource.end = 0x003fffff;
        hose->io_resource.flags = IORESOURCE_IO;
-       hose->pci_mem_offset = 0;
        hose->first_busno = 0;
        hose->last_busno = 0xef;
 
index 97b08fc..1da578b 100644 (file)
@@ -915,11 +915,14 @@ static void pnv_ioda_setup_pe_seg(struct pci_controller *hose,
                                index++;
                        }
                } else if (res->flags & IORESOURCE_MEM) {
+                       /* WARNING: Assumes M32 is mem region 0 in PHB. We need to
+                        * harden that algorithm when we start supporting M64
+                        */
                        region.start = res->start -
-                                      hose->pci_mem_offset -
+                                      hose->mem_offset[0] -
                                       phb->ioda.m32_pci_base;
                        region.end   = res->end -
-                                      hose->pci_mem_offset -
+                                      hose->mem_offset[0] -
                                       phb->ioda.m32_pci_base;
                        index = region.start / phb->ioda.m32_segsize;
 
@@ -1115,8 +1118,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np, int ioda_type)
        phb->ioda.m32_size += 0x10000;
 
        phb->ioda.m32_segsize = phb->ioda.m32_size / phb->ioda.total_pe;
-       phb->ioda.m32_pci_base = hose->mem_resources[0].start -
-               hose->pci_mem_offset;
+       phb->ioda.m32_pci_base = hose->mem_resources[0].start - hose->mem_offset[0];
        phb->ioda.io_size = hose->pci_io_size;
        phb->ioda.io_segsize = phb->ioda.io_size / phb->ioda.total_pe;
        phb->ioda.io_pci_base = 0; /* XXX calculate this ? */
index 8e22f56..62cb527 100644 (file)
@@ -502,7 +502,7 @@ static void __init wsp_pcie_configure_hw(struct pci_controller *hose)
                 (~(hose->mem_resources[0].end -
                    hose->mem_resources[0].start)) & 0x3ffffff0000ul);
        out_be64(hose->cfg_data + PCIE_REG_M32A_START_ADDR,
-                (hose->mem_resources[0].start - hose->pci_mem_offset) | 1);
+                (hose->mem_resources[0].start - hose->mem_offset[0]) | 1);
 
        /* Clear all TVT entries
         *
index cffe7ed..028ac1f 100644 (file)
@@ -178,7 +178,7 @@ static void setup_pci_atmu(struct pci_controller *hose)
        struct ccsr_pci __iomem *pci = hose->private_data;
        int i, j, n, mem_log, win_idx = 3, start_idx = 1, end_idx = 4;
        u64 mem, sz, paddr_hi = 0;
-       u64 paddr_lo = ULLONG_MAX;
+       u64 offset = 0, paddr_lo = ULLONG_MAX;
        u32 pcicsrbar = 0, pcicsrbar_sz;
        u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL |
                        PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
@@ -208,8 +208,9 @@ static void setup_pci_atmu(struct pci_controller *hose)
                paddr_lo = min(paddr_lo, (u64)hose->mem_resources[i].start);
                paddr_hi = max(paddr_hi, (u64)hose->mem_resources[i].end);
 
-               n = setup_one_atmu(pci, j, &hose->mem_resources[i],
-                                  hose->pci_mem_offset);
+               /* We assume all memory resources have the same offset */
+               offset = hose->mem_offset[i];
+               n = setup_one_atmu(pci, j, &hose->mem_resources[i], offset);
 
                if (n < 0 || j >= 5) {
                        pr_err("Ran out of outbound PCI ATMUs for resource %d!\n", i);
@@ -239,8 +240,8 @@ static void setup_pci_atmu(struct pci_controller *hose)
        }
 
        /* convert to pci address space */
-       paddr_hi -= hose->pci_mem_offset;
-       paddr_lo -= hose->pci_mem_offset;
+       paddr_hi -= offset;
+       paddr_lo -= offset;
 
        if (paddr_hi == paddr_lo) {
                pr_err("%s: No outbound window space\n", name);
index 56e8b3c..64603a1 100644 (file)
@@ -257,6 +257,7 @@ static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose,
        /* Setup outbound memory windows */
        for (i = j = 0; i < 3; i++) {
                struct resource *res = &hose->mem_resources[i];
+               resource_size_t offset = hose->mem_offset[i];
 
                /* we only care about memory windows */
                if (!(res->flags & IORESOURCE_MEM))
@@ -270,7 +271,7 @@ static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose,
                /* Configure the resource */
                if (ppc4xx_setup_one_pci_PMM(hose, reg,
                                             res->start,
-                                            res->start - hose->pci_mem_offset,
+                                            res->start - offset,
                                             resource_size(res),
                                             res->flags,
                                             j) == 0) {
@@ -279,7 +280,7 @@ static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose,
                        /* If the resource PCI address is 0 then we have our
                         * ISA memory hole
                         */
-                       if (res->start == hose->pci_mem_offset)
+                       if (res->start == offset)
                                found_isa_hole = 1;
                }
        }
@@ -457,6 +458,7 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose,
        /* Setup outbound memory windows */
        for (i = j = 0; i < 3; i++) {
                struct resource *res = &hose->mem_resources[i];
+               resource_size_t offset = hose->mem_offset[i];
 
                /* we only care about memory windows */
                if (!(res->flags & IORESOURCE_MEM))
@@ -470,7 +472,7 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose,
                /* Configure the resource */
                if (ppc4xx_setup_one_pcix_POM(hose, reg,
                                              res->start,
-                                             res->start - hose->pci_mem_offset,
+                                             res->start - offset,
                                              resource_size(res),
                                              res->flags,
                                              j) == 0) {
@@ -479,7 +481,7 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose,
                        /* If the resource PCI address is 0 then we have our
                         * ISA memory hole
                         */
-                       if (res->start == hose->pci_mem_offset)
+                       if (res->start == offset)
                                found_isa_hole = 1;
                }
        }
@@ -1792,6 +1794,7 @@ static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port,
        /* Setup outbound memory windows */
        for (i = j = 0; i < 3; i++) {
                struct resource *res = &hose->mem_resources[i];
+               resource_size_t offset = hose->mem_offset[i];
 
                /* we only care about memory windows */
                if (!(res->flags & IORESOURCE_MEM))
@@ -1805,7 +1808,7 @@ static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port,
                /* Configure the resource */
                if (ppc4xx_setup_one_pciex_POM(port, hose, mbase,
                                               res->start,
-                                              res->start - hose->pci_mem_offset,
+                                              res->start - offset,
                                               resource_size(res),
                                               res->flags,
                                               j) == 0) {
@@ -1814,7 +1817,7 @@ static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port,
                        /* If the resource PCI address is 0 then we have our
                         * ISA memory hole
                         */
-                       if (res->start == hose->pci_mem_offset)
+                       if (res->start == offset)
                                found_isa_hole = 1;
                }
        }