|
@@ -2297,20 +2297,32 @@ void pci_bridge_d3_update(struct pci_dev *dev)
|
|
return;
|
|
return;
|
|
|
|
|
|
/*
|
|
/*
|
|
- * If the device is removed we do not care about its D3cold
|
|
|
|
- * capabilities.
|
|
|
|
|
|
+ * 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 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)
|
|
if (!remove)
|
|
pci_dev_check_d3cold(dev, &d3cold_ok);
|
|
pci_dev_check_d3cold(dev, &d3cold_ok);
|
|
|
|
|
|
- if (d3cold_ok) {
|
|
|
|
- /*
|
|
|
|
- * We need to go through all children to find out if all of
|
|
|
|
- * them can still go to D3cold.
|
|
|
|
- */
|
|
|
|
|
|
+ /*
|
|
|
|
+ * 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,
|
|
pci_walk_bus(bridge->subordinate, pci_dev_check_d3cold,
|
|
&d3cold_ok);
|
|
&d3cold_ok);
|
|
- }
|
|
|
|
|
|
|
|
if (bridge->bridge_d3 != d3cold_ok) {
|
|
if (bridge->bridge_d3 != d3cold_ok) {
|
|
bridge->bridge_d3 = d3cold_ok;
|
|
bridge->bridge_d3 = d3cold_ok;
|