Skip to content

Commit 2a4d2c4

Browse files
committed
PCI: Make pci_wakeup_bus() & pci_bus_set_current_state() public
There are PCI devices which are power-manageable by a nonstandard means, such as a custom ACPI method. One example are discrete GPUs in hybrid graphics laptops, another are Thunderbolt controllers in Macs. Such devices can't be put into D3cold with pci_set_power_state() because pci_platform_power_transition() fails with -ENODEV. Instead they're put into D3hot by pci_set_power_state() and subsequently into D3cold by invoking the nonstandard means. However as a consequence the cached current_state is incorrectly left at D3hot. What we need to do is walk the hierarchy below such a PCI device on powerdown and update the current_state to D3cold. On powerup the PCI device itself and the hierarchy below it is in D0uninitialized, so we need to walk the hierarchy again and wake all devices, causing them to be put into D0active and then letting them autosuspend as they see fit. To this end make pci_wakeup_bus() & pci_bus_set_current_state() public so PCI drivers don't have to reinvent the wheel. Cc: Rafael J. Wysocki <[email protected]> Acked-by: Bjorn Helgaas <[email protected]> Signed-off-by: Lukas Wunner <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/2962443259e7faec577274b4ef8c54aad66f9a94.1520068884.git.lukas@wunner.de
1 parent 5775b84 commit 2a4d2c4

File tree

2 files changed

+6
-4
lines changed

2 files changed

+6
-4
lines changed

drivers/pci/pci.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -800,7 +800,7 @@ static int pci_wakeup(struct pci_dev *pci_dev, void *ign)
800800
* pci_wakeup_bus - Walk given bus and wake up devices on it
801801
* @bus: Top bus of the subtree to walk.
802802
*/
803-
static void pci_wakeup_bus(struct pci_bus *bus)
803+
void pci_wakeup_bus(struct pci_bus *bus)
804804
{
805805
if (bus)
806806
pci_walk_bus(bus, pci_wakeup, NULL);
@@ -850,11 +850,11 @@ static int __pci_dev_set_current_state(struct pci_dev *dev, void *data)
850850
}
851851

852852
/**
853-
* __pci_bus_set_current_state - Walk given bus and set current state of devices
853+
* pci_bus_set_current_state - Walk given bus and set current state of devices
854854
* @bus: Top bus of the subtree to walk.
855855
* @state: state to be set
856856
*/
857-
static void __pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
857+
void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
858858
{
859859
if (bus)
860860
pci_walk_bus(bus, __pci_dev_set_current_state, &state);
@@ -876,7 +876,7 @@ int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state)
876876
ret = pci_platform_power_transition(dev, state);
877877
/* Power off the bridge may power off the whole hierarchy */
878878
if (!ret && state == PCI_D3cold)
879-
__pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
879+
pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
880880
return ret;
881881
}
882882
EXPORT_SYMBOL_GPL(__pci_complete_power_transition);

include/linux/pci.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,8 @@ void pci_pme_wakeup_bus(struct pci_bus *bus);
11471147
void pci_d3cold_enable(struct pci_dev *dev);
11481148
void pci_d3cold_disable(struct pci_dev *dev);
11491149
bool pcie_relaxed_ordering_enabled(struct pci_dev *dev);
1150+
void pci_wakeup_bus(struct pci_bus *bus);
1151+
void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state);
11501152

11511153
/* PCI Virtual Channel */
11521154
int pci_save_vc_state(struct pci_dev *dev);

0 commit comments

Comments
 (0)