diff options
| -rw-r--r-- | drivers/pci/pci.h | 2 | ||||
| -rw-r--r-- | drivers/pci/setup-bus.c | 38 | ||||
| -rw-r--r-- | drivers/pci/setup-res.c | 2 |
3 files changed, 20 insertions, 22 deletions
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index cbd40f05c39c..0d96a9141227 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -334,7 +334,7 @@ struct device *pci_get_host_bridge_device(struct pci_dev *dev); void pci_put_host_bridge_device(struct device *dev); unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge); -int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type); +int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *res); int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align); int pci_configure_extended_tags(struct pci_dev *dev, void *ign); diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 913fd41e1d0d..4b08b9cecab3 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -2522,10 +2522,16 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge) } EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources); -int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type) +/* + * Walk to the root bus, find the bridge window relevant for @res and + * release it when possible. If the bridge window contains assigned + * resources, it cannot be released. + */ +int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *res) { + unsigned long type = res->flags; struct pci_dev_resource *dev_res; - struct pci_dev *next; + struct pci_dev *bridge; LIST_HEAD(saved); LIST_HEAD(added); LIST_HEAD(failed); @@ -2534,33 +2540,25 @@ int pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type) down_read(&pci_bus_sem); - /* Walk to the root hub, releasing bridge BARs when possible */ - next = bridge; - do { - bridge = next; - for (i = PCI_BRIDGE_RESOURCES; i < PCI_BRIDGE_RESOURCE_END; - i++) { - struct resource *res = &bridge->resource[i]; - - if ((res->flags ^ type) & PCI_RES_TYPE_MASK) - continue; + while (!pci_is_root_bus(bus)) { + bridge = bus->self; + res = pbus_select_window(bus, res); + if (!res) + break; - /* Ignore BARs which are still in use */ - if (res->child) - continue; + i = pci_resource_num(bridge, res); + /* Ignore BARs which are still in use */ + if (!res->child) { ret = add_to_list(&saved, bridge, res, 0, 0); if (ret) goto cleanup; pci_release_resource(bridge, i); - break; } - if (i == PCI_BRIDGE_RESOURCE_END) - break; - next = bridge->bus ? bridge->bus->self : NULL; - } while (next); + bus = bus->parent; + } if (list_empty(&saved)) { up_read(&pci_bus_sem); diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 21f77e5c647c..c3ba4ccecd43 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -496,7 +496,7 @@ int pci_resize_resource(struct pci_dev *dev, int resno, int size) /* Check if the new config works by trying to assign everything. */ if (dev->bus->self) { - ret = pci_reassign_bridge_resources(dev->bus->self, res->flags); + ret = pbus_reassign_bridge_resources(dev->bus, res); if (ret) goto error_resize; } |
