[PATCH 02/10] PCI, x86: clip firmware assigned resource under parent bridge's

From: Yinghai Lu
Date: Mon Jan 12 2015 - 14:24:21 EST


Some bios put range that is not fully coverred by root bus resources.
Try to clip them and update them in pci bridge bars.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=85491
Reported-by: Marek Kordik <kordikmarek@xxxxxxxxx>
Tested-by: Marek Kordik <kordikmarek@xxxxxxxxx>
Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources")
Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Cc: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: "H. Peter Anvin" <hpa@xxxxxxxxx>
Cc: x86@xxxxxxxxxx
---
arch/x86/pci/i386.c | 74 +++++++++++++++++++++++++++++++++++++----------------
1 file changed, 52 insertions(+), 22 deletions(-)

diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 9b18ef3..d43e1af 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -205,10 +205,11 @@ EXPORT_SYMBOL(pcibios_align_resource);
* as well.
*/

-static void pcibios_allocate_bridge_resources(struct pci_dev *dev)
+static bool pcibios_allocate_bridge_resources(struct pci_dev *dev)
{
int idx;
struct resource *r;
+ bool changed = false;

for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
r = &dev->resource[idx];
@@ -216,17 +217,33 @@ static void pcibios_allocate_bridge_resources(struct pci_dev *dev)
continue;
if (r->parent) /* Already allocated */
continue;
- if (!r->start || pci_claim_resource(dev, idx) < 0) {
- /*
- * Something is wrong with the region.
- * Invalidate the resource to prevent
- * child resource allocations in this
- * range.
- */
- r->start = r->end = 0;
- r->flags = 0;
+
+ if (!r->start)
+ goto clear;
+
+ if (pci_claim_resource(dev, idx) >= 0)
+ continue;
+
+ /* try again after clip for pci bridge*/
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
+ pci_bus_clip_resource(dev, r)) {
+ changed = true;
+ if (pci_claim_resource(dev, idx) >= 0)
+ continue;
}
+
+clear:
+ /*
+ * Something is wrong with the region.
+ * Invalidate the resource to prevent
+ * child resource allocations in this
+ * range.
+ */
+ r->start = r->end = 0;
+ r->flags = 0;
}
+
+ return changed;
}

static void pcibios_allocate_bus_resources(struct pci_bus *bus)
@@ -234,8 +251,12 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
struct pci_bus *child;

/* Depth-First Search on bus tree */
- if (bus->self)
- pcibios_allocate_bridge_resources(bus->self);
+ if (bus->self) {
+ bool changed = pcibios_allocate_bridge_resources(bus->self);
+
+ if (changed)
+ pci_setup_bridge(bus);
+ }
list_for_each_entry(child, &bus->children, node)
pcibios_allocate_bus_resources(child);
}
@@ -274,18 +295,27 @@ static void pcibios_allocate_dev_resources(struct pci_dev *dev, int pass)
dev_dbg(&dev->dev,
"BAR %d: reserving %pr (d=%d, p=%d)\n",
idx, r, disabled, pass);
- if (pci_claim_resource(dev, idx) < 0) {
- if (r->flags & IORESOURCE_PCI_FIXED) {
- dev_info(&dev->dev, "BAR %d %pR is immovable\n",
+
+ if (pci_claim_resource(dev, idx) >= 0)
+ continue;
+
+ if (r->flags & IORESOURCE_PCI_FIXED) {
+ dev_info(&dev->dev, "BAR %d %pR is immovable\n",
idx, r);
- } else {
- /* We'll assign a new address later */
- pcibios_save_fw_addr(dev,
- idx, r->start);
- r->end -= r->start;
- r->start = 0;
- }
+ continue;
+ }
+
+ /* try again with clip */
+ if (pci_bus_clip_resource(dev, r)) {
+ pci_update_resource(dev, idx);
+ if (pci_claim_resource(dev, idx) >= 0)
+ continue;
}
+
+ /* We'll assign a new address later */
+ pcibios_save_fw_addr(dev, idx, r->start);
+ r->end -= r->start;
+ r->start = 0;
}
}
if (!pass) {
--
1.8.4.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/