diff options
author | Takashi Iwai <tiwai@suse.de> | 2019-10-29 16:41:20 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2019-10-30 10:32:37 -0400 |
commit | 302d5a80d232134246032bc4263fd7facdddb8f1 (patch) | |
tree | b36a354c7572ab6773c0f19c968044af9955eed6 | |
parent | 1a7f60b9df614bb36d14dc0c0bc898a31b2b506f (diff) |
ALSA: hda - Fix mutex deadlock in HDMI codec driver
The commit ade49db337a9 ("ALSA: hda/hdmi - Allow audio component for
AMD/ATI and Nvidia HDMI") introduced the spec->pcm_lock mutex lock to
the whole generic_hdmi_init() function for avoiding the race with the
audio component registration. However, this caused a dead lock when
the unsolicited event is handled without the audio component, as the
codec gets runtime-resumed in hdmi_present_sense() which is already
inside the spec->pcm_lock in its caller.
For avoiding this deadlock, add a new mutex only for the audio
component binding that is used in both generic_hdmi_init() and the
audio notifier registration where the jack callbacks are handled /
re-registered.
Fixes: ade49db337a9 ("ALSA: hda/hdmi - Allow audio component for AMD/ATI and Nvidia HDMI")
Reported-and-tested-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://lore.kernel.org/r/s5himo7i89i.wl-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 795cbda32cbb..b72553710ffb 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -145,6 +145,7 @@ struct hdmi_spec { | |||
145 | struct snd_array pins; /* struct hdmi_spec_per_pin */ | 145 | struct snd_array pins; /* struct hdmi_spec_per_pin */ |
146 | struct hdmi_pcm pcm_rec[16]; | 146 | struct hdmi_pcm pcm_rec[16]; |
147 | struct mutex pcm_lock; | 147 | struct mutex pcm_lock; |
148 | struct mutex bind_lock; /* for audio component binding */ | ||
148 | /* pcm_bitmap means which pcms have been assigned to pins*/ | 149 | /* pcm_bitmap means which pcms have been assigned to pins*/ |
149 | unsigned long pcm_bitmap; | 150 | unsigned long pcm_bitmap; |
150 | int pcm_used; /* counter of pcm_rec[] */ | 151 | int pcm_used; /* counter of pcm_rec[] */ |
@@ -2258,7 +2259,7 @@ static int generic_hdmi_init(struct hda_codec *codec) | |||
2258 | struct hdmi_spec *spec = codec->spec; | 2259 | struct hdmi_spec *spec = codec->spec; |
2259 | int pin_idx; | 2260 | int pin_idx; |
2260 | 2261 | ||
2261 | mutex_lock(&spec->pcm_lock); | 2262 | mutex_lock(&spec->bind_lock); |
2262 | spec->use_jack_detect = !codec->jackpoll_interval; | 2263 | spec->use_jack_detect = !codec->jackpoll_interval; |
2263 | for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { | 2264 | for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { |
2264 | struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); | 2265 | struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); |
@@ -2275,7 +2276,7 @@ static int generic_hdmi_init(struct hda_codec *codec) | |||
2275 | snd_hda_jack_detect_enable_callback(codec, pin_nid, | 2276 | snd_hda_jack_detect_enable_callback(codec, pin_nid, |
2276 | jack_callback); | 2277 | jack_callback); |
2277 | } | 2278 | } |
2278 | mutex_unlock(&spec->pcm_lock); | 2279 | mutex_unlock(&spec->bind_lock); |
2279 | return 0; | 2280 | return 0; |
2280 | } | 2281 | } |
2281 | 2282 | ||
@@ -2382,6 +2383,7 @@ static int alloc_generic_hdmi(struct hda_codec *codec) | |||
2382 | spec->ops = generic_standard_hdmi_ops; | 2383 | spec->ops = generic_standard_hdmi_ops; |
2383 | spec->dev_num = 1; /* initialize to 1 */ | 2384 | spec->dev_num = 1; /* initialize to 1 */ |
2384 | mutex_init(&spec->pcm_lock); | 2385 | mutex_init(&spec->pcm_lock); |
2386 | mutex_init(&spec->bind_lock); | ||
2385 | snd_hdac_register_chmap_ops(&codec->core, &spec->chmap); | 2387 | snd_hdac_register_chmap_ops(&codec->core, &spec->chmap); |
2386 | 2388 | ||
2387 | spec->chmap.ops.get_chmap = hdmi_get_chmap; | 2389 | spec->chmap.ops.get_chmap = hdmi_get_chmap; |
@@ -2451,7 +2453,7 @@ static void generic_acomp_notifier_set(struct drm_audio_component *acomp, | |||
2451 | int i; | 2453 | int i; |
2452 | 2454 | ||
2453 | spec = container_of(acomp->audio_ops, struct hdmi_spec, drm_audio_ops); | 2455 | spec = container_of(acomp->audio_ops, struct hdmi_spec, drm_audio_ops); |
2454 | mutex_lock(&spec->pcm_lock); | 2456 | mutex_lock(&spec->bind_lock); |
2455 | spec->use_acomp_notifier = use_acomp; | 2457 | spec->use_acomp_notifier = use_acomp; |
2456 | spec->codec->relaxed_resume = use_acomp; | 2458 | spec->codec->relaxed_resume = use_acomp; |
2457 | /* reprogram each jack detection logic depending on the notifier */ | 2459 | /* reprogram each jack detection logic depending on the notifier */ |
@@ -2461,7 +2463,7 @@ static void generic_acomp_notifier_set(struct drm_audio_component *acomp, | |||
2461 | get_pin(spec, i)->pin_nid, | 2463 | get_pin(spec, i)->pin_nid, |
2462 | use_acomp); | 2464 | use_acomp); |
2463 | } | 2465 | } |
2464 | mutex_unlock(&spec->pcm_lock); | 2466 | mutex_unlock(&spec->bind_lock); |
2465 | } | 2467 | } |
2466 | 2468 | ||
2467 | /* enable / disable the notifier via master bind / unbind */ | 2469 | /* enable / disable the notifier via master bind / unbind */ |