diff mbox series

[v17,3/4] PCI: Check for changes in pci_bridge_d3_possible() when updating D3

Message ID 20230906184354.45846-4-mario.limonciello@amd.com
State New
Headers show
Series Allow drivers to influence D3 behavior for bridges | expand

Commit Message

Mario Limonciello Sept. 6, 2023, 6:43 p.m. UTC
As drivers can report an optin or veto for a given PCI device it's
possible that pci_bridge_d3_possible() reports different values while
calling pci_bridge_d3_update().  Take these values into account while
updating the ability for a bridge to go into D3.

Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
---
 drivers/pci/pci.c | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 06ab73f58adf..9004d8ea460a 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3100,6 +3100,14 @@  static int pci_dev_check_d3cold(struct pci_dev *dev, void *data)
 	return !*d3cold_ok;
 }
 
+static void pci_bridge_d3_propagate(struct pci_dev *bridge, bool d3_ok)
+{
+	if (bridge->bridge_d3 != d3_ok) {
+		bridge->bridge_d3 = d3_ok;
+		pci_bridge_d3_propagate(bridge, d3_ok);
+	}
+}
+
 /*
  * pci_bridge_d3_update - Update bridge D3 capabilities
  * @dev: PCI device which is changed
@@ -3112,12 +3120,16 @@  void pci_bridge_d3_update(struct pci_dev *dev)
 {
 	bool remove = !device_is_registered(&dev->dev);
 	struct pci_dev *bridge;
-	bool d3cold_ok = true;
+	bool d3_ok = true;
 
 	bridge = pci_upstream_bridge(dev);
-	if (!bridge || !pci_bridge_d3_possible(bridge))
+	if (!bridge)
 		return;
 
+	/* Propagate change to upstream bridges */
+	d3_ok = pci_bridge_d3_possible(bridge);
+	pci_bridge_d3_propagate(bridge, d3_ok);
+
 	/*
 	 * If D3 is currently allowed for the bridge, removing one of its
 	 * children won't change that.
@@ -3134,7 +3146,7 @@  void pci_bridge_d3_update(struct pci_dev *dev)
 	 * first may allow us to skip checking its siblings.
 	 */
 	if (!remove)
-		pci_dev_check_d3cold(dev, &d3cold_ok);
+		pci_dev_check_d3cold(dev, &d3_ok);
 
 	/*
 	 * If D3 is currently not allowed for the bridge, this may be caused
@@ -3142,15 +3154,12 @@  void pci_bridge_d3_update(struct pci_dev *dev)
 	 * 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)
+	if (d3_ok && !bridge->bridge_d3)
 		pci_walk_bus(bridge->subordinate, pci_dev_check_d3cold,
-			     &d3cold_ok);
+			     &d3_ok);
 
-	if (bridge->bridge_d3 != d3cold_ok) {
-		bridge->bridge_d3 = d3cold_ok;
-		/* Propagate change to upstream bridges */
-		pci_bridge_d3_update(bridge);
-	}
+	/* Propagate change to upstream bridges */
+	pci_bridge_d3_propagate(bridge, d3_ok);
 }
 
 /**