* [PATCH] PCI: release empty sibling resources during bridge window resize
@ 2026-04-08 22:31 Geramy Loveless
2026-04-09 8:03 ` Ilpo Järvinen
0 siblings, 1 reply; 6+ messages in thread
From: Geramy Loveless @ 2026-04-08 22:31 UTC (permalink / raw)
To: linux-pci; +Cc: ilpo.jarvinen
When pci_resize_resource() walks up the bridge hierarchy via
pbus_reassign_bridge_resources(), bridge windows with any child
resources are refused release. 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_release_bridge_resources_safe() which verifies that a
resource subtree contains no active children before releasing it,
and use it in pbus_reassign_bridge_resources() to clear empty sibling
reservations so the bridge window can grow.
Signed-off-by: Geramy Loveless <gloveless@jqluv.com>
---
drivers/pci/setup-bus.c | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 4cf120ebe..9a3a23819 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -2297,6 +2297,30 @@
EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
* release it when possible. If the bridge window contains assigned
* resources, it cannot be released.
*/
+
+/*
+ * Release child resources from a bridge window so it can be freed and
+ * re-sized, but only if the entire subtree is empty (no active device
+ * resources underneath). Walks the resource tree recursively to handle
+ * arbitrarily deep bridge hierarchies. Returns true if the resources
+ * were released or the window was already empty.
+ */
+static bool pci_bus_release_bridge_resources_safe(struct pci_bus *bus,
+ struct resource *res)
+{
+ struct resource *child;
+
+ for (child = res->child; child; child = child->sibling) {
+ if (child->child &&
+ !pci_bus_release_bridge_resources_safe(bus, child))
+ return false;
+ }
+
+ if (res->child)
+ pci_bus_release_bridge_resources(bus, res, whole_subtree);
+ return true;
+}
+
static int pbus_reassign_bridge_resources(struct pci_bus *bus, struct
resource *res,
struct list_head *saved)
{
@@ -2316,8 +2340,8 @@ 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 */
- if (!res->child) {
+ if (!res->child ||
+ pci_bus_release_bridge_resources_safe(bridge->subordinate, res)) {
ret = pci_dev_res_add_to_list(saved, bridge, res, 0, 0);
if (ret)
return ret;
@@ -2327,7 +2351,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.51.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH] PCI: release empty sibling resources during bridge window resize
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>
0 siblings, 1 reply; 6+ messages in thread
From: Ilpo Järvinen @ 2026-04-09 8:03 UTC (permalink / raw)
To: Geramy Loveless; +Cc: linux-pci, Cristian Cocos
On Wed, 8 Apr 2026, Geramy Loveless wrote:
Thanks for the patch. The patch need some work but the general direction
looks acceptable.
FYI, your patch is misformatted, tabs got eaten, probably something in
tha way you send the email does that.
Please Cc also Cristian Cocos <cristi@ieee.org> on further submissions.
> When pci_resize_resource() walks up the bridge hierarchy via
> pbus_reassign_bridge_resources(), bridge windows with any child
> resources are refused release. 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_release_bridge_resources_safe() which verifies that a
> resource subtree contains no active children before releasing it,
> and use it in pbus_reassign_bridge_resources() to clear empty sibling
> reservations so the bridge window can grow.
>
> Signed-off-by: Geramy Loveless <gloveless@jqluv.com>
You may want to add Suggested-by tag.
> ---
> drivers/pci/setup-bus.c | 30 +++++++++++++++++++++++++++---
> 1 file changed, 27 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
> index 4cf120ebe..9a3a23819 100644
> --- a/drivers/pci/setup-bus.c
> +++ b/drivers/pci/setup-bus.c
> @@ -2297,6 +2297,30 @@
> EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
> * release it when possible. If the bridge window contains assigned
> * resources, it cannot be released.
> */
> +
> +/*
> + * Release child resources from a bridge window so it can be freed and
> + * re-sized, but only if the entire subtree is empty (no active device
> + * resources underneath). Walks the resource tree recursively to handle
> + * arbitrarily deep bridge hierarchies. Returns true if the resources
> + * were released or the window was already empty.
> + */
> +static bool pci_bus_release_bridge_resources_safe(struct pci_bus *bus,
> + struct resource *res)
> +{
> + struct resource *child;
> +
> + for (child = res->child; child; child = child->sibling) {
> + if (child->child &&
> + !pci_bus_release_bridge_resources_safe(bus, child))
> + return false;
This should walk bus devices and device resources using PCI side
iterators (not using the low-level resource list). This does not look
safe iteration anyway because the code is also removing entries from the
resource tree (it only works because resource code leaves stale sibling
pointers which should be corrected one day).
PCI side should be enough to capture all resources, and that way you
still have access to all PCI side structs.
Perhaps sanity checking ! ->child at the end wouldn't hurt but it the
release should be doable.
You should also pass the saved list and store any released resources so
you can properly rollback in case of a failure (I think the rollback
code will already just-work as long as you add the entries there).
> + }
> +
> + if (res->child)
> + pci_bus_release_bridge_resources(bus, res, whole_subtree);
I think this could pass non-bridge window resources which looks wrong but
you need to rewrite the algorithm in this function anyway.
> + return true;
> +}
> +
> static int pbus_reassign_bridge_resources(struct pci_bus *bus, struct
> resource *res,
> struct list_head *saved)
> {
> @@ -2316,8 +2340,8 @@ 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 */
> - if (!res->child) {
> + if (!res->child ||
> + pci_bus_release_bridge_resources_safe(bridge->subordinate, res)) {
Just call this release always before checking !res->child.
You need to check bridge->subordinate before calling it.
> ret = pci_dev_res_add_to_list(saved, bridge, res, 0, 0);
> if (ret)
> return ret;
> @@ -2327,7 +2351,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);
> }
>
--
i.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] PCI: release empty sibling resources during bridge window resize
[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
0 siblings, 1 reply; 6+ messages in thread
From: Ilpo Järvinen @ 2026-04-09 13:26 UTC (permalink / raw)
To: Geramy Loveless; +Cc: linux-pci, cristi
[-- Attachment #1: Type: text/plain, Size: 5983 bytes --]
On Thu, 9 Apr 2026, Geramy Loveless wrote:
> Perfect I’ll get started on these changes, while I’m here, does the other bug create
> a cascade of problems if fixed?
Hi,
I'm not sure what "other bug" refers to?
If you meant Cristian problem, he seemed to have empty bridge windows
which this approach should be able to solve without extra problems
expected.
If you refer to the resource entries having dangling resource tree
pointers (sibling, etc.), it's not a big problem when the resource entry
has been detached from the tree. It has some impact on whether
resource_assigned() can always be trusted so it would be nice to clear all
those links on removal (the current remove algorithm shortcuts the
subtree).
--
i.
> On Thu, Apr 9, 2026 at 1:03 AM Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> wrote:
> On Wed, 8 Apr 2026, Geramy Loveless wrote:
>
> Thanks for the patch. The patch need some work but the general direction
> looks acceptable.
>
> FYI, your patch is misformatted, tabs got eaten, probably something in
> tha way you send the email does that.
>
> Please Cc also Cristian Cocos <cristi@ieee.org> on further submissions.
>
> > When pci_resize_resource() walks up the bridge hierarchy via
> > pbus_reassign_bridge_resources(), bridge windows with any child
> > resources are refused release. 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_release_bridge_resources_safe() which verifies that a
> > resource subtree contains no active children before releasing it,
> > and use it in pbus_reassign_bridge_resources() to clear empty sibling
> > reservations so the bridge window can grow.
> >
> > Signed-off-by: Geramy Loveless <gloveless@jqluv.com>
>
> You may want to add Suggested-by tag.
>
> > ---
> > drivers/pci/setup-bus.c | 30 +++++++++++++++++++++++++++---
> > 1 file changed, 27 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
> > index 4cf120ebe..9a3a23819 100644
> > --- a/drivers/pci/setup-bus.c
> > +++ b/drivers/pci/setup-bus.c
> > @@ -2297,6 +2297,30 @@
> > EXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
> > * release it when possible. If the bridge window contains assigned
> > * resources, it cannot be released.
> > */
> > +
> > +/*
> > + * Release child resources from a bridge window so it can be freed and
> > + * re-sized, but only if the entire subtree is empty (no active device
> > + * resources underneath). Walks the resource tree recursively to
> handle
> > + * arbitrarily deep bridge hierarchies. Returns true if the resources
> > + * were released or the window was already empty.
> > + */
> > +static bool pci_bus_release_bridge_resources_safe(struct pci_bus *bus,
> > + struct resource *res)
> > +{
> > + struct resource *child;
> > +
> > + for (child = res->child; child; child = child->sibling) {
> > + if (child->child &&
> > + !pci_bus_release_bridge_resources_safe(bus, child))
> > + return false;
>
> This should walk bus devices and device resources using PCI side
> iterators (not using the low-level resource list). This does not look
> safe iteration anyway because the code is also removing entries from the
> resource tree (it only works because resource code leaves stale sibling
> pointers which should be corrected one day).
>
> PCI side should be enough to capture all resources, and that way you
> still have access to all PCI side structs.
>
> Perhaps sanity checking ! ->child at the end wouldn't hurt but it the
> release should be doable.
>
> You should also pass the saved list and store any released resources so
> you can properly rollback in case of a failure (I think the rollback
> code will already just-work as long as you add the entries there).
>
> > + }
> > +
> > + if (res->child)
> > + pci_bus_release_bridge_resources(bus, res, whole_subtree);
>
> I think this could pass non-bridge window resources which looks wrong but
> you need to rewrite the algorithm in this function anyway.
>
> > + return true;
> > +}
> > +
> > static int pbus_reassign_bridge_resources(struct pci_bus *bus, struct
> > resource *res,
> > struct list_head *saved)
> > {
> > @@ -2316,8 +2340,8 @@ 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 */
> > - if (!res->child) {
> > + if (!res->child ||
> > + pci_bus_release_bridge_resources_safe(bridge->subordinate, res)) {
>
> Just call this release always before checking !res->child.
>
> You need to check bridge->subordinate before calling it.
>
> > ret = pci_dev_res_add_to_list(saved, bridge, res, 0, 0);
> > if (ret)
> > return ret;
> > @@ -2327,7 +2351,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);
> > }
> >
>
> --
> i.
>
>
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH] PCI: release empty sibling resources during bridge window resize
2026-04-09 13:26 ` Ilpo Järvinen
@ 2026-04-09 19:32 ` Cristian Cocos
2026-04-10 5:26 ` [PATCH v2] PCI: release empty sibling bridge windows during rebar expansion Geramy Loveless
0 siblings, 1 reply; 6+ messages in thread
From: Cristian Cocos @ 2026-04-09 19:32 UTC (permalink / raw)
To: Ilpo Järvinen, Geramy Loveless; +Cc: linux-pci
This looks very encouraging!
Thanks for keeping me in the loop!
C
On Thu, 2026-04-09 at 16:26 +0300, Ilpo Järvinen wrote:
> On Thu, 9 Apr 2026, Geramy Loveless wrote:
>
> > Perfect I’ll get started on these changes, while I’m here, does the
> > other bug create
> > a cascade of problems if fixed?
>
> Hi,
>
> I'm not sure what "other bug" refers to?
>
> If you meant Cristian problem, he seemed to have empty bridge windows
> which this approach should be able to solve without extra problems
> expected.
>
> If you refer to the resource entries having dangling resource tree
> pointers (sibling, etc.), it's not a big problem when the resource
> entry
> has been detached from the tree. It has some impact on whether
> resource_assigned() can always be trusted so it would be nice to
> clear all
> those links on removal (the current remove algorithm shortcuts the
> subtree).
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2] PCI: release empty sibling bridge windows during rebar expansion
2026-04-09 19:32 ` Cristian Cocos
@ 2026-04-10 5:26 ` Geramy Loveless
2026-04-10 10:09 ` Ilpo Järvinen
0 siblings, 1 reply; 6+ messages in thread
From: Geramy Loveless @ 2026-04-10 5:26 UTC (permalink / raw)
To: ilpo.jarvinen; +Cc: Geramy Loveless, linux-pci, cristi
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
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2] PCI: release empty sibling bridge windows during rebar expansion
2026-04-10 5:26 ` [PATCH v2] PCI: release empty sibling bridge windows during rebar expansion Geramy Loveless
@ 2026-04-10 10:09 ` Ilpo Järvinen
0 siblings, 0 replies; 6+ messages in thread
From: Ilpo Järvinen @ 2026-04-10 10:09 UTC (permalink / raw)
To: Geramy Loveless; +Cc: linux-pci, cristi
[-- Attachment #1: Type: text/plain, Size: 7314 bytes --]
On Thu, 9 Apr 2026, Geramy Loveless wrote:
> 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.
This paragraph can be dropped. And it's not exactly correct either as
the pointers are only stale for resource entries that reside outside of
the resource tree (after they've been released in a specific way) so if
you start from a resource tree entry, you should never encounter a stale
pointer.
> 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;
I suppose dev->subordinate check is enough for what we're doing so this
looks redundant.
> +
> + 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);
Unfortunately you cannot call this low-level function because it
recursively frees child resources which means you won't be able to
rollback them as they were not added to the saved list.
I think the release algorithm should basically do this:
- Recurse to the subordinate buses
- Loop through bridge window resources of this bus
- Skip resources that are not assigned or are not parented by b_win
- If the resource still has childs, leave the resource alone
(+ log it for easier troubleshooting these cases; any failure
will also cascade to upstream so it may be possible to
shortcut something but it will also make the algorithm more
complicated)
- Save and free the resource
It might be better to move some of the code from
pbus_reassign_bridge_resources() here as there's overlap with the sketched
algorithm (but I'm not sure until I see the updated version but keep this
in mind).
Doing pci_bus_subtree_empty() before any removal is fine with me, but I
see it just an optimization.
> + 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 */
I don't know why you removed this comment (I admit though "BARs" could
have been worded better as it's bridge windows we're dealing here).
> + /* Release empty sibling bridge windows first */
> + if (bridge->subordinate) {
> + ret = pci_bus_release_empty_bridges(
> + bridge->subordinate, res, saved);
First arg fits to the previous line.
Align the second line to (.
But consider also rearranging code as I mentioned above.
> + if (ret)
> + return ret;
Consider proceeding with the resize even if something failed as there are
cases where the bridge windows are large enough (admittedly, you seem to
only bail out in case of alloc error).
In to the same vein, there seems to be one existing goto restore (that was
added by me), which could also probably do continue instead (but changing
it would be worth another patch).
> + }
> +
> 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);
> }
>
>
--
i.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-04-10 10:09 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [PATCH v2] PCI: release empty sibling bridge windows during rebar expansion Geramy Loveless
2026-04-10 10:09 ` Ilpo Järvinen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox