Skip to content

Commit

Permalink
ALSA: hda - Manage power well properly for resume
Browse files Browse the repository at this point in the history
For SKL and later Intel chips, we control the power well per codec
basis via link_power callback since the commit [03b135c: ALSA:
hda - remove dependency on i915 power well for SKL].
However, there are a few exceptional cases where the gfx registers are
accessed from the audio driver: namely the wakeup override bit
toggling at (both system and runtime) resume.  This seems causing a
kernel warning when accessed during the power well down (and likely
resulting in the bogus register accesses).

This patch puts the proper power up / down sequence around the resume
code so that the wakeup bit is fiddled properly while the power is
up.  (The other callback, sync_audio_rate, is used only in the PCM
callback, so it's guaranteed in the power-on.)

Also, by this proper power up/down, the instantaneous flip of wakeup
bit in the resume callback that was introduced by the commit
[033ea34: ALSA: hda - Fix Skylake codec timeout] becomes
superfluous, as snd_hdac_display_power() already does it.  So we can
clean it up together.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=96214
Fixes: 03b135c ('ALSA: hda - remove dependency on i915 power well for SKL')
Cc: <stable@vger.kernel.org> # v4.2+
Tested-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Takashi Iwai committed Aug 10, 2016
1 parent 41f5e3b commit a52ff34
Showing 1 changed file with 20 additions and 12 deletions.
32 changes: 20 additions & 12 deletions sound/pci/hda/hda_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -906,20 +906,23 @@ static int azx_resume(struct device *dev)
struct snd_card *card = dev_get_drvdata(dev);
struct azx *chip;
struct hda_intel *hda;
struct hdac_bus *bus;

if (!card)
return 0;

chip = card->private_data;
hda = container_of(chip, struct hda_intel, chip);
bus = azx_bus(chip);
if (chip->disabled || hda->init_failed || !chip->running)
return 0;

if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL
&& hda->need_i915_power) {
snd_hdac_display_power(azx_bus(chip), true);
snd_hdac_i915_set_bclk(azx_bus(chip));
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
snd_hdac_display_power(bus, true);
if (hda->need_i915_power)
snd_hdac_i915_set_bclk(bus);
}

if (chip->msi)
if (pci_enable_msi(pci) < 0)
chip->msi = 0;
Expand All @@ -929,6 +932,11 @@ static int azx_resume(struct device *dev)

hda_intel_init_chip(chip, true);

/* power down again for link-controlled chips */
if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
!hda->need_i915_power)
snd_hdac_display_power(bus, false);

snd_power_change_state(card, SNDRV_CTL_POWER_D0);

trace_azx_resume(chip);
Expand Down Expand Up @@ -1008,22 +1016,17 @@ static int azx_runtime_resume(struct device *dev)

chip = card->private_data;
hda = container_of(chip, struct hda_intel, chip);
bus = azx_bus(chip);
if (chip->disabled || hda->init_failed)
return 0;

if (!azx_has_pm_runtime(chip))
return 0;

if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
bus = azx_bus(chip);
if (hda->need_i915_power) {
snd_hdac_display_power(bus, true);
snd_hdac_display_power(bus, true);
if (hda->need_i915_power)
snd_hdac_i915_set_bclk(bus);
} else {
/* toggle codec wakeup bit for STATESTS read */
snd_hdac_set_codec_wakeup(bus, true);
snd_hdac_set_codec_wakeup(bus, false);
}
}

/* Read STATESTS before controller reset */
Expand All @@ -1043,6 +1046,11 @@ static int azx_runtime_resume(struct device *dev)
azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) &
~STATESTS_INT_MASK);

/* power down again for link-controlled chips */
if ((chip->driver_caps & AZX_DCAPS_I915_POWERWELL) &&
!hda->need_i915_power)
snd_hdac_display_power(bus, false);

trace_azx_runtime_resume(chip);
return 0;
}
Expand Down

0 comments on commit a52ff34

Please sign in to comment.