All of lore.kernel.org
 help / color / mirror / Atom feed
From: Geramy Loveless <gloveless@jqluv.com>
To: ilpo.jarvinen@linux.intel.com
Cc: Geramy Loveless <gloveless@jqluv.com>,
	linux-pci@vger.kernel.org, cristi@ieee.org
Subject: [PATCH v2] PCI: release empty sibling bridge windows during rebar expansion
Date: Thu,  9 Apr 2026 22:26:02 -0700	[thread overview]
Message-ID: <20260410052918.5556-2-gloveless@jqluv.com> (raw)
In-Reply-To: <29a5ee31baf8be7d07617beea016c3f6d03934bf.camel@ieee.org>

When pbus_reassign_bridge_resources() walks up the bridge hierarchy
to expand a window (e.g. for resizable BAR), it refuses to release
any bridge window that has children.  This prevents BAR resize on
devices behind multi-port PCIe switches (such as Thunderbolt docks)
where empty sibling downstream ports hold small reservations that
block the parent bridge window from being freed and re-sized.

Add pci_bus_subtree_empty() to check whether a bus subtree contains
any assigned device BARs, and pci_bus_release_empty_bridges() to
release bridge window resources of empty sibling bridges, saving
them to the rollback list so failures can be properly unwound.

In pbus_reassign_bridge_resources(), call pci_bus_release_empty_bridges()
before checking res->child, so empty sibling windows are cleared first
and the parent window can then be released and grown.

Uses PCI bus/device iterators rather than walking the raw resource
tree, which avoids issues with stale sibling pointers after resource
release.

Suggested-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Geramy Loveless <gloveless@jqluv.com>
---
 drivers/pci/setup-bus.c | 99 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 97 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 4cf120ebe5a..7a182cd7e4d 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -2292,6 +2292,94 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
 }
 EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
 
+/*
+ * pci_bus_subtree_empty - Check whether a bus subtree has any assigned
+ * non-bridge device resources.
+ * @bus: PCI bus to check
+ *
+ * Returns true if no device on @bus or its descendant buses has any
+ * assigned BARs (bridge window resources are not considered).
+ */
+static bool pci_bus_subtree_empty(struct pci_bus *bus)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		struct resource *r;
+		unsigned int i;
+
+		pci_dev_for_each_resource(dev, r, i) {
+			if (i >= PCI_BRIDGE_RESOURCES)
+				break;
+			if (resource_assigned(r))
+				return false;
+		}
+
+		if (dev->subordinate &&
+		    !pci_bus_subtree_empty(dev->subordinate))
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * pci_bus_release_empty_bridges - Release bridge window resources of
+ * empty sibling bridges so the parent window can be freed and re-sized.
+ * @bus: PCI bus whose child bridges to scan
+ * @b_win: Parent bridge window resource; only children of this window
+ *         are released
+ * @saved: List to save released resources for rollback
+ *
+ * For each PCI-to-PCI bridge on @bus whose subtree is empty (no assigned
+ * device BARs), releases bridge window resources that are children of
+ * @b_win, saving them for rollback via @saved.
+ *
+ * Returns 0 on success, negative errno on failure.
+ */
+static int pci_bus_release_empty_bridges(struct pci_bus *bus,
+					 struct resource *b_win,
+					 struct list_head *saved)
+{
+	struct pci_dev *dev;
+
+	list_for_each_entry(dev, &bus->devices, bus_list) {
+		struct resource *r;
+		unsigned int i;
+
+		if (!dev->subordinate)
+			continue;
+
+		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+			continue;
+
+		if (!pci_bus_subtree_empty(dev->subordinate))
+			continue;
+
+		pci_dev_for_each_resource(dev, r, i) {
+			int ret;
+
+			if (!pci_resource_is_bridge_win(i))
+				continue;
+
+			if (!resource_assigned(r))
+				continue;
+
+			if (r->parent != b_win)
+				continue;
+
+			ret = pci_dev_res_add_to_list(saved, dev, r, 0, 0);
+			if (ret)
+				return ret;
+
+			release_child_resources(r);
+			pci_release_resource(dev, i);
+		}
+	}
+
+	return 0;
+}
+
 /*
  * Walk to the root bus, find the bridge window relevant for @res and
  * release it when possible. If the bridge window contains assigned
@@ -2316,7 +2404,14 @@ static int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *
 
 		i = pci_resource_num(bridge, res);
 
-		/* Ignore BARs which are still in use */
+		/* Release empty sibling bridge windows first */
+		if (bridge->subordinate) {
+			ret = pci_bus_release_empty_bridges(
+					bridge->subordinate, res, saved);
+			if (ret)
+				return ret;
+		}
+
 		if (!res->child) {
 			ret = pci_dev_res_add_to_list(saved, bridge, res, 0, 0);
 			if (ret)
@@ -2327,7 +2422,7 @@ static int pbus_reassign_bridge_resources(struct pci_bus *bus, struct resource *
 			const char *res_name = pci_resource_name(bridge, i);
 
 			pci_warn(bridge,
-				 "%s %pR: was not released (still contains assigned resources)\n",
+				 "%s %pR: not released, active children present\n",
 				 res_name, res);
 		}
 
-- 
2.43.0


  reply	other threads:[~2026-04-10  5:30 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-08 22:31 [PATCH] PCI: release empty sibling resources during bridge window resize Geramy Loveless
2026-04-09  8:03 ` Ilpo Järvinen
     [not found]   ` <CAGpo2mcyLhY6muz9Zgg3zD=Ux-HT8RXeMvbUi27a+SX=VxCRPQ@mail.gmail.com>
2026-04-09 13:26     ` Ilpo Järvinen
2026-04-09 19:32       ` Cristian Cocos
2026-04-10  5:26         ` Geramy Loveless [this message]
2026-04-10 10:09           ` [PATCH v2] PCI: release empty sibling bridge windows during rebar expansion Ilpo Järvinen
2026-04-10 17:53             ` Geramy Loveless
2026-04-10 18:58               ` Cristian Cocos
2026-04-10 19:10                 ` [PATCH] PCI: release empty sibling bridge resources during window resize Geramy Loveless
2026-04-13 10:22                   ` Ilpo Järvinen
2026-04-10 19:14                 ` [PATCH v2] PCI: release empty sibling bridge windows during rebar expansion Geramy Loveless
2026-04-10 23:01                   ` Geramy Loveless
2026-04-10 23:21                     ` Cristian Cocos
2026-04-11  3:28                       ` Mario Limonciello
2026-04-11 16:30                         ` Geramy Loveless
2026-04-11 17:42                           ` Mario Limonciello

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=20260410052918.5556-2-gloveless@jqluv.com \
    --to=gloveless@jqluv.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.