summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2022-02-14 14:04:10 +0100
committerTakashi Iwai <tiwai@suse.de>2022-02-14 14:04:48 +0100
commit2a845837e3d0ddaed493b4c5c4643d7f0542804d (patch)
tree223ca9fc213b8715868a1042ca6c752fd88bd0be /sound
parent9a5adeb28b77416446658e75bdef3bbe5fb92a83 (diff)
ALSA: hda/realtek: Fix deadlock by COEF mutex
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: b837a9f5ab3b ("ALSA: hda: realtek: Fix race at concurrent COEF updates") Reported-and-tested-by: Julian 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.de Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/patch_realtek.c39
1 files changed, 24 insertions, 15 deletions
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 9473fb76ff19..3a42457984e9 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -138,6 +138,22 @@ struct alc_spec {
* 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,
unsigned int coef_idx)
{
@@ -151,12 +167,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,
unsigned int coef_idx)
{
- struct alc_spec *spec = codec->spec;
unsigned int val;
- mutex_lock(&spec->coef_mutex);
+ coef_mutex_lock(codec);
val = __alc_read_coefex_idx(codec, nid, coef_idx);
- mutex_unlock(&spec->coef_mutex);
+ coef_mutex_unlock(codec);
return val;
}
@@ -173,11 +188,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,
unsigned int coef_idx, unsigned int coef_val)
{
- struct alc_spec *spec = codec->spec;
-
- mutex_lock(&spec->coef_mutex);
+ coef_mutex_lock(codec);
__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) \
@@ -198,11 +211,9 @@ static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
unsigned int coef_idx, unsigned int mask,
unsigned int bits_set)
{
- struct alc_spec *spec = codec->spec;
-
- mutex_lock(&spec->coef_mutex);
+ coef_mutex_lock(codec);
__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) \
@@ -235,9 +246,7 @@ struct coef_fw {
static void alc_process_coef_fw(struct hda_codec *codec,
const struct coef_fw *fw)
{
- struct alc_spec *spec = codec->spec;
-
- mutex_lock(&spec->coef_mutex);
+ coef_mutex_lock(codec);
for (; fw->nid; fw++) {
if (fw->mask == (unsigned short)-1)
__alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
@@ -245,7 +254,7 @@ static void alc_process_coef_fw(struct hda_codec *codec,
__alc_update_coefex_idx(codec, fw->nid, fw->idx,
fw->mask, fw->val);
}
- mutex_unlock(&spec->coef_mutex);
+ coef_mutex_unlock(codec);
}
/*