提交 ef2ef5bc 编写于 作者: T Takashi Iwai 提交者: Zheng Zengkai

ALSA: hda/realtek: Fix deadlock by COEF mutex

stable inclusion
from stable-v5.10.102
commit 63b1602c2fd5af84f3fc4eec64d93298237c791e
bugzilla: https://gitee.com/openeuler/kernel/issues/I567K6

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=63b1602c2fd5af84f3fc4eec64d93298237c791e

--------------------------------

commit 2a845837 upstream.

The recently introduced coef_mutex for Realtek codec seems causing a
deadlock when the relevant code is invoked from the power-off state;
then the HD-audio core tries to power-up internally, and this kicks
off the codec runtime PM code that tries to take the same coef_mutex.

In order to avoid the deadlock, do the temporary power up/down around
the coef_mutex acquisition and release.  This assures that the
power-up sequence runs before the mutex, hence no re-entrance will
happen.

Fixes: b837a9f5 ("ALSA: hda: realtek: Fix race at concurrent COEF updates")
Reported-and-tested-by: NJulian Wollrath <jwollrath@web.de>
Cc: <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20220214132838.4db10fca@schienar
Link: https://lore.kernel.org/r/20220214130410.21230-1-tiwai@suse.deSigned-off-by: NTakashi Iwai <tiwai@suse.de>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NYu Liao <liaoyu15@huawei.com>
Reviewed-by: NWei Li <liwei391@huawei.com>
Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
上级 87a1e3be
...@@ -134,6 +134,22 @@ struct alc_spec { ...@@ -134,6 +134,22 @@ struct alc_spec {
* COEF access helper functions * COEF access helper functions
*/ */
static void coef_mutex_lock(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
snd_hda_power_up_pm(codec);
mutex_lock(&spec->coef_mutex);
}
static void coef_mutex_unlock(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
mutex_unlock(&spec->coef_mutex);
snd_hda_power_down_pm(codec);
}
static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid, static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
unsigned int coef_idx) unsigned int coef_idx)
{ {
...@@ -147,12 +163,11 @@ static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid, ...@@ -147,12 +163,11 @@ static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid, static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
unsigned int coef_idx) unsigned int coef_idx)
{ {
struct alc_spec *spec = codec->spec;
unsigned int val; unsigned int val;
mutex_lock(&spec->coef_mutex); coef_mutex_lock(codec);
val = __alc_read_coefex_idx(codec, nid, coef_idx); val = __alc_read_coefex_idx(codec, nid, coef_idx);
mutex_unlock(&spec->coef_mutex); coef_mutex_unlock(codec);
return val; return val;
} }
...@@ -169,11 +184,9 @@ static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, ...@@ -169,11 +184,9 @@ static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
unsigned int coef_idx, unsigned int coef_val) unsigned int coef_idx, unsigned int coef_val)
{ {
struct alc_spec *spec = codec->spec; coef_mutex_lock(codec);
mutex_lock(&spec->coef_mutex);
__alc_write_coefex_idx(codec, nid, coef_idx, coef_val); __alc_write_coefex_idx(codec, nid, coef_idx, coef_val);
mutex_unlock(&spec->coef_mutex); coef_mutex_unlock(codec);
} }
#define alc_write_coef_idx(codec, coef_idx, coef_val) \ #define alc_write_coef_idx(codec, coef_idx, coef_val) \
...@@ -194,11 +207,9 @@ static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid, ...@@ -194,11 +207,9 @@ static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
unsigned int coef_idx, unsigned int mask, unsigned int coef_idx, unsigned int mask,
unsigned int bits_set) unsigned int bits_set)
{ {
struct alc_spec *spec = codec->spec; coef_mutex_lock(codec);
mutex_lock(&spec->coef_mutex);
__alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set); __alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set);
mutex_unlock(&spec->coef_mutex); coef_mutex_unlock(codec);
} }
#define alc_update_coef_idx(codec, coef_idx, mask, bits_set) \ #define alc_update_coef_idx(codec, coef_idx, mask, bits_set) \
...@@ -231,9 +242,7 @@ struct coef_fw { ...@@ -231,9 +242,7 @@ struct coef_fw {
static void alc_process_coef_fw(struct hda_codec *codec, static void alc_process_coef_fw(struct hda_codec *codec,
const struct coef_fw *fw) const struct coef_fw *fw)
{ {
struct alc_spec *spec = codec->spec; coef_mutex_lock(codec);
mutex_lock(&spec->coef_mutex);
for (; fw->nid; fw++) { for (; fw->nid; fw++) {
if (fw->mask == (unsigned short)-1) if (fw->mask == (unsigned short)-1)
__alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val); __alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
...@@ -241,7 +250,7 @@ static void alc_process_coef_fw(struct hda_codec *codec, ...@@ -241,7 +250,7 @@ static void alc_process_coef_fw(struct hda_codec *codec,
__alc_update_coefex_idx(codec, fw->nid, fw->idx, __alc_update_coefex_idx(codec, fw->nid, fw->idx,
fw->mask, fw->val); fw->mask, fw->val);
} }
mutex_unlock(&spec->coef_mutex); coef_mutex_unlock(codec);
} }
/* /*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册