pci_bus_release_bridge_resources() takes type, which is converted
into a bridge window resource in pci_bridge_release_resources().

Find out the correct bridge window for resource whose assignment failed.
Pass that bridge window to pci_bus_release_bridge_resources() instead of
passing the type. When recursing to subordinate, check which bridge
windows have to be released and recurse for each.

For now, use pbus_select_window_for_type() instead of
pbus_select_window() because non-bridge window resources still have
their flags reset which destroys the type information from the struct
resource. The struct pci_dev_resource holds a copy of the flags which
are used instead.

Signed-off-by: Ilpo Järvinen <ilpo.jarvi...@linux.intel.com>
---
 drivers/pci/setup-bus.c | 69 ++++++++++++++++-------------------------
 1 file changed, 27 insertions(+), 42 deletions(-)

diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index f5b0274bde0a..9c69a84f2b23 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -1800,51 +1800,24 @@ static void __pci_bridge_assign_resources(const struct 
pci_dev *bridge,
 }
 
 static void pci_bridge_release_resources(struct pci_bus *bus,
-                                        unsigned long type)
+                                        struct resource *b_win)
 {
        struct pci_dev *dev = bus->self;
-       struct resource *r;
-       struct resource *b_res;
        int idx, ret;
 
-       b_res = &dev->resource[PCI_BRIDGE_RESOURCES];
-
-       /*
-        * 1. If IO port assignment fails, release bridge IO port.
-        * 2. If non pref MMIO assignment fails, release bridge nonpref MMIO.
-        * 3. If 64bit pref MMIO assignment fails, and bridge pref is 64bit,
-        *    release bridge pref MMIO.
-        * 4. If pref MMIO assignment fails, and bridge pref is 32bit,
-        *    release bridge pref MMIO.
-        * 5. If pref MMIO assignment fails, and bridge pref is not
-        *    assigned, release bridge nonpref MMIO.
-        */
-       if (type & IORESOURCE_IO)
-               idx = 0;
-       else if (!(type & IORESOURCE_PREFETCH))
-               idx = 1;
-       else if ((type & IORESOURCE_MEM_64) &&
-                (b_res[2].flags & IORESOURCE_MEM_64))
-               idx = 2;
-       else if (!(b_res[2].flags & IORESOURCE_MEM_64) &&
-                (b_res[2].flags & IORESOURCE_PREFETCH))
-               idx = 2;
-       else
-               idx = 1;
-
-       r = &b_res[idx];
-
-       if (!r->parent)
+       if (!b_win->parent)
                return;
 
+       idx = pci_resource_num(dev, b_win);
+
        /* If there are children, release them all */
-       release_child_resources(r);
+       release_child_resources(b_win);
 
-       ret = pci_release_resource(dev, PCI_BRIDGE_RESOURCES + idx);
+       ret = pci_release_resource(dev, idx);
        if (ret)
                return;
 
-       pci_setup_one_bridge_window(dev, PCI_BRIDGE_RESOURCES + idx);
+       pci_setup_one_bridge_window(dev, idx);
 }
 
 enum release_type {
@@ -1857,7 +1830,7 @@ enum release_type {
  * a larger window later.
  */
 static void pci_bus_release_bridge_resources(struct pci_bus *bus,
-                                            unsigned long type,
+                                            struct resource *b_win,
                                             enum release_type rel_type)
 {
        struct pci_dev *dev;
@@ -1865,6 +1838,8 @@ static void pci_bus_release_bridge_resources(struct 
pci_bus *bus,
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
                struct pci_bus *b = dev->subordinate;
+               struct resource *res;
+
                if (!b)
                        continue;
 
@@ -1873,9 +1848,15 @@ static void pci_bus_release_bridge_resources(struct 
pci_bus *bus,
                if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
                        continue;
 
-               if (rel_type == whole_subtree)
-                       pci_bus_release_bridge_resources(b, type,
-                                                whole_subtree);
+               if (rel_type != whole_subtree)
+                       continue;
+
+               pci_bus_for_each_resource(b, res) {
+                       if (res->parent != b_win)
+                               continue;
+
+                       pci_bus_release_bridge_resources(b, res, whole_subtree);
+               }
        }
 
        if (pci_is_root_bus(bus))
@@ -1885,7 +1866,7 @@ static void pci_bus_release_bridge_resources(struct 
pci_bus *bus,
                return;
 
        if ((rel_type == whole_subtree) || is_leaf_bridge)
-               pci_bridge_release_resources(bus, type);
+               pci_bridge_release_resources(bus, b_win);
 }
 
 static void pci_bus_dump_res(struct pci_bus *bus)
@@ -2282,9 +2263,13 @@ static void pci_prepare_next_assign_round(struct 
list_head *fail_head,
         * enough to contain child device resources.
         */
        list_for_each_entry(fail_res, fail_head, list) {
-               pci_bus_release_bridge_resources(fail_res->dev->bus,
-                                                fail_res->flags & 
PCI_RES_TYPE_MASK,
-                                                rel_type);
+               struct pci_bus *bus = fail_res->dev->bus;
+               struct resource *b_win;
+
+               b_win = pbus_select_window_for_type(bus, fail_res->flags);
+               if (!b_win)
+                       continue;
+               pci_bus_release_bridge_resources(bus, b_win, rel_type);
        }
 
        /* Restore size and flags */
-- 
2.39.5


Reply via email to