[alsa-devel] HDA controller w/o CLKSTOP and EPSS support

Takashi Iwai tiwai at suse.de
Wed Jun 20 12:14:32 CEST 2018


On Wed, 20 Jun 2018 11:34:52 +0200,
Lukas Wunner wrote:
> 
> Hi Takashi,
> 
> Henning Kühn reports that due to my commit 07f4f97d7b4b ("vga_switcheroo:
> Use device link for HDA controller"), the discrete GPU on his hybrid
> graphics laptop no longer runtime suspends.
> 
> The root cause is that the single codec of the GPU's HDA controller
> doesn't support CLKSTOP and EPSS.  (The "Supported Power States" are
> 0x00000009, i.e. CLKSTOP and EPSS bits are not set, cf. page 209 of
> the HDA spec.)
> 
> This means that in hda_codec_runtime_suspend() we do not call
> snd_hdac_codec_link_down():
> 
> 	if (codec_has_clkstop(codec) && codec_has_epss(codec) &&
> 	    (state & AC_PWRST_CLK_STOP_OK))
> 		snd_hdac_codec_link_down(&codec->core);
> 
> If snd_hdac_codec_link_down() isn't called, the bit in the codec_powered
> bitmask isn't cleared, which in turn prevents the controller from going
> to PCI_D3hot in azx_runtime_idle():
> 
> 	if (!power_save_controller || !azx_has_pm_runtime(chip) ||
> 	    azx_bus(chip)->codec_powered || !chip->running)
> 		return -EBUSY;
> 
> The codec does runtime suspend to D3, but the PS-ClkStopOk bit in the
> response to "Get Power State" is not set. (Response is 0x00000033,
> cf. page 151 of the HD Audio spec.)  Hence the check above
> "state & AC_PWRST_CLK_STOP_OK" also results in "false".
> 
> I'm not familiar enough with the intricacies of the HD Audio spec to
> fully comprehend the implications of missing EPSS and CLKSTOP support
> and to come up with a fix.  We could quirk any HDA controller in a
> vga_switcheroo setup to ignore missing EPSS and CLKSTOP support, but
> would that be safe?  E.g. the spec says that if the bus clock does stop,
> "a full reset shall be performed" when the clock is reenabled.  Are we
> handling this correctly?

I guess it would work with a quirk.  The EPSS and CLKSTOP checks are
just to assure the modern codec PM, and GPU is always exceptional.

Supposing that it's AMD GPU, does a fix like below work?


thanks,

Takashi

-- 8< --
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -2899,8 +2899,9 @@ static int hda_codec_runtime_suspend(struct device *dev)
 	list_for_each_entry(pcm, &codec->pcm_list_head, list)
 		snd_pcm_suspend_all(pcm->pcm);
 	state = hda_call_codec_suspend(codec);
-	if (codec_has_clkstop(codec) && codec_has_epss(codec) &&
-	    (state & AC_PWRST_CLK_STOP_OK))
+	if (codec->link_down_at_suspend ||
+	    (codec_has_clkstop(codec) && codec_has_epss(codec) &&
+	     (state & AC_PWRST_CLK_STOP_OK)))
 		snd_hdac_codec_link_down(&codec->core);
 	snd_hdac_link_power(&codec->core, false);
 	return 0;
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 681c360f29f9..5b00c1eb857e 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -258,6 +258,7 @@ struct hda_codec {
 	unsigned int power_save_node:1; /* advanced PM for each widget */
 	unsigned int auto_runtime_pm:1; /* enable automatic codec runtime pm */
 	unsigned int force_pin_prefix:1; /* Add location prefix */
+	unsigned int link_down_at_suspend:1; /* force to link down at suspend */
 #ifdef CONFIG_PM
 	unsigned long power_on_acct;
 	unsigned long power_off_acct;
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 8840daf9c6a3..98e1c411c56a 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -3741,6 +3741,11 @@ static int patch_atihdmi(struct hda_codec *codec)
 
 	spec->chmap.channels_max = max(spec->chmap.channels_max, 8u);
 
+	/* AMD GPUs have neither EPSS nor CLKSTOP bits, hence preventing
+	 * the link-down as is.  Tell the core to allow it.
+	 */
+	codec->link_down_at_suspend = 1;
+
 	return 0;
 }
 


More information about the Alsa-devel mailing list