[PATCH 4/4] snd/hda: add runtime suspend/resume on optimus support

Dave Airlie airlied at gmail.com
Mon Jul 29 23:46:07 PDT 2013


On Mon, Jul 29, 2013 at 10:46 PM, Takashi Iwai <tiwai at suse.de> wrote:
> At Mon, 29 Jul 2013 16:06:59 +1000,
> Dave Airlie wrote:
>>
>> Add support for HDMI audio device on VGA cards that powerdown
>> to D3cold using non-standard ACPI/PCI infrastructure (optimus).
>>
>> This does a couple of things to make it work:
>>
>> a) add a set of power ops for the hdmi domain, and enables them
>> via vga_switcheroo when we are a switcheroo controlled card. This
>> just replaces the runtime resume operation so that when the card
>> is in D3cold the userspace pci config space access via sysfs,
>> the vga switcheroon runtime resume gets called first and it calls
>> the GPU resume callback before calling the sound card runtime
>> resume.
>>
>> b) standard ACPI/PCI stacks won't put a device into D3cold without
>> an ACPI handle, but since the hdmi audio devices on gpus don't have
>> an ACPI handle, we need to manually force the device into D3cold
>> after suspend from the switcheroo path only.
>>
>> c) don't try and do runtime s/r when the GPU is off.
>>
>> d) call runtime suspend/resume during switcheroo suspend/resume
>> this is to make sure the runtime stack knows to try and resume
>> the hdmi audio device for pci config space access.
>>
>> Signed-off-by: Dave Airlie <airlied at redhat.com>
>> ---
>>  sound/pci/hda/hda_intel.c | 40 +++++++++++++++++++++++++++++++++++++---
>>  1 file changed, 37 insertions(+), 3 deletions(-)
>>
>> diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
>> index 8860dd5..4b4d05b 100644
>> --- a/sound/pci/hda/hda_intel.c
>> +++ b/sound/pci/hda/hda_intel.c
>> @@ -555,6 +555,9 @@ struct azx {
>>  #ifdef CONFIG_SND_HDA_DSP_LOADER
>>       struct azx_dev saved_azx_dev;
>>  #endif
>> +
>> +     /* secondary power domain for hdmi audio under vga device */
>> +     struct dev_pm_domain hdmi_pm_domain;
>>  };
>>
>>  #define CREATE_TRACE_POINTS
>> @@ -2898,7 +2901,7 @@ static int param_set_xint(const char *val, const struct kernel_param *kp)
>>  /*
>>   * power management
>>   */
>> -static int azx_suspend(struct device *dev)
>> +static int azx_do_suspend(struct device *dev, pci_power_t state)
>>  {
>>       struct pci_dev *pci = to_pci_dev(dev);
>>       struct snd_card *card = dev_get_drvdata(dev);
>> @@ -2920,16 +2923,30 @@ static int azx_suspend(struct device *dev)
>>               free_irq(chip->irq, chip);
>>               chip->irq = -1;
>>       }
>> +
>> +     /*
>> +      * for vga switcheroo suspend we need to
>> +      * force runtime suspend so lspci works.
>> +      */
>> +     if (state == PCI_D3cold)
>> +             pm_runtime_suspend(&pci->dev);
>> +
>>       if (chip->msi)
>>               pci_disable_msi(chip->pci);
>>       pci_disable_device(pci);
>>       pci_save_state(pci);
>> -     pci_set_power_state(pci, PCI_D3hot);
>> +
>> +     pci_set_power_state(pci, state);
>>       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
>>               hda_display_power(false);
>>       return 0;
>>  }
>>
>> +static int azx_suspend(struct device *dev)
>> +{
>> +     return azx_do_suspend(dev, PCI_D3hot);
>> +}
>> +
>>  static int azx_resume(struct device *dev)
>>  {
>>       struct pci_dev *pci = to_pci_dev(dev);
>> @@ -2971,6 +2988,9 @@ static int azx_runtime_suspend(struct device *dev)
>>       struct snd_card *card = dev_get_drvdata(dev);
>>       struct azx *chip = card->private_data;
>>
>> +     if (chip->disabled)
>> +             return 0;
>> +
>>       azx_stop_chip(chip);
>>       azx_enter_link_reset(chip);
>>       azx_clear_irq_pending(chip);
>> @@ -2984,6 +3004,9 @@ static int azx_runtime_resume(struct device *dev)
>>       struct snd_card *card = dev_get_drvdata(dev);
>>       struct azx *chip = card->private_data;
>>
>> +     if (chip->disabled)
>> +             return 0;
>> +
>>       if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
>>               hda_display_power(true);
>>       azx_init_pci(chip);
>> @@ -2996,6 +3019,9 @@ static int azx_runtime_idle(struct device *dev)
>>       struct snd_card *card = dev_get_drvdata(dev);
>>       struct azx *chip = card->private_data;
>>
>> +     if (chip->disabled)
>> +             return 0;
>> +
>>       if (!power_save_controller ||
>>           !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
>>               return -EBUSY;
>> @@ -3078,7 +3104,11 @@ static void azx_vs_set_state(struct pci_dev *pci,
>>                          "%s: %s via VGA-switcheroo\n", pci_name(chip->pci),
>>                          disabled ? "Disabling" : "Enabling");
>>               if (disabled) {
>> -                     azx_suspend(&pci->dev);
>> +                     azx_do_suspend(&pci->dev, PCI_D3cold);
>> +                     /* when we get suspended by vga switcheroo we end up in D3cold,
>> +                      * however we have no ACPI handle, so pci/acpi can't put us there,
>> +                      * put ourselves there */
>> +                     pci->current_state = PCI_D3cold;
>>                       chip->disabled = true;
>>                       if (snd_hda_lock_devices(chip->bus))
>>                               snd_printk(KERN_WARNING SFX "%s: Cannot lock devices!\n",
>> @@ -3087,6 +3117,7 @@ static void azx_vs_set_state(struct pci_dev *pci,
>>                       snd_hda_unlock_devices(chip->bus);
>>                       chip->disabled = false;
>>                       azx_resume(&pci->dev);
>> +                     pm_runtime_suspend(&pci->dev);
>
> Is this meant as pm_runtime_resume()?
>

Oh probably that seems likely alright!

Dave.


More information about the dri-devel mailing list