On Fri, Dec 19, 2014 at 5:33 PM, Yinghai Lu <yinghai@xxxxxxxxxx> wrote: > On Fri, Dec 19, 2014 at 4:56 PM, Bjorn Helgaas <bhelgaas@xxxxxxxxxx> wrote: >> >> Marek's case is a little easier because his system is using _CRS. We >> should be able to notice that the Root Port window overlaps the host >> bridge window, but isn't contained by it. In that case, if we merely >> trim the Root Port window so it fits, everything will just work. > > Ok, will check that Monday. Please check attached patch that clip bridge resource. Marek, can you give it a try on top of v3.18? Thanks Yinghai
Subject: [RFC PATCH] PCI, x86: clip firmware assigned pci bridges under hostbridge 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> Fixes: 5b28541552ef ("PCI: Restrict 64-bit prefetchable bridge windows to 64-bit resources") Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx> --- arch/x86/pci/i386.c | 43 +++++++++++++++++++++++++++++++------------ drivers/pci/host-bridge.c | 31 +++++++++++++++++++++++++++++++ include/linux/pci.h | 2 ++ 3 files changed, 64 insertions(+), 12 deletions(-) Index: linux-2.6/arch/x86/pci/i386.c =================================================================== --- linux-2.6.orig/arch/x86/pci/i386.c +++ linux-2.6/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,31 @@ static void pcibios_allocate_bridge_reso 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) { + /* try again after clip for pci bridge*/ + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && + pcibios_resource_clip_in_host_bridge(dev->bus, r)) { + changed = true; + if (pci_claim_resource(dev, idx) >= 0) + continue; + } + goto clear; } + 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 +249,12 @@ static void pcibios_allocate_bus_resourc 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); } Index: linux-2.6/drivers/pci/host-bridge.c =================================================================== --- linux-2.6.orig/drivers/pci/host-bridge.c +++ linux-2.6/drivers/pci/host-bridge.c @@ -31,6 +31,37 @@ void pci_set_host_bridge_release(struct bridge->release_data = release_data; } +bool pcibios_resource_clip_in_host_bridge(struct pci_bus *bus, + struct resource *res) +{ + struct pci_host_bridge *bridge = find_pci_host_bridge(bus); + struct pci_host_bridge_window *window; + resource_size_t start, end; + + list_for_each_entry(window, &bridge->windows, list) { + if (resource_type(res) != resource_type(window->res)) + continue; + + start = max(window->res->start, res->start); + end = min(window->res->end, res->end); + + /* no overlap ? */ + if (start > end) + continue; + + if (res->start == start && res->end == end) + return false; + + /* changed */ + res->start = start; + res->end = end; + + return true; + } + + return false; +} + void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region, struct resource *res) { Index: linux-2.6/include/linux/pci.h =================================================================== --- linux-2.6.orig/include/linux/pci.h +++ linux-2.6/include/linux/pci.h @@ -762,6 +762,8 @@ void pci_fixup_cardbus(struct pci_bus *) /* Generic PCI functions used internally */ +bool pcibios_resource_clip_in_host_bridge(struct pci_bus *bus, + struct resource *res); void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region, struct resource *res); void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,