powerpc/pci: Support per-aperture memory offset

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>
This commit is contained in:
Benjamin Herrenschmidt 2013-05-06 13:40:40 +10:00
parent 342d6666f7
commit 3fd47f063b
10 changed files with 54 additions and 104 deletions

View File

@ -39,11 +39,6 @@ struct pci_controller {
resource_size_t io_base_phys; resource_size_t io_base_phys;
resource_size_t pci_io_size; 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 /* Some machines have a special region to forward the ISA
* "memory" cycles such as VGA memory regions. Left to 0 * "memory" cycles such as VGA memory regions. Left to 0
* if unsupported * if unsupported
@ -86,6 +81,7 @@ struct pci_controller {
*/ */
struct resource io_resource; struct resource io_resource;
struct resource mem_resources[3]; struct resource mem_resources[3];
resource_size_t mem_offset[3];
int global_number; /* PCI domain number */ int global_number; /* PCI domain number */
resource_size_t dma_window_base_cur; resource_size_t dma_window_base_cur;

View File

@ -786,22 +786,8 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
hose->isa_mem_size = size; 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 */ /* Build resource */
hose->mem_offset[memno] = cpu_addr - pci_addr;
res = &hose->mem_resources[memno++]; res = &hose->mem_resources[memno++];
res->flags = IORESOURCE_MEM; res->flags = IORESOURCE_MEM;
if (pci_space & 0x40000000) if (pci_space & 0x40000000)
@ -817,20 +803,6 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
res->child = NULL; 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 */ /* 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_controller *hose = pci_bus_to_host(bus);
struct pci_dev *dev = bus->self; struct pci_dev *dev = bus->self;
resource_size_t offset; resource_size_t offset;
struct pci_bus_region region;
u16 command; u16 command;
int i; 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 */ /* Job is a bit different between memory and IO */
if (res->flags & IORESOURCE_MEM) { if (res->flags & IORESOURCE_MEM) {
/* If the BAR is non-0 (res != pci_mem_offset) then it's probably been pcibios_resource_to_bus(dev, &region, res);
* initialized by somebody
*/ /* If the BAR is non-0 then it's probably been initialized */
if (res->start != hose->pci_mem_offset) if (region.start != 0)
return 0; return 0;
/* The BAR is 0, let's check if memory decoding is enabled on /* 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 /* 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 * 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++) { for (i = 0; i < 3; i++) {
if ((hose->mem_resources[i].flags & IORESOURCE_MEM) && 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; return 0;
} }
@ -1381,10 +1354,9 @@ static void __init pcibios_reserve_legacy_regions(struct pci_bus *bus)
no_io: no_io:
/* Check for memory */ /* 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++) { for (i = 0; i < 3; i++) {
pres = &hose->mem_resources[i]; pres = &hose->mem_resources[i];
offset = hose->mem_offset[i];
if (!(pres->flags & IORESOURCE_MEM)) if (!(pres->flags & IORESOURCE_MEM))
continue; continue;
pr_debug("hose mem res: %pR\n", pres); 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 list_head *resources)
{ {
struct resource *res; struct resource *res;
resource_size_t offset;
int i; int i;
/* Hookup PHB IO resource */ /* 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" printk(KERN_WARNING "PCI: I/O resource not set for host"
" bridge %s (domain %d)\n", " bridge %s (domain %d)\n",
hose->dn->full_name, hose->global_number); hose->dn->full_name, hose->global_number);
#ifdef CONFIG_PPC32 } else {
/* Workaround for lack of IO resource only on 32-bit */ offset = pcibios_io_space_offset(hose);
res->start = (unsigned long)hose->io_base_virt - isa_io_base;
res->end = res->start + IO_SPACE_LIMIT; pr_debug("PCI: PHB IO resource = %08llx-%08llx [%lx] off 0x%08llx\n",
res->flags = IORESOURCE_IO;
#endif /* CONFIG_PPC32 */
}
if (res->flags) {
pr_debug("PCI: PHB IO resource = %016llx-%016llx [%lx]\n",
(unsigned long long)res->start, (unsigned long long)res->start,
(unsigned long long)res->end, (unsigned long long)res->end,
(unsigned long)res->flags); (unsigned long)res->flags,
pci_add_resource_offset(resources, res, pcibios_io_space_offset(hose)); (unsigned long long)offset);
pci_add_resource_offset(resources, res, offset);
pr_debug("PCI: PHB IO offset = %08lx\n",
(unsigned long)hose->io_base_virt - _IO_BASE);
} }
/* Hookup PHB Memory resources */ /* Hookup PHB Memory resources */
for (i = 0; i < 3; ++i) { for (i = 0; i < 3; ++i) {
res = &hose->mem_resources[i]; res = &hose->mem_resources[i];
if (!res->flags) { if (!res->flags) {
if (i > 0)
continue;
printk(KERN_ERR "PCI: Memory resource 0 not set for " printk(KERN_ERR "PCI: Memory resource 0 not set for "
"host bridge %s (domain %d)\n", "host bridge %s (domain %d)\n",
hose->dn->full_name, hose->global_number); hose->dn->full_name, hose->global_number);
#ifdef CONFIG_PPC32 continue;
/* 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) { offset = hose->mem_offset[i];
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);
}
}
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);
}
} }
/* /*

View File

@ -295,7 +295,7 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
case IOBASE_BRIDGE_NUMBER: case IOBASE_BRIDGE_NUMBER:
return (long)hose->first_busno; return (long)hose->first_busno;
case IOBASE_MEMORY: case IOBASE_MEMORY:
return (long)hose->pci_mem_offset; return (long)hose->mem_offset[0];
case IOBASE_IO: case IOBASE_IO:
return (long)hose->io_base_phys; return (long)hose->io_base_phys;
case IOBASE_ISA_IO: case IOBASE_ISA_IO:

View File

@ -246,7 +246,7 @@ long sys_pciconfig_iobase(long which, unsigned long in_bus,
case IOBASE_BRIDGE_NUMBER: case IOBASE_BRIDGE_NUMBER:
return (long)hose->first_busno; return (long)hose->first_busno;
case IOBASE_MEMORY: case IOBASE_MEMORY:
return (long)hose->pci_mem_offset; return (long)hose->mem_offset[0];
case IOBASE_IO: case IOBASE_IO:
return (long)hose->io_base_phys; return (long)hose->io_base_phys;
case IOBASE_ISA_IO: case IOBASE_ISA_IO:

View File

@ -81,17 +81,6 @@
#define MPC10X_MAPB_PCI_MEM_OFFSET (MPC10X_MAPB_ISA_MEM_BASE - \ #define MPC10X_MAPB_PCI_MEM_OFFSET (MPC10X_MAPB_ISA_MEM_BASE - \
MPC10X_MAPB_PCI_MEM_START) 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 */ /* Miscellaneous Configuration register offsets */
#define MPC10X_CFG_PIR_REG 0x09 #define MPC10X_CFG_PIR_REG 0x09
#define MPC10X_CFG_PIR_HOST_BRIDGE 0x00 #define MPC10X_CFG_PIR_HOST_BRIDGE 0x00

View 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].name = hose->dn->full_name;
hose->mem_resources[cur].start = base; hose->mem_resources[cur].start = base;
hose->mem_resources[cur].end = end; hose->mem_resources[cur].end = end;
hose->mem_offset[cur] = 0;
DBG(" %d: 0x%08lx-0x%08lx\n", cur, base, end); DBG(" %d: 0x%08lx-0x%08lx\n", cur, base, end);
} else { } else {
DBG(" : -0x%08lx\n", end); 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.start = 0;
hose->io_resource.end = 0x003fffff; hose->io_resource.end = 0x003fffff;
hose->io_resource.flags = IORESOURCE_IO; hose->io_resource.flags = IORESOURCE_IO;
hose->pci_mem_offset = 0;
hose->first_busno = 0; hose->first_busno = 0;
hose->last_busno = 0xef; hose->last_busno = 0xef;

View File

@ -915,11 +915,14 @@ static void pnv_ioda_setup_pe_seg(struct pci_controller *hose,
index++; index++;
} }
} else if (res->flags & IORESOURCE_MEM) { } 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 - region.start = res->start -
hose->pci_mem_offset - hose->mem_offset[0] -
phb->ioda.m32_pci_base; phb->ioda.m32_pci_base;
region.end = res->end - region.end = res->end -
hose->pci_mem_offset - hose->mem_offset[0] -
phb->ioda.m32_pci_base; phb->ioda.m32_pci_base;
index = region.start / phb->ioda.m32_segsize; 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_size += 0x10000;
phb->ioda.m32_segsize = phb->ioda.m32_size / phb->ioda.total_pe; phb->ioda.m32_segsize = phb->ioda.m32_size / phb->ioda.total_pe;
phb->ioda.m32_pci_base = hose->mem_resources[0].start - phb->ioda.m32_pci_base = hose->mem_resources[0].start - hose->mem_offset[0];
hose->pci_mem_offset;
phb->ioda.io_size = hose->pci_io_size; phb->ioda.io_size = hose->pci_io_size;
phb->ioda.io_segsize = phb->ioda.io_size / phb->ioda.total_pe; phb->ioda.io_segsize = phb->ioda.io_size / phb->ioda.total_pe;
phb->ioda.io_pci_base = 0; /* XXX calculate this ? */ phb->ioda.io_pci_base = 0; /* XXX calculate this ? */

View 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].end -
hose->mem_resources[0].start)) & 0x3ffffff0000ul); hose->mem_resources[0].start)) & 0x3ffffff0000ul);
out_be64(hose->cfg_data + PCIE_REG_M32A_START_ADDR, 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 /* Clear all TVT entries
* *

View File

@ -178,7 +178,7 @@ static void setup_pci_atmu(struct pci_controller *hose)
struct ccsr_pci __iomem *pci = hose->private_data; struct ccsr_pci __iomem *pci = hose->private_data;
int i, j, n, mem_log, win_idx = 3, start_idx = 1, end_idx = 4; int i, j, n, mem_log, win_idx = 3, start_idx = 1, end_idx = 4;
u64 mem, sz, paddr_hi = 0; u64 mem, sz, paddr_hi = 0;
u64 paddr_lo = ULLONG_MAX; u64 offset = 0, paddr_lo = ULLONG_MAX;
u32 pcicsrbar = 0, pcicsrbar_sz; u32 pcicsrbar = 0, pcicsrbar_sz;
u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL | u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL |
PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP; 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_lo = min(paddr_lo, (u64)hose->mem_resources[i].start);
paddr_hi = max(paddr_hi, (u64)hose->mem_resources[i].end); paddr_hi = max(paddr_hi, (u64)hose->mem_resources[i].end);
n = setup_one_atmu(pci, j, &hose->mem_resources[i], /* We assume all memory resources have the same offset */
hose->pci_mem_offset); offset = hose->mem_offset[i];
n = setup_one_atmu(pci, j, &hose->mem_resources[i], offset);
if (n < 0 || j >= 5) { if (n < 0 || j >= 5) {
pr_err("Ran out of outbound PCI ATMUs for resource %d!\n", i); 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 */ /* convert to pci address space */
paddr_hi -= hose->pci_mem_offset; paddr_hi -= offset;
paddr_lo -= hose->pci_mem_offset; paddr_lo -= offset;
if (paddr_hi == paddr_lo) { if (paddr_hi == paddr_lo) {
pr_err("%s: No outbound window space\n", name); pr_err("%s: No outbound window space\n", name);

View File

@ -257,6 +257,7 @@ static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose,
/* Setup outbound memory windows */ /* Setup outbound memory windows */
for (i = j = 0; i < 3; i++) { for (i = j = 0; i < 3; i++) {
struct resource *res = &hose->mem_resources[i]; struct resource *res = &hose->mem_resources[i];
resource_size_t offset = hose->mem_offset[i];
/* we only care about memory windows */ /* we only care about memory windows */
if (!(res->flags & IORESOURCE_MEM)) if (!(res->flags & IORESOURCE_MEM))
@ -270,7 +271,7 @@ static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose,
/* Configure the resource */ /* Configure the resource */
if (ppc4xx_setup_one_pci_PMM(hose, reg, if (ppc4xx_setup_one_pci_PMM(hose, reg,
res->start, res->start,
res->start - hose->pci_mem_offset, res->start - offset,
resource_size(res), resource_size(res),
res->flags, res->flags,
j) == 0) { 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 /* If the resource PCI address is 0 then we have our
* ISA memory hole * ISA memory hole
*/ */
if (res->start == hose->pci_mem_offset) if (res->start == offset)
found_isa_hole = 1; found_isa_hole = 1;
} }
} }
@ -457,6 +458,7 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose,
/* Setup outbound memory windows */ /* Setup outbound memory windows */
for (i = j = 0; i < 3; i++) { for (i = j = 0; i < 3; i++) {
struct resource *res = &hose->mem_resources[i]; struct resource *res = &hose->mem_resources[i];
resource_size_t offset = hose->mem_offset[i];
/* we only care about memory windows */ /* we only care about memory windows */
if (!(res->flags & IORESOURCE_MEM)) if (!(res->flags & IORESOURCE_MEM))
@ -470,7 +472,7 @@ static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose,
/* Configure the resource */ /* Configure the resource */
if (ppc4xx_setup_one_pcix_POM(hose, reg, if (ppc4xx_setup_one_pcix_POM(hose, reg,
res->start, res->start,
res->start - hose->pci_mem_offset, res->start - offset,
resource_size(res), resource_size(res),
res->flags, res->flags,
j) == 0) { 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 /* If the resource PCI address is 0 then we have our
* ISA memory hole * ISA memory hole
*/ */
if (res->start == hose->pci_mem_offset) if (res->start == offset)
found_isa_hole = 1; found_isa_hole = 1;
} }
} }
@ -1792,6 +1794,7 @@ static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port,
/* Setup outbound memory windows */ /* Setup outbound memory windows */
for (i = j = 0; i < 3; i++) { for (i = j = 0; i < 3; i++) {
struct resource *res = &hose->mem_resources[i]; struct resource *res = &hose->mem_resources[i];
resource_size_t offset = hose->mem_offset[i];
/* we only care about memory windows */ /* we only care about memory windows */
if (!(res->flags & IORESOURCE_MEM)) if (!(res->flags & IORESOURCE_MEM))
@ -1805,7 +1808,7 @@ static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port,
/* Configure the resource */ /* Configure the resource */
if (ppc4xx_setup_one_pciex_POM(port, hose, mbase, if (ppc4xx_setup_one_pciex_POM(port, hose, mbase,
res->start, res->start,
res->start - hose->pci_mem_offset, res->start - offset,
resource_size(res), resource_size(res),
res->flags, res->flags,
j) == 0) { 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 /* If the resource PCI address is 0 then we have our
* ISA memory hole * ISA memory hole
*/ */
if (res->start == hose->pci_mem_offset) if (res->start == offset)
found_isa_hole = 1; found_isa_hole = 1;
} }
} }