|
@@ -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);
|