diff options
-rw-r--r-- | drivers/pci/pci.c | 28 |
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; |