We should not release bridge resource if there is fixed resources under it, otherwise the children firmware would stop working. Reported-by: Paul Johnson <pjay@xxxxxxxxxxx> Suggested-by: Bjorn Helgaas <bhelgaas@xxxxxxxxxx> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=92351 Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx> Cc: stable@xxxxxxxxxxxxxxx --- drivers/pci/setup-bus.c | 6 ++++-- include/linux/ioport.h | 2 +- kernel/resource.c | 28 ++++++++++++++++++++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 63a5d4cf..dcbbe04 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -2070,14 +2070,16 @@ static void pci_bridge_release_resources(struct pci_bus *bus, r = &b_res[idx]; - if (!r->parent) + if (!r->parent || r->flags & IORESOURCE_PCI_FIXED) return; /* * if there are children under that, we should release them * all */ - release_child_resources(r); + if (!release_child_resources(r)) + return; + if (!release_resource(r)) { type = old_flags = r->flags & type_mask; dev_printk(KERN_DEBUG, &dev->dev, "resource %d %pR released\n", diff --git a/include/linux/ioport.h b/include/linux/ioport.h index 388e3ae..27dbb18 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -141,7 +141,7 @@ extern struct resource iomem_resource; extern struct resource *request_resource_conflict(struct resource *root, struct resource *new); extern int request_resource(struct resource *root, struct resource *new); extern int release_resource(struct resource *new); -void release_child_resources(struct resource *new); +bool release_child_resources(struct resource *new); extern void reserve_region_with_split(struct resource *root, resource_size_t start, resource_size_t end, const char *name); diff --git a/kernel/resource.c b/kernel/resource.c index 697b8ca..4e43f9b 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -276,11 +276,35 @@ static void __release_child_resources(struct resource *r) } } -void release_child_resources(struct resource *r) +static bool __has_fixed_child_resources(struct resource *r) { + struct resource *p; + + p = r->child; + while (p) { + if (p->flags & IORESOURCE_PCI_FIXED) + return true; + + if (__has_fixed_child_resources(p)) + return true; + + p = p->sibling; + } + + return false; +} + +bool release_child_resources(struct resource *r) +{ + bool fixed; + write_lock(&resource_lock); - __release_child_resources(r); + fixed = __has_fixed_child_resources(r); + if (!fixed) + __release_child_resources(r); write_unlock(&resource_lock); + + return !fixed; } /** -- 1.8.4.5 -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html