• Lukas Wunner's avatar
    vga_switcheroo: Update PCI current_state on power change · dcac86b7
    Lukas Wunner authored
    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@redhat.com>
    Cc: Ben Skeggs <bskeggs@redhat.com>
    Cc: Takashi Iwai <tiwai@suse.de>
    Cc: Alex Deucher <alexander.deucher@amd.com>
    Cc: Bjorn Helgaas <bhelgaas@google.com>
    Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
    Reviewed-by: default avatarPeter Wu <peter@lekensteyn.nl>
    Tested-by: Kai Heng Feng <kai.heng.feng@canonical.com> # AMD PowerXpress
    Tested-by: Mike Lothian <mike@fireburn.co.uk>          # AMD PowerXpress
    Tested-by: Denis Lisov <dennis.lissov@gmail.com>       # Nvidia Optimus
    Tested-by: Peter Wu <peter@lekensteyn.nl>              # Nvidia Optimus
    Tested-by: Lukas Wunner <lukas@wunner.de>              # MacBook Pro
    Signed-off-by: default avatarLukas Wunner <lukas@wunner.de>
    Link: https://patchwork.freedesktop.org/patch/msgid/8416958482c8c42d6f311ea5c1e5a65ccf21f5db.1520068884.git.lukas@wunner.de
    dcac86b7
vga_switcheroo.c 34.6 KB