Skip to content

Commit 246efa4

Browse files
committed
snd/hda: add runtime suspend/resume on optimus support (v4)
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. v2: fix incorrect runtime call suspend->resume. v3: rework irq handler to avoid false irq when we are resuming but haven't runtime resumed yet, don't bother trying D3cold, it won't work, just set it manually ourselves, move runtime s/r calls outside the main s/r hook. enable dnyamic pm properly by dropping reference. v4: put back irq handler check just wrap it with cap check Acked-by: Takashi Iwai <[email protected]> Signed-off-by: Dave Airlie <[email protected]>
1 parent 0d69704 commit 246efa4

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

sound/pci/hda/hda_intel.c

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,9 @@ struct azx {
555555
#ifdef CONFIG_SND_HDA_DSP_LOADER
556556
struct azx_dev saved_azx_dev;
557557
#endif
558+
559+
/* secondary power domain for hdmi audio under vga device */
560+
struct dev_pm_domain hdmi_pm_domain;
558561
};
559562

560563
#define CREATE_TRACE_POINTS
@@ -1397,8 +1400,9 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
13971400
int i, ok;
13981401

13991402
#ifdef CONFIG_PM_RUNTIME
1400-
if (chip->pci->dev.power.runtime_status != RPM_ACTIVE)
1401-
return IRQ_NONE;
1403+
if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
1404+
if (chip->pci->dev.power.runtime_status != RPM_ACTIVE)
1405+
return IRQ_NONE;
14021406
#endif
14031407

14041408
spin_lock(&chip->reg_lock);
@@ -1409,7 +1413,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
14091413
}
14101414

14111415
status = azx_readl(chip, INTSTS);
1412-
if (status == 0) {
1416+
if (status == 0 || status == 0xffffffff) {
14131417
spin_unlock(&chip->reg_lock);
14141418
return IRQ_NONE;
14151419
}
@@ -2971,6 +2975,12 @@ static int azx_runtime_suspend(struct device *dev)
29712975
struct snd_card *card = dev_get_drvdata(dev);
29722976
struct azx *chip = card->private_data;
29732977

2978+
if (chip->disabled)
2979+
return 0;
2980+
2981+
if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
2982+
return 0;
2983+
29742984
azx_stop_chip(chip);
29752985
azx_enter_link_reset(chip);
29762986
azx_clear_irq_pending(chip);
@@ -2984,6 +2994,12 @@ static int azx_runtime_resume(struct device *dev)
29842994
struct snd_card *card = dev_get_drvdata(dev);
29852995
struct azx *chip = card->private_data;
29862996

2997+
if (chip->disabled)
2998+
return 0;
2999+
3000+
if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
3001+
return 0;
3002+
29873003
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
29883004
hda_display_power(true);
29893005
azx_init_pci(chip);
@@ -2996,6 +3012,9 @@ static int azx_runtime_idle(struct device *dev)
29963012
struct snd_card *card = dev_get_drvdata(dev);
29973013
struct azx *chip = card->private_data;
29983014

3015+
if (chip->disabled)
3016+
return 0;
3017+
29993018
if (!power_save_controller ||
30003019
!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
30013020
return -EBUSY;
@@ -3078,13 +3097,19 @@ static void azx_vs_set_state(struct pci_dev *pci,
30783097
"%s: %s via VGA-switcheroo\n", pci_name(chip->pci),
30793098
disabled ? "Disabling" : "Enabling");
30803099
if (disabled) {
3100+
pm_runtime_put_sync_suspend(&pci->dev);
30813101
azx_suspend(&pci->dev);
3102+
/* when we get suspended by vga switcheroo we end up in D3cold,
3103+
* however we have no ACPI handle, so pci/acpi can't put us there,
3104+
* put ourselves there */
3105+
pci->current_state = PCI_D3cold;
30823106
chip->disabled = true;
30833107
if (snd_hda_lock_devices(chip->bus))
30843108
snd_printk(KERN_WARNING SFX "%s: Cannot lock devices!\n",
30853109
pci_name(chip->pci));
30863110
} else {
30873111
snd_hda_unlock_devices(chip->bus);
3112+
pm_runtime_get_noresume(&pci->dev);
30883113
chip->disabled = false;
30893114
azx_resume(&pci->dev);
30903115
}
@@ -3139,6 +3164,9 @@ static int register_vga_switcheroo(struct azx *chip)
31393164
if (err < 0)
31403165
return err;
31413166
chip->vga_switcheroo_registered = 1;
3167+
3168+
/* register as an optimus hdmi audio power domain */
3169+
vga_switcheroo_init_domain_pm_optimus_hdmi_audio(&chip->pci->dev, &chip->hdmi_pm_domain);
31423170
return 0;
31433171
}
31443172
#else
@@ -3887,7 +3915,7 @@ static int azx_probe_continue(struct azx *chip)
38873915
power_down_all_codecs(chip);
38883916
azx_notifier_register(chip);
38893917
azx_add_card_list(chip);
3890-
if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
3918+
if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) || chip->use_vga_switcheroo)
38913919
pm_runtime_put_noidle(&pci->dev);
38923920

38933921
return 0;

0 commit comments

Comments
 (0)