Commit 5958d19a authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by Michael Ellerman

powerpc/pnv/pci: Fix incorrect PE reservation attempt on some 64-bit BARs

The generic allocation code may sometimes decide to assign a prefetchable
64-bit BAR to the M32 window. In fact it may also decide to allocate
a 64-bit non-prefetchable BAR to the M64 one ! So using the resource
flags as a test to decide which window was used for PE allocation is
just wrong and leads to insane PE numbers.

Instead, compare the addresses to figure it out.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
[mpe: Rename the function as agreed by Ben & Gavin]
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent c74dd88e
...@@ -111,10 +111,17 @@ static int __init iommu_setup(char *str) ...@@ -111,10 +111,17 @@ static int __init iommu_setup(char *str)
} }
early_param("iommu", iommu_setup); early_param("iommu", iommu_setup);
static inline bool pnv_pci_is_mem_pref_64(unsigned long flags) static inline bool pnv_pci_is_m64(struct pnv_phb *phb, struct resource *r)
{ {
return ((flags & (IORESOURCE_MEM_64 | IORESOURCE_PREFETCH)) == /*
(IORESOURCE_MEM_64 | IORESOURCE_PREFETCH)); * WARNING: We cannot rely on the resource flags. The Linux PCI
* allocation code sometimes decides to put a 64-bit prefetchable
* BAR in the 32-bit window, so we have to compare the addresses.
*
* For simplicity we only test resource start.
*/
return (r->start >= phb->ioda.m64_base &&
r->start < (phb->ioda.m64_base + phb->ioda.m64_size));
} }
static struct pnv_ioda_pe *pnv_ioda_init_pe(struct pnv_phb *phb, int pe_no) static struct pnv_ioda_pe *pnv_ioda_init_pe(struct pnv_phb *phb, int pe_no)
...@@ -229,7 +236,7 @@ static void pnv_ioda_reserve_dev_m64_pe(struct pci_dev *pdev, ...@@ -229,7 +236,7 @@ static void pnv_ioda_reserve_dev_m64_pe(struct pci_dev *pdev,
sgsz = phb->ioda.m64_segsize; sgsz = phb->ioda.m64_segsize;
for (i = 0; i <= PCI_ROM_RESOURCE; i++) { for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
r = &pdev->resource[i]; r = &pdev->resource[i];
if (!r->parent || !pnv_pci_is_mem_pref_64(r->flags)) if (!r->parent || !pnv_pci_is_m64(phb, r))
continue; continue;
start = _ALIGN_DOWN(r->start - base, sgsz); start = _ALIGN_DOWN(r->start - base, sgsz);
...@@ -2863,7 +2870,7 @@ static void pnv_pci_ioda_fixup_iov_resources(struct pci_dev *pdev) ...@@ -2863,7 +2870,7 @@ static void pnv_pci_ioda_fixup_iov_resources(struct pci_dev *pdev)
res = &pdev->resource[i + PCI_IOV_RESOURCES]; res = &pdev->resource[i + PCI_IOV_RESOURCES];
if (!res->flags || res->parent) if (!res->flags || res->parent)
continue; continue;
if (!pnv_pci_is_mem_pref_64(res->flags)) { if (!pnv_pci_is_m64(phb, res)) {
dev_warn(&pdev->dev, "Don't support SR-IOV with" dev_warn(&pdev->dev, "Don't support SR-IOV with"
" non M64 VF BAR%d: %pR. \n", " non M64 VF BAR%d: %pR. \n",
i, res); i, res);
...@@ -2958,7 +2965,7 @@ static void pnv_ioda_setup_pe_res(struct pnv_ioda_pe *pe, ...@@ -2958,7 +2965,7 @@ static void pnv_ioda_setup_pe_res(struct pnv_ioda_pe *pe,
index++; index++;
} }
} else if ((res->flags & IORESOURCE_MEM) && } else if ((res->flags & IORESOURCE_MEM) &&
!pnv_pci_is_mem_pref_64(res->flags)) { !pnv_pci_is_m64(phb, res)) {
region.start = res->start - region.start = res->start -
phb->hose->mem_offset[0] - phb->hose->mem_offset[0] -
phb->ioda.m32_pci_base; phb->ioda.m32_pci_base;
...@@ -3083,9 +3090,12 @@ static resource_size_t pnv_pci_window_alignment(struct pci_bus *bus, ...@@ -3083,9 +3090,12 @@ static resource_size_t pnv_pci_window_alignment(struct pci_bus *bus,
bridge = bridge->bus->self; bridge = bridge->bus->self;
} }
/* We fail back to M32 if M64 isn't supported */ /*
if (phb->ioda.m64_segsize && * We fall back to M32 if M64 isn't supported. We enforce the M64
pnv_pci_is_mem_pref_64(type)) * alignment for any 64-bit resource, PCIe doesn't care and
* bridges only do 64-bit prefetchable anyway.
*/
if (phb->ioda.m64_segsize && (type & IORESOURCE_MEM_64))
return phb->ioda.m64_segsize; return phb->ioda.m64_segsize;
if (type & IORESOURCE_MEM) if (type & IORESOURCE_MEM)
return phb->ioda.m32_segsize; return phb->ioda.m32_segsize;
...@@ -3125,7 +3135,7 @@ static void pnv_pci_fixup_bridge_resources(struct pci_bus *bus, ...@@ -3125,7 +3135,7 @@ static void pnv_pci_fixup_bridge_resources(struct pci_bus *bus,
w = NULL; w = NULL;
if (r->flags & type & IORESOURCE_IO) if (r->flags & type & IORESOURCE_IO)
w = &hose->io_resource; w = &hose->io_resource;
else if (pnv_pci_is_mem_pref_64(r->flags) && else if (pnv_pci_is_m64(phb, r) &&
(type & IORESOURCE_PREFETCH) && (type & IORESOURCE_PREFETCH) &&
phb->ioda.m64_segsize) phb->ioda.m64_segsize)
w = &hose->mem_resources[1]; w = &hose->mem_resources[1];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment