powerpc/powernv: Extend PCI bridge resources

The PCI slots are associated with root port or downstream ports
of the PCIe switch connected to root port. When adapter is hot
added to the PCI slot, it usually requests more IO or memory
resource from the directly connected parent bridge (port) and
update the bridge's windows accordingly. The resource windows
of upstream bridges can't be updated automatically. It possibly
leads to unbalanced resource across the bridges: The window of
downstream bridge is overruning that of upstream bridge. The
IO or MMIO path won't work.

This resolves the above issue by extending bridge windows of
root port and upstream port of the PCIe switch connected to
the root port to PHB's windows.

The windows of root port and bridge behind that are extended to
the PHB's windows to accomodate the PCI hotplug happening in
future. The PHB's 64KB 32-bits MSI region is included in bridge's
M32 windows (in hardware) though it's excluded in the corresponding
resource, as the bridge's M32 windows have 1MB as their minimal
alignment. We observed EEH error during system boot when the MSI
region is included in bridge's M32 window.

This excludes top 1MB (including 64KB 32-bits MSI region) region
from bridge's M32 windows when extending them.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
Gavin Shan 2016-05-20 16:41:33 +10:00 committed by Michael Ellerman
parent 63803c39c8
commit 40e2a47e62
1 changed files with 61 additions and 0 deletions

View File

@ -3223,6 +3223,64 @@ static resource_size_t pnv_pci_window_alignment(struct pci_bus *bus,
return phb->ioda.io_segsize;
}
/*
* We are updating root port or the upstream port of the
* bridge behind the root port with PHB's windows in order
* to accommodate the changes on required resources during
* PCI (slot) hotplug, which is connected to either root
* port or the downstream ports of PCIe switch behind the
* root port.
*/
static void pnv_pci_fixup_bridge_resources(struct pci_bus *bus,
unsigned long type)
{
struct pci_controller *hose = pci_bus_to_host(bus);
struct pnv_phb *phb = hose->private_data;
struct pci_dev *bridge = bus->self;
struct resource *r, *w;
bool msi_region = false;
int i;
/* Check if we need apply fixup to the bridge's windows */
if (!pci_is_root_bus(bridge->bus) &&
!pci_is_root_bus(bridge->bus->self->bus))
return;
/* Fixup the resources */
for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
r = &bridge->resource[PCI_BRIDGE_RESOURCES + i];
if (!r->flags || !r->parent)
continue;
w = NULL;
if (r->flags & type & IORESOURCE_IO)
w = &hose->io_resource;
else if (pnv_pci_is_mem_pref_64(r->flags) &&
(type & IORESOURCE_PREFETCH) &&
phb->ioda.m64_segsize)
w = &hose->mem_resources[1];
else if (r->flags & type & IORESOURCE_MEM) {
w = &hose->mem_resources[0];
msi_region = true;
}
r->start = w->start;
r->end = w->end;
/* The 64KB 32-bits MSI region shouldn't be included in
* the 32-bits bridge window. Otherwise, we can see strange
* issues. One of them is EEH error observed on Garrison.
*
* Exclude top 1MB region which is the minimal alignment of
* 32-bits bridge window.
*/
if (msi_region) {
r->end += 0x10000;
r->end -= 0x100000;
}
}
}
static void pnv_pci_setup_bridge(struct pci_bus *bus, unsigned long type)
{
struct pci_controller *hose = pci_bus_to_host(bus);
@ -3231,6 +3289,9 @@ static void pnv_pci_setup_bridge(struct pci_bus *bus, unsigned long type)
struct pnv_ioda_pe *pe;
bool all = (pci_pcie_type(bridge) == PCI_EXP_TYPE_PCI_BRIDGE);
/* Extend bridge's windows if necessary */
pnv_pci_fixup_bridge_resources(bus, type);
/* The PE for root bus should be realized before any one else */
if (!phb->ioda.root_pe_populated) {
pe = pnv_ioda_setup_bus_PE(phb->hose->bus, false);