Skip to content

Commit 2a84583

Browse files
committed
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: b837a9f ("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>
1 parent 9a5adeb commit 2a84583

1 file changed

Lines changed: 24 additions & 15 deletions

File tree

sound/pci/hda/patch_realtek.c

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,22 @@ struct alc_spec {
138138
* COEF access helper functions
139139
*/
140140

141+
static void coef_mutex_lock(struct hda_codec *codec)
142+
{
143+
struct alc_spec *spec = codec->spec;
144+
145+
snd_hda_power_up_pm(codec);
146+
mutex_lock(&spec->coef_mutex);
147+
}
148+
149+
static void coef_mutex_unlock(struct hda_codec *codec)
150+
{
151+
struct alc_spec *spec = codec->spec;
152+
153+
mutex_unlock(&spec->coef_mutex);
154+
snd_hda_power_down_pm(codec);
155+
}
156+
141157
static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
142158
unsigned int coef_idx)
143159
{
@@ -151,12 +167,11 @@ static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
151167
static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
152168
unsigned int coef_idx)
153169
{
154-
struct alc_spec *spec = codec->spec;
155170
unsigned int val;
156171

157-
mutex_lock(&spec->coef_mutex);
172+
coef_mutex_lock(codec);
158173
val = __alc_read_coefex_idx(codec, nid, coef_idx);
159-
mutex_unlock(&spec->coef_mutex);
174+
coef_mutex_unlock(codec);
160175
return val;
161176
}
162177

@@ -173,11 +188,9 @@ static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
173188
static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
174189
unsigned int coef_idx, unsigned int coef_val)
175190
{
176-
struct alc_spec *spec = codec->spec;
177-
178-
mutex_lock(&spec->coef_mutex);
191+
coef_mutex_lock(codec);
179192
__alc_write_coefex_idx(codec, nid, coef_idx, coef_val);
180-
mutex_unlock(&spec->coef_mutex);
193+
coef_mutex_unlock(codec);
181194
}
182195

183196
#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,
198211
unsigned int coef_idx, unsigned int mask,
199212
unsigned int bits_set)
200213
{
201-
struct alc_spec *spec = codec->spec;
202-
203-
mutex_lock(&spec->coef_mutex);
214+
coef_mutex_lock(codec);
204215
__alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set);
205-
mutex_unlock(&spec->coef_mutex);
216+
coef_mutex_unlock(codec);
206217
}
207218

208219
#define alc_update_coef_idx(codec, coef_idx, mask, bits_set) \
@@ -235,17 +246,15 @@ struct coef_fw {
235246
static void alc_process_coef_fw(struct hda_codec *codec,
236247
const struct coef_fw *fw)
237248
{
238-
struct alc_spec *spec = codec->spec;
239-
240-
mutex_lock(&spec->coef_mutex);
249+
coef_mutex_lock(codec);
241250
for (; fw->nid; fw++) {
242251
if (fw->mask == (unsigned short)-1)
243252
__alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
244253
else
245254
__alc_update_coefex_idx(codec, fw->nid, fw->idx,
246255
fw->mask, fw->val);
247256
}
248-
mutex_unlock(&spec->coef_mutex);
257+
coef_mutex_unlock(codec);
249258
}
250259

251260
/*

0 commit comments

Comments
 (0)