[PATCH v2 3/7] vga_switcheroo: Update PCI current_state on power change

Lukas Wunner lukas at wunner.de
Sat Mar 3 09:53:24 UTC 2018


When cutting power to a GPU and its integrated HDA controller, their
cached current_state should be updated to D3cold to reflect reality.

We currently rely on the DRM and HDA drivers to do that, however:

- The HDA driver updates the current_state in azx_vs_set_state(), which
  will no longer be called with driver power control once we migrate to
  device links.  (It will still be called with manual power control.)

- If the HDA device is not bound, its current_state remains at D0 even
  though the GPU driver may decide to go to D3cold.

- The DRM drivers update the current_state using pci_set_power_state()
  which can't put the device into a deeper power state than D3hot if the
  GPU is not deemed power-manageable by the platform (even though it
  *is* power-manageable by some nonstandard means, such as a _DSM).

Centralize updating the current_state of the GPU and HDA controller in
vga_switcheroo's ->runtime_suspend hook to overcome these deficiencies.

The GPU and HDA controller are two functions of the same PCI device
(VGA class device on function 0 and audio device on function 1) and
no other PCI devices reside on the same bus since this is a PCIe
point-to-point link, so we can just walk the bus and update the
current_state of all devices.

On ->runtime_resume, the HDA controller is in D0uninitialized state.
Resume to D0active and then let it autosuspend as it sees fit.

Note that vga_switcheroo_init_domain_pm_ops() is not supposed to be
called by hybrid graphics laptops which power down the GPU via its root
port's _PR3 resources and consequently vga_switcheroo_runtime_suspend()
is not used.  On those laptops, the root port is power-manageable by the
platform (instead of by a nonstandard means) and the current_state is
therefore updated by the PCI core through the following call chain:

  pci_set_power_state()
    __pci_complete_power_transition()
      pci_bus_set_current_state()

Resuming to D0active happens through:

  pci_set_power_state()
    __pci_start_power_transition()
      pci_wakeup_bus()

Cc: Dave Airlie <airlied at redhat.com>
Cc: Ben Skeggs <bskeggs at redhat.com>
Cc: Takashi Iwai <tiwai at suse.de>
Cc: Peter Wu <peter at lekensteyn.nl>
Cc: Alex Deucher <alexander.deucher at amd.com>
Cc: Bjorn Helgaas <bhelgaas at google.com>
Cc: Rafael J. Wysocki <rafael.j.wysocki at intel.com>
Tested-by: Mike Lothian <mike at fireburn.co.uk>
Signed-off-by: Lukas Wunner <lukas at wunner.de>
---
 drivers/gpu/vga/vga_switcheroo.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 3cd153c6d271..09dd40dd1dbe 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -1022,6 +1022,7 @@ static int vga_switcheroo_runtime_suspend(struct device *dev)
 		vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD);
 		mutex_unlock(&vgasr_priv.mux_hw_lock);
 	}
+	pci_bus_set_current_state(pdev->bus, PCI_D3cold);
 	vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF);
 	mutex_unlock(&vgasr_mutex);
 	return 0;
@@ -1035,6 +1036,7 @@ static int vga_switcheroo_runtime_resume(struct device *dev)
 	mutex_lock(&vgasr_mutex);
 	vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_ON);
 	mutex_unlock(&vgasr_mutex);
+	pci_wakeup_bus(pdev->bus);
 	ret = dev->bus->pm->runtime_resume(dev);
 	if (ret)
 		return ret;
-- 
2.15.1



More information about the dri-devel mailing list