[PATCH 0/3] ALSA: hda: Forcibly suspend codec at shutdown
Hi,
this is a patch set for fixing the issue at shutdown/reboot with HD-audio. The recent regression report brought me to check the shutdown code execution and it turned out that we don't do right for the codec shutdown while powering off the controller side. As a simple but big-hammer solution, this changes the codec driver's shutdown callback to forcibly (runtime-)suspend. It assures the proper power-off and the mute, as done at the usual suspend/resume.
Currently my plan is to apply this for 5.15, as the impact is significant and it's a bit too late for 5.14 shortly before the final.
Takashi
===
Takashi Iwai (3): ALSA: hda: conexant: Turn off EAPD at suspend, too ALSA: hda: Suspend codec at shutdown ALSA: hda: Nuke unused reboot_notify callback
include/sound/hda_codec.h | 1 - sound/pci/hda/hda_bind.c | 8 +------- sound/pci/hda/hda_codec.c | 14 ++++++++++++++ sound/pci/hda/hda_generic.c | 19 ------------------- sound/pci/hda/hda_generic.h | 1 - sound/pci/hda/hda_local.h | 2 ++ sound/pci/hda/patch_analog.c | 1 - sound/pci/hda/patch_ca0132.c | 6 ------ sound/pci/hda/patch_conexant.c | 15 +++++++++++---- sound/pci/hda/patch_realtek.c | 13 ------------- sound/pci/hda/patch_sigmatel.c | 1 - 11 files changed, 28 insertions(+), 53 deletions(-)
Conexant codecs have a workaround for the noise at shutdown to turn off EAPD, but it wasn't applied at suspend. In the later patch, we'll switch from reboot_notify callback to the general suspend-at-shutdown, so let's apply the workaround to the suspend case, too.
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=214045 Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/patch_conexant.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index d111258c6f45..6d2bdef7f017 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -177,13 +177,18 @@ static int cx_auto_init(struct hda_codec *codec) return 0; }
-static void cx_auto_reboot_notify(struct hda_codec *codec) +static void cx_auto_shutdown(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec;
/* Turn the problematic codec into D3 to avoid spurious noises from the internal speaker during (and after) reboot */ cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false); +} + +static void cx_auto_reboot_notify(struct hda_codec *codec) +{ + cx_auto_shutdown(codec); snd_hda_gen_reboot_notify(codec); }
@@ -193,6 +198,14 @@ static void cx_auto_free(struct hda_codec *codec) snd_hda_gen_free(codec); }
+#ifdef CONFIG_PM +static int cx_auto_suspend(struct hda_codec *codec) +{ + cx_auto_shutdown(codec); + return 0; +} +#endif + static const struct hda_codec_ops cx_auto_patch_ops = { .build_controls = snd_hda_gen_build_controls, .build_pcms = snd_hda_gen_build_pcms, @@ -201,6 +214,7 @@ static const struct hda_codec_ops cx_auto_patch_ops = { .free = cx_auto_free, .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM + .suspend = cx_auto_suspend, .check_power_status = snd_hda_gen_check_power_status, #endif };
So far we have a few workarounds at shutdown for each codec, e.g. turning off the display power and setting the codec to D3. But all those are basically a part of the suspend procedure. Moreover, the streams are still active after that call, hence it might hit the update on the codec that has been already put to D3.
In this patch, instead of calling each reboot_notify callback, simply put the codec into the runtime-suspended state after the manual suspend of all PCM streams. It makes the code and the behavior more consistent.
The reboot_notify callback is no longer used after this patch, and will be cleaned up later.
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=214045 Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/pci/hda/hda_bind.c | 8 +------- sound/pci/hda/hda_codec.c | 14 ++++++++++++++ sound/pci/hda/hda_local.h | 2 ++ 3 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index e8dee24c309d..2523b23389e9 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -165,13 +165,7 @@ static int hda_codec_driver_remove(struct device *dev)
static void hda_codec_driver_shutdown(struct device *dev) { - struct hda_codec *codec = dev_to_hda_codec(dev); - - if (!pm_runtime_suspended(dev)) { - if (codec->patch_ops.reboot_notify) - codec->patch_ops.reboot_notify(codec); - snd_hda_codec_display_power(codec, false); - } + snd_hda_codec_shutdown(dev_to_hda_codec(dev)); }
int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 7a717e151156..2c91c92c9ab2 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2981,6 +2981,20 @@ const struct dev_pm_ops hda_codec_driver_pm = { NULL) };
+/* suspend the codec at shutdown; called from driver's shutdown callback */ +void snd_hda_codec_shutdown(struct hda_codec *codec) +{ + struct hda_pcm *cpcm; + + if (pm_runtime_suspended(hda_codec_dev(codec))) + return; + + list_for_each_entry(cpcm, &codec->pcm_list_head, list) + snd_pcm_suspend_all(cpcm->pcm); + + pm_runtime_suspend(hda_codec_dev(codec)); +} + /* * add standard channel maps if not specified */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 8d2503e8dad8..ea8ab8b43337 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -615,6 +615,8 @@ unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec, hda_nid_t nid, unsigned int power_state);
+void snd_hda_codec_shutdown(struct hda_codec *codec); + /* * AMP control callbacks */
As reboot_notify callback is no longer used by the codec core, let's get rid of the unused code. Conexant codec needs a slight code change as it used to call the reboot_notify at the codec removal, too.
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=214045 Signed-off-by: Takashi Iwai tiwai@suse.de --- include/sound/hda_codec.h | 1 - sound/pci/hda/hda_generic.c | 19 ------------------- sound/pci/hda/hda_generic.h | 1 - sound/pci/hda/patch_analog.c | 1 - sound/pci/hda/patch_ca0132.c | 6 ------ sound/pci/hda/patch_conexant.c | 9 +-------- sound/pci/hda/patch_realtek.c | 13 ------------- sound/pci/hda/patch_sigmatel.c | 1 - 8 files changed, 1 insertion(+), 50 deletions(-)
diff --git a/include/sound/hda_codec.h b/include/sound/hda_codec.h index 2e8d51937acd..01570dbda503 100644 --- a/include/sound/hda_codec.h +++ b/include/sound/hda_codec.h @@ -114,7 +114,6 @@ struct hda_codec_ops { int (*resume)(struct hda_codec *codec); int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid); #endif - void (*reboot_notify)(struct hda_codec *codec); void (*stream_pm)(struct hda_codec *codec, hda_nid_t nid, bool on); };
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index e97d00585e8e..f46d4e7f499c 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -6000,24 +6000,6 @@ void snd_hda_gen_free(struct hda_codec *codec) } EXPORT_SYMBOL_GPL(snd_hda_gen_free);
-/** - * snd_hda_gen_reboot_notify - Make codec enter D3 before rebooting - * @codec: the HDA codec - * - * This can be put as patch_ops reboot_notify function. - */ -void snd_hda_gen_reboot_notify(struct hda_codec *codec) -{ - /* Make the codec enter D3 to avoid spurious noises from the internal - * speaker during (and after) reboot - */ - snd_hda_codec_set_power_to_all(codec, codec->core.afg, AC_PWRST_D3); - snd_hda_codec_write(codec, codec->core.afg, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - msleep(10); -} -EXPORT_SYMBOL_GPL(snd_hda_gen_reboot_notify); - #ifdef CONFIG_PM /** * snd_hda_gen_check_power_status - check the loopback power save state @@ -6045,7 +6027,6 @@ static const struct hda_codec_ops generic_patch_ops = { .init = snd_hda_gen_init, .free = snd_hda_gen_free, .unsol_event = snd_hda_jack_unsol_event, - .reboot_notify = snd_hda_gen_reboot_notify, #ifdef CONFIG_PM .check_power_status = snd_hda_gen_check_power_status, #endif diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index d4dd1b8a2e7e..c43bd0f0338e 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -324,7 +324,6 @@ int snd_hda_gen_parse_auto_config(struct hda_codec *codec, struct auto_pin_cfg *cfg); int snd_hda_gen_build_controls(struct hda_codec *codec); int snd_hda_gen_build_pcms(struct hda_codec *codec); -void snd_hda_gen_reboot_notify(struct hda_codec *codec);
/* standard jack event callbacks */ void snd_hda_gen_hp_automute(struct hda_codec *codec, diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 2132b2acec4d..a356e1662929 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -168,7 +168,6 @@ static const struct hda_codec_ops ad198x_auto_patch_ops = { .check_power_status = snd_hda_gen_check_power_status, .suspend = ad198x_suspend, #endif - .reboot_notify = ad198x_shutup, };
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 50ca72ee586e..208933792787 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -9682,11 +9682,6 @@ static void dbpro_free(struct hda_codec *codec) kfree(codec->spec); }
-static void ca0132_reboot_notify(struct hda_codec *codec) -{ - codec->patch_ops.free(codec); -} - #ifdef CONFIG_PM static int ca0132_suspend(struct hda_codec *codec) { @@ -9706,7 +9701,6 @@ static const struct hda_codec_ops ca0132_patch_ops = { #ifdef CONFIG_PM .suspend = ca0132_suspend, #endif - .reboot_notify = ca0132_reboot_notify, };
static const struct hda_codec_ops dbpro_patch_ops = { diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 6d2bdef7f017..0515137a75b0 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -186,15 +186,9 @@ static void cx_auto_shutdown(struct hda_codec *codec) cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false); }
-static void cx_auto_reboot_notify(struct hda_codec *codec) -{ - cx_auto_shutdown(codec); - snd_hda_gen_reboot_notify(codec); -} - static void cx_auto_free(struct hda_codec *codec) { - cx_auto_reboot_notify(codec); + cx_auto_shutdown(codec); snd_hda_gen_free(codec); }
@@ -210,7 +204,6 @@ static const struct hda_codec_ops cx_auto_patch_ops = { .build_controls = snd_hda_gen_build_controls, .build_pcms = snd_hda_gen_build_pcms, .init = cx_auto_init, - .reboot_notify = cx_auto_reboot_notify, .free = cx_auto_free, .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4043a2362f27..4f2296d062d5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -109,7 +109,6 @@ struct alc_spec { void (*power_hook)(struct hda_codec *codec); #endif void (*shutup)(struct hda_codec *codec); - void (*reboot_notify)(struct hda_codec *codec);
int init_amp; int codec_variant; /* flag for other variants */ @@ -897,16 +896,6 @@ static inline void alc_shutup(struct hda_codec *codec) alc_shutup_pins(codec); }
-static void alc_reboot_notify(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (spec && spec->reboot_notify) - spec->reboot_notify(codec); - else - alc_shutup(codec); -} - #define alc_free snd_hda_gen_free
#ifdef CONFIG_PM @@ -952,7 +941,6 @@ static const struct hda_codec_ops alc_patch_ops = { .suspend = alc_suspend, .check_power_status = snd_hda_gen_check_power_status, #endif - .reboot_notify = alc_reboot_notify, };
@@ -5773,7 +5761,6 @@ static void alc_fixup_tpt440_dock(struct hda_codec *codec, struct alc_spec *spec = codec->spec;
if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->reboot_notify = snd_hda_gen_reboot_notify; /* reduce noise */ spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; codec->power_save_node = 0; /* avoid click noises */ snd_hda_apply_pincfgs(codec, pincfgs); diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3bd592e126a3..3e00116db86e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4460,7 +4460,6 @@ static const struct hda_codec_ops stac_patch_ops = { #ifdef CONFIG_PM .suspend = stac_suspend, #endif - .reboot_notify = stac_shutup, };
static int alloc_stac_spec(struct hda_codec *codec)
participants (1)
-
Takashi Iwai