From: Geramy Loveless <gloveless@jqluv.com>
To: "Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>
Cc: "Cristian Cocos" <cristi@ieee.org>,
"Christian König" <christian.koenig@amd.com>,
linux-pci@vger.kernel.org,
"Geramy Loveless" <gloveless@jqluv.com>
Subject: [PATCH v3 RESEND] PCI: release empty sibling bridge windows during window resize
Date: Tue, 28 Apr 2026 15:55:32 -0700 [thread overview]
Message-ID: <20260428225532.3108047-1-gloveless@jqluv.com> (raw)
pbus_reassign_bridge_resources() refuses to release bridge windows that
have child resources. On multi-port PCIe switches (e.g. Thunderbolt
docks), empty sibling downstream ports hold small reservations that
prevent the parent window from being freed and re-sized for rebar.
Walk descendants of the target window depth-first, saving and freeing
each empty bridge window so the parent can then be released and grown.
Without this change, attempts to grow a window deep below a switch
fabric leave nested empty windows pinning the ancestor:
pcieport 0000:65:00.0: bridge window [mem 0x8880000000-0x98800fffff
64bit pref]: not released, active children present
pcieport 0000:00:03.2: bridge window [mem 0x8880000000-0x98800fffff
64bit pref]: not released, active children present
With the bottom-up walk and upstream ancestry check, the chain unwinds
and the rebar succeeds:
pcieport 0000:96:00.0: bridge window [...]: releasing
pcieport 0000:95:00.0: bridge window [...]: releasing
pcieport 0000:94:00.0: bridge window [...]: releasing
pcieport 0000:65:00.0: bridge window [...]: releasing
amdgpu 0000:97:00.0: BAR 0 [mem 0x9000000000-0x97ffffffff 64bit pref]:
assigned
Suggested-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Geramy Loveless <gloveless@jqluv.com>
---
RESEND: my earlier v3 (Message-ID 20260428225146.3104063-1-gloveless@jqluv.com)
was sent with stale code — the diff was byte-identical to v2 because the
v3 edits weren't staged before commit --amend. This resend contains the
actual v3 content described below. Apologies for the noise.
v3:
- Restructure helper: outer loop only recurses; inner iterates bus
resources via pci_bus_for_each_resource(). The release path is now
unified, so the caller-side block in pbus_reassign_bridge_resources()
is gone.
- Walk the resource tree upstream when checking ancestry of @b_win,
so descendants in nested topologies are also released (Ilpo).
- Drop pci_resource_is_bridge_win() filter; bus resources are
inherently bridge windows.
- Rename pci_bus_release_empty_bridge_resources() to
pbus_release_empty_bridge_resources().
- Drop misleading "Uses PCI bus/device iterators..." paragraph from
commit message.
- Kerneldoc tweaks per Ilpo's review.
v2:
- Use PCI bus/device iterators instead of walking raw resource tree.
- Save released resources to rollback list.
- Filter via pci_resource_is_bridge_win() (now removed in v3).
- Call release before the !res->child check.
- Check bridge->subordinate before recursion.
---
drivers/pci/setup-bus.c | 78 ++++++++++++++++++++++++++++++++---------
1 file changed, 61 insertions(+), 17 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 4cf120ebe5a..b47dc1a2925 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -2292,6 +2292,63 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
}
EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
+/*
+ * pbus_release_empty_bridge_resources - Bottom-up release of bridge windows
+ * in empty subtrees.
+ * @bus: PCI bus whose child bridges to process
+ * @b_win: Ancestor bridge window; only resources that are (grand)parented
+ * by @b_win are released
+ * @saved: List to store released resources into for rollback
+ *
+ * Recurses depth-first into subordinate buses, then releases bridge windows
+ * that are (grand)parented by @b_win on the way back up. Each resource is
+ * stored into @saved before release so the entire operation can be rolled
+ * back.
+ */
+static void pbus_release_empty_bridge_resources(struct pci_bus *bus,
+ struct resource *b_win,
+ struct list_head *saved)
+{
+ struct pci_dev *dev;
+ struct resource *r;
+ unsigned int i;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ if (dev->subordinate)
+ pbus_release_empty_bridge_resources(dev->subordinate,
+ b_win, saved);
+ }
+
+ pci_bus_for_each_resource(bus, r, i) {
+ struct resource *p;
+ unsigned int idx;
+
+ if (!r || !resource_assigned(r))
+ continue;
+
+ /* Walk upstream to confirm r descends from (or equals) b_win */
+ for (p = r; p && p != b_win; p = p->parent)
+ ;
+ if (!p)
+ continue;
+
+ idx = pci_resource_num(bus->self, r);
+
+ if (r->child) {
+ const char *res_name = pci_resource_name(bus->self, idx);
+
+ pci_info(bus->self, "%s %pR: not released, active children present\n",
+ res_name, r);
+ continue;
+ }
+
+ if (pci_dev_res_add_to_list(saved, bus->self, r, 0, 0))
+ continue;
+
+ pci_release_resource(bus->self, idx);
+ }
+}
+
/*
* Walk to the root bus, find the bridge window relevant for @res and
* release it when possible. If the bridge window contains assigned
@@ -2305,7 +2362,6 @@ static int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *
struct pci_dev *bridge = NULL;
LIST_HEAD(added);
LIST_HEAD(failed);
- unsigned int i;
int ret = 0;
while (!pci_is_root_bus(bus)) {
@@ -2314,22 +2370,10 @@ static int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *
if (!res)
break;
- i = pci_resource_num(bridge, res);
-
- /* Ignore BARs which are still in use */
- if (!res->child) {
- ret = pci_dev_res_add_to_list(saved, bridge, res, 0, 0);
- if (ret)
- return ret;
-
- pci_release_resource(bridge, i);
- } else {
- const char *res_name = pci_resource_name(bridge, i);
-
- pci_warn(bridge,
- "%s %pR: was not released (still contains assigned resources)\n",
- res_name, res);
- }
+ /* Release this bridge window and any empty descendants bottom-up */
+ if (bridge->subordinate)
+ pbus_release_empty_bridge_resources(bridge->subordinate,
+ res, saved);
bus = bus->parent;
}
--
2.43.0
next reply other threads:[~2026-04-28 22:55 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-28 22:55 Geramy Loveless [this message]
2026-04-29 10:34 ` [PATCH v3 RESEND] PCI: release empty sibling bridge windows during window resize Ilpo Järvinen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260428225532.3108047-1-gloveless@jqluv.com \
--to=gloveless@jqluv.com \
--cc=christian.koenig@amd.com \
--cc=cristi@ieee.org \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=linux-pci@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox