aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorDave Airlie <airlied@gmail.com>2013-07-29 01:19:29 -0400
committerDave Airlie <airlied@redhat.com>2013-08-28 23:30:29 -0400
commit246efa4a072f3a2e03010ef0b78b0974ec69c377 (patch)
treeea81a248b4578ef9e159ccbdec382f7a669978c7 /sound
parent0d69704ae348c03bc216b01e32a0e9a2372be419 (diff)
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 <tiwai@suse.de> Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/hda_intel.c36
1 files changed, 32 insertions, 4 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 8860dd529520..bf5e58ec1efe 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -555,6 +555,9 @@ struct azx {
555#ifdef CONFIG_SND_HDA_DSP_LOADER 555#ifdef CONFIG_SND_HDA_DSP_LOADER
556 struct azx_dev saved_azx_dev; 556 struct azx_dev saved_azx_dev;
557#endif 557#endif
558
559 /* secondary power domain for hdmi audio under vga device */
560 struct dev_pm_domain hdmi_pm_domain;
558}; 561};
559 562
560#define CREATE_TRACE_POINTS 563#define CREATE_TRACE_POINTS
@@ -1397,8 +1400,9 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
1397 int i, ok; 1400 int i, ok;
1398 1401
1399#ifdef CONFIG_PM_RUNTIME 1402#ifdef CONFIG_PM_RUNTIME
1400 if (chip->pci->dev.power.runtime_status != RPM_ACTIVE) 1403 if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
1401 return IRQ_NONE; 1404 if (chip->pci->dev.power.runtime_status != RPM_ACTIVE)
1405 return IRQ_NONE;
1402#endif 1406#endif
1403 1407
1404 spin_lock(&chip->reg_lock); 1408 spin_lock(&chip->reg_lock);
@@ -1409,7 +1413,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
1409 } 1413 }
1410 1414
1411 status = azx_readl(chip, INTSTS); 1415 status = azx_readl(chip, INTSTS);
1412 if (status == 0) { 1416 if (status == 0 || status == 0xffffffff) {
1413 spin_unlock(&chip->reg_lock); 1417 spin_unlock(&chip->reg_lock);
1414 return IRQ_NONE; 1418 return IRQ_NONE;
1415 } 1419 }
@@ -2971,6 +2975,12 @@ static int azx_runtime_suspend(struct device *dev)
2971 struct snd_card *card = dev_get_drvdata(dev); 2975 struct snd_card *card = dev_get_drvdata(dev);
2972 struct azx *chip = card->private_data; 2976 struct azx *chip = card->private_data;
2973 2977
2978 if (chip->disabled)
2979 return 0;
2980
2981 if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
2982 return 0;
2983
2974 azx_stop_chip(chip); 2984 azx_stop_chip(chip);
2975 azx_enter_link_reset(chip); 2985 azx_enter_link_reset(chip);
2976 azx_clear_irq_pending(chip); 2986 azx_clear_irq_pending(chip);
@@ -2984,6 +2994,12 @@ static int azx_runtime_resume(struct device *dev)
2984 struct snd_card *card = dev_get_drvdata(dev); 2994 struct snd_card *card = dev_get_drvdata(dev);
2985 struct azx *chip = card->private_data; 2995 struct azx *chip = card->private_data;
2986 2996
2997 if (chip->disabled)
2998 return 0;
2999
3000 if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
3001 return 0;
3002
2987 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) 3003 if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
2988 hda_display_power(true); 3004 hda_display_power(true);
2989 azx_init_pci(chip); 3005 azx_init_pci(chip);
@@ -2996,6 +3012,9 @@ static int azx_runtime_idle(struct device *dev)
2996 struct snd_card *card = dev_get_drvdata(dev); 3012 struct snd_card *card = dev_get_drvdata(dev);
2997 struct azx *chip = card->private_data; 3013 struct azx *chip = card->private_data;
2998 3014
3015 if (chip->disabled)
3016 return 0;
3017
2999 if (!power_save_controller || 3018 if (!power_save_controller ||
3000 !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) 3019 !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
3001 return -EBUSY; 3020 return -EBUSY;
@@ -3078,13 +3097,19 @@ static void azx_vs_set_state(struct pci_dev *pci,
3078 "%s: %s via VGA-switcheroo\n", pci_name(chip->pci), 3097 "%s: %s via VGA-switcheroo\n", pci_name(chip->pci),
3079 disabled ? "Disabling" : "Enabling"); 3098 disabled ? "Disabling" : "Enabling");
3080 if (disabled) { 3099 if (disabled) {
3100 pm_runtime_put_sync_suspend(&pci->dev);
3081 azx_suspend(&pci->dev); 3101 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;
3082 chip->disabled = true; 3106 chip->disabled = true;
3083 if (snd_hda_lock_devices(chip->bus)) 3107 if (snd_hda_lock_devices(chip->bus))
3084 snd_printk(KERN_WARNING SFX "%s: Cannot lock devices!\n", 3108 snd_printk(KERN_WARNING SFX "%s: Cannot lock devices!\n",
3085 pci_name(chip->pci)); 3109 pci_name(chip->pci));
3086 } else { 3110 } else {
3087 snd_hda_unlock_devices(chip->bus); 3111 snd_hda_unlock_devices(chip->bus);
3112 pm_runtime_get_noresume(&pci->dev);
3088 chip->disabled = false; 3113 chip->disabled = false;
3089 azx_resume(&pci->dev); 3114 azx_resume(&pci->dev);
3090 } 3115 }
@@ -3139,6 +3164,9 @@ static int register_vga_switcheroo(struct azx *chip)
3139 if (err < 0) 3164 if (err < 0)
3140 return err; 3165 return err;
3141 chip->vga_switcheroo_registered = 1; 3166 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);
3142 return 0; 3170 return 0;
3143} 3171}
3144#else 3172#else
@@ -3887,7 +3915,7 @@ static int azx_probe_continue(struct azx *chip)
3887 power_down_all_codecs(chip); 3915 power_down_all_codecs(chip);
3888 azx_notifier_register(chip); 3916 azx_notifier_register(chip);
3889 azx_add_card_list(chip); 3917 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)
3891 pm_runtime_put_noidle(&pci->dev); 3919 pm_runtime_put_noidle(&pci->dev);
3892 3920
3893 return 0; 3921 return 0;