Commit 1ed276a7 authored by Lukas Wunner's avatar Lukas Wunner Committed by Bjorn Helgaas

PCI: Autosense device removal in pci_bridge_d3_update()

The algorithm to update the flag indicating whether a bridge may go to D3
makes a few optimizations based on whether the update was caused by the
removal of a device on the one hand, versus the addition of a device or the
change of its D3cold flags on the other hand.

The information whether the update pertains to a removal is currently
passed in by the caller, but the function may as well determine that itself
by examining the device in question, thereby allowing for a considerable
simplification and reduction of the code.

Out of several options to determine removal, I've chosen the function
device_is_registered() because it's cheap:  It merely returns the
dev->kobj.state_in_sysfs flag.  That flag is set through device_add() when
the root bus is scanned and cleared through device_remove().  The call to
pci_bridge_d3_update() happens after each of these calls, respectively, so
the ordering is correct.

No functional change intended.
Tested-by: default avatarMika Westerberg <>
Signed-off-by: default avatarLukas Wunner <>
Signed-off-by: default avatarBjorn Helgaas <>
Reviewed-by: default avatarRafael J. Wysocki <>
parent 738a7edb
......@@ -320,7 +320,7 @@ void pci_bus_add_device(struct pci_dev *dev)
pci_fixup_device(pci_fixup_final, dev);
dev->match_driver = true;
retval = device_attach(&dev->dev);
......@@ -2281,14 +2281,14 @@ static int pci_dev_check_d3cold(struct pci_dev *dev, void *data)
* pci_bridge_d3_update - Update bridge D3 capabilities
* @dev: PCI device which is changed
* @remove: Is the device being removed
* Update upstream bridge PM capabilities accordingly depending on if the
* device PM configuration was changed or the device is being removed. The
* change is also propagated upstream.
static void pci_bridge_d3_update(struct pci_dev *dev, bool remove)
void pci_bridge_d3_update(struct pci_dev *dev)
bool remove = !device_is_registered(&dev->dev);
struct pci_dev *bridge;
bool d3cold_ok = true;
......@@ -2315,35 +2315,10 @@ static void pci_bridge_d3_update(struct pci_dev *dev, bool remove)
if (bridge->bridge_d3 != d3cold_ok) {
bridge->bridge_d3 = d3cold_ok;
/* Propagate change to upstream bridges */
pci_bridge_d3_update(bridge, false);
* pci_bridge_d3_device_changed - Update bridge D3 capabilities on change
* @dev: PCI device that was changed
* If a device is added or its PM configuration, such as is it allowed to
* enter D3cold, is changed this function updates upstream bridge PM
* capabilities accordingly.
void pci_bridge_d3_device_changed(struct pci_dev *dev)
pci_bridge_d3_update(dev, false);
* pci_bridge_d3_device_removed - Update bridge D3 capabilities on remove
* @dev: PCI device being removed
* Function updates upstream bridge PM capabilities based on other devices
* still left on the bus.
void pci_bridge_d3_device_removed(struct pci_dev *dev)
pci_bridge_d3_update(dev, true);
* pci_d3cold_enable - Enable D3cold for device
* @dev: PCI device to handle
......@@ -2356,7 +2331,7 @@ void pci_d3cold_enable(struct pci_dev *dev)
if (dev->no_d3cold) {
dev->no_d3cold = false;
......@@ -2373,7 +2348,7 @@ void pci_d3cold_disable(struct pci_dev *dev)
if (!dev->no_d3cold) {
dev->no_d3cold = true;
......@@ -85,8 +85,7 @@ void pci_pm_init(struct pci_dev *dev);
void pci_ea_init(struct pci_dev *dev);
void pci_allocate_cap_save_buffers(struct pci_dev *dev);
void pci_free_cap_save_buffers(struct pci_dev *dev);
void pci_bridge_d3_device_changed(struct pci_dev *dev);
void pci_bridge_d3_device_removed(struct pci_dev *dev);
void pci_bridge_d3_update(struct pci_dev *dev);
static inline void pci_wakeup_event(struct pci_dev *dev)
......@@ -40,7 +40,7 @@ static void pci_destroy_dev(struct pci_dev *dev)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment