[Nouveau] [PATCH 2/7] PCI: Make pci_wakeup_bus() & pci_bus_set_current_state() public
Bjorn Helgaas
helgaas at kernel.org
Thu Feb 22 17:45:11 UTC 2018
On Sun, Feb 18, 2018 at 09:38:32AM +0100, Lukas Wunner wrote:
> 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: Bjorn Helgaas <bhelgaas at google.com>
> Cc: Rafael J. Wysocki <rafael.j.wysocki at intel.com>
> Signed-off-by: Lukas Wunner <lukas at wunner.de>
Acked-by: Bjorn Helgaas <bhelgaas at google.com>
> ---
> drivers/pci/pci.c | 8 ++++----
> include/linux/pci.h | 2 ++
> 2 files changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
> index f694650235f2..6e6e322a5a7d 100644
> --- a/drivers/pci/pci.c
> +++ b/drivers/pci/pci.c
> @@ -800,7 +800,7 @@ static int pci_wakeup(struct pci_dev *pci_dev, void *ign)
> * pci_wakeup_bus - Walk given bus and wake up devices on it
> * @bus: Top bus of the subtree to walk.
> */
> -static void pci_wakeup_bus(struct pci_bus *bus)
> +void pci_wakeup_bus(struct pci_bus *bus)
> {
> if (bus)
> pci_walk_bus(bus, pci_wakeup, NULL);
> @@ -850,11 +850,11 @@ static int __pci_dev_set_current_state(struct pci_dev *dev, void *data)
> }
>
> /**
> - * __pci_bus_set_current_state - Walk given bus and set current state of devices
> + * pci_bus_set_current_state - Walk given bus and set current state of devices
> * @bus: Top bus of the subtree to walk.
> * @state: state to be set
> */
> -static void __pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
> +void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state)
> {
> if (bus)
> 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)
> ret = pci_platform_power_transition(dev, state);
> /* Power off the bridge may power off the whole hierarchy */
> if (!ret && state == PCI_D3cold)
> - __pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
> + pci_bus_set_current_state(dev->subordinate, PCI_D3cold);
> return ret;
> }
> EXPORT_SYMBOL_GPL(__pci_complete_power_transition);
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 024a1beda008..ae42289662df 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -1147,6 +1147,8 @@ void pci_pme_wakeup_bus(struct pci_bus *bus);
> void pci_d3cold_enable(struct pci_dev *dev);
> void pci_d3cold_disable(struct pci_dev *dev);
> bool pcie_relaxed_ordering_enabled(struct pci_dev *dev);
> +void pci_wakeup_bus(struct pci_bus *bus);
> +void pci_bus_set_current_state(struct pci_bus *bus, pci_power_t state);
>
> /* PCI Virtual Channel */
> int pci_save_vc_state(struct pci_dev *dev);
> --
> 2.15.1
>
More information about the Nouveau
mailing list