aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/pci.c28
1 files changed, 20 insertions, 8 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 8200874ef5fc..4a7f6f54d669 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2297,20 +2297,32 @@ void pci_bridge_d3_update(struct pci_dev *dev)
2297 return; 2297 return;
2298 2298
2299 /* 2299 /*
2300 * If the device is removed we do not care about its D3cold 2300 * If D3 is currently allowed for the bridge, removing one of its
2301 * capabilities. 2301 * children won't change that.
2302 */
2303 if (remove && bridge->bridge_d3)
2304 return;
2305
2306 /*
2307 * If D3 is currently allowed for the bridge and a child is added or
2308 * changed, disallowance of D3 can only be caused by that child, so
2309 * we only need to check that single device, not any of its siblings.
2310 *
2311 * If D3 is currently not allowed for the bridge, checking the device
2312 * first may allow us to skip checking its siblings.
2302 */ 2313 */
2303 if (!remove) 2314 if (!remove)
2304 pci_dev_check_d3cold(dev, &d3cold_ok); 2315 pci_dev_check_d3cold(dev, &d3cold_ok);
2305 2316
2306 if (d3cold_ok) { 2317 /*
2307 /* 2318 * If D3 is currently not allowed for the bridge, this may be caused
2308 * We need to go through all children to find out if all of 2319 * either by the device being changed/removed or any of its siblings,
2309 * them can still go to D3cold. 2320 * so we need to go through all children to find out if one of them
2310 */ 2321 * continues to block D3.
2322 */
2323 if (d3cold_ok && !bridge->bridge_d3)
2311 pci_walk_bus(bridge->subordinate, pci_dev_check_d3cold, 2324 pci_walk_bus(bridge->subordinate, pci_dev_check_d3cold,
2312 &d3cold_ok); 2325 &d3cold_ok);
2313 }
2314 2326
2315 if (bridge->bridge_d3 != d3cold_ok) { 2327 if (bridge->bridge_d3 != d3cold_ok) {
2316 bridge->bridge_d3 = d3cold_ok; 2328 bridge->bridge_d3 = d3cold_ok;