From: Pavol Sakac <sakacpav@amazon.de>
To: Bjorn Helgaas <bhelgaas@google.com>
Cc: linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org,
"David Matlack" <dmatlack@google.com>,
"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
"Krzysztof Wilczyński" <kwilczynski@kernel.org>,
"Kees Cook" <kees@kernel.org>,
"Madhavan Srinivasan" <maddy@linux.ibm.com>,
"Michael Ellerman" <mpe@ellerman.id.au>,
"Nicholas Piggin" <npiggin@gmail.com>,
"Christophe Leroy" <chleroy@kernel.org>,
linuxppc-dev@lists.ozlabs.org,
"Niklas Schnelle" <schnelle@linux.ibm.com>,
"Benjamin Block" <bblock@linux.ibm.com>,
"Lukas Wunner" <lukas@wunner.de>,
"Ionut Nechita" <ionut.nechita@windriver.com>,
nh-open-source@amazon.com
Subject: [RFC PATCH 3/8] PCI/PM: Convert pci_bridge_d3_update() recursion to iteration
Date: Fri, 11 Sep 2026 14:29:58 +0200 [thread overview]
Message-ID: <20260911122958.88717-1-sakacpav@amazon.de> (raw)
In-Reply-To: <20260911-vfopt-s1-v1-0-693271dc0226@amazon.de>
pci_bridge_d3_update() propagates a bridge_d3 change to upstream bridges
by tail recursion: when a bridge's bridge_d3 value changes, the function
calls itself with that bridge as the new device.
Convert the tail recursion into an iterative loop. Each level recomputes
"remove" and d3cold_ok exactly as the recursive call did for its own
device, and the early returns become loop exits. No functional change
intended.
An upcoming change serializes this update with a mutex; the iterative
form lets that mutex be taken once per external call instead of once per
bridge level.
Assisted-by: LLM
Signed-off-by: Pavol Sakac <sakacpav@amazon.de>
---
drivers/pci/pci.c | 67 +++++++++++++++++++++++++----------------------
1 file changed, 35 insertions(+), 32 deletions(-)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b2879a6be5f8..c62a315c0b4c 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3104,46 +3104,49 @@ static int pci_dev_check_d3cold(struct pci_dev *dev, void *data)
*/
void pci_bridge_d3_update(struct pci_dev *dev)
{
- bool remove = !device_is_registered(&dev->dev);
struct pci_dev *bridge;
- bool d3cold_ok = true;
- bridge = pci_upstream_bridge(dev);
- if (!bridge || !pci_bridge_d3_possible(bridge))
- return;
+ while ((bridge = pci_upstream_bridge(dev)) &&
+ pci_bridge_d3_possible(bridge)) {
+ bool remove = !device_is_registered(&dev->dev);
+ bool d3cold_ok = true;
- /*
- * If D3 is currently allowed for the bridge, removing one of its
- * children won't change that.
- */
- if (remove && bridge->bridge_d3)
- return;
+ /*
+ * If D3 is currently allowed for the bridge, removing one of
+ * its children won't change that.
+ */
+ if (remove && bridge->bridge_d3)
+ break;
- /*
- * If D3 is currently allowed for the bridge and a child is added or
- * changed, disallowance of D3 can only be caused by that child, so
- * we only need to check that single device, not any of its siblings.
- *
- * If D3 is currently not allowed for the bridge, checking the device
- * first may allow us to skip checking its siblings.
- */
- if (!remove)
- pci_dev_check_d3cold(dev, &d3cold_ok);
+ /*
+ * If D3 is currently allowed for the bridge and a child is
+ * added or changed, disallowance of D3 can only be caused by
+ * that child, so we only need to check that single device,
+ * not any of its siblings.
+ *
+ * If D3 is currently not allowed for the bridge, checking the
+ * device first may allow us to skip checking its siblings.
+ */
+ if (!remove)
+ pci_dev_check_d3cold(dev, &d3cold_ok);
- /*
- * If D3 is currently not allowed for the bridge, this may be caused
- * either by the device being changed/removed or any of its siblings,
- * so we need to go through all children to find out if one of them
- * continues to block D3.
- */
- if (d3cold_ok && !bridge->bridge_d3)
- pci_walk_bus(bridge->subordinate, pci_dev_check_d3cold,
- &d3cold_ok);
+ /*
+ * If D3 is currently not allowed for the bridge, this may be
+ * caused either by the device being changed/removed or any of
+ * its siblings, so we need to go through all children to find
+ * out if one of them continues to block D3.
+ */
+ if (d3cold_ok && !bridge->bridge_d3)
+ pci_walk_bus(bridge->subordinate, pci_dev_check_d3cold,
+ &d3cold_ok);
+
+ if (bridge->bridge_d3 == d3cold_ok)
+ break;
- if (bridge->bridge_d3 != d3cold_ok) {
bridge->bridge_d3 = d3cold_ok;
+
/* Propagate change to upstream bridges */
- pci_bridge_d3_update(bridge);
+ dev = bridge;
}
}
--
2.47.3
next prev parent reply other threads:[~2026-09-11 12:30 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-11 12:11 [RFC PATCH 0/8] PCI/IOV: Initialize virtual functions in parallel Pavol Sakac
2026-09-11 12:28 ` [RFC PATCH 1/8] PCI/IOV: Split virtfn bus handling out of pci_iov_add_virtfn() Pavol Sakac
2026-09-11 12:45 ` sashiko-bot
2026-09-11 12:29 ` [RFC PATCH 2/8] PCI/IOV: Create virtfn buses up front in sriov_add_vfs() Pavol Sakac
2026-09-11 12:46 ` sashiko-bot
2026-09-11 12:29 ` Pavol Sakac [this message]
2026-09-11 12:40 ` [RFC PATCH 3/8] PCI/PM: Convert pci_bridge_d3_update() recursion to iteration sashiko-bot
2026-09-11 12:30 ` [RFC PATCH 4/8] PCI/PM: Serialize pci_bridge_d3_update() Pavol Sakac
2026-09-11 12:47 ` sashiko-bot
2026-09-11 12:31 ` [RFC PATCH 5/8] powerpc/pci: Serialize pcibios_bus_add_device() Pavol Sakac
2026-09-11 12:55 ` sashiko-bot
2026-09-11 12:32 ` [RFC PATCH 6/8] PCI/IOV: Let sriov_add_vfs() own the failure unwind Pavol Sakac
2026-09-11 12:52 ` sashiko-bot
2026-09-11 12:33 ` [RFC PATCH 7/8] PCI/IOV: Initialize virtual functions in parallel Pavol Sakac
2026-09-11 12:43 ` sashiko-bot
2026-09-11 12:34 ` [RFC PATCH 8/8] PCI: Probe inline from node-local workqueue workers Pavol Sakac
2026-09-11 12:40 ` sashiko-bot
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=20260911122958.88717-1-sakacpav@amazon.de \
--to=sakacpav@amazon.de \
--cc=bblock@linux.ibm.com \
--cc=bhelgaas@google.com \
--cc=chleroy@kernel.org \
--cc=dmatlack@google.com \
--cc=ilpo.jarvinen@linux.intel.com \
--cc=ionut.nechita@windriver.com \
--cc=kees@kernel.org \
--cc=kwilczynski@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=lukas@wunner.de \
--cc=maddy@linux.ibm.com \
--cc=mpe@ellerman.id.au \
--cc=nh-open-source@amazon.com \
--cc=npiggin@gmail.com \
--cc=schnelle@linux.ibm.com \
/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.