Skip to content

Commit 222bde0

Browse files
committed
ALSA: hda - Fix mutex deadlock at HDMI/DP hotplug
The recent change in HD-audio HDMI/DP codec driver for allowing the dynamic PCM binding introduced a new spec->pcm_mutex. One of the protected area by this mutex is hdmi_present_sense(). As reported by Intel CI tests, unfortunately, the new mutex causes a deadlock when the hotplug/unplug is triggered during the codec is in runtime suspend. The buggy code path is like the following: hdmi_unsol_event() -> ... -> hdmi_present_sense() ==> ** here taking pcm_mutex -> hdmi_present_sense_via_verbs() -> snd_hda_power_up_pm() -> ... (runtime resume calls) -> generic_hdmi_resume() -> hdmi_present_sense() ==> ** here taking pcm_mutex again! As we can see here, the problem is that the mutex is taken before snd_hda_power_up_pm() call that triggers the runtime resume. That is, the obvious solution is to move the power up/down call outside the mutex; it is exactly what this patch provides. The patch also clarifies why this bug wasn't caught beforehand. We used to have the i915 audio component for hotplug for all Intel chips, and in that code path, there is no power up required but the information is taken directly from the graphics side. However, we recently switched back to the old method for some old Intel chips due to regressions, and now the deadlock issue is surfaced. Fixes: a76056f ('ALSA: hda - hdmi dynamically bind PCM to pin when monitor hotplug') Reported-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Tested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent 6f02174 commit 222bde0

File tree

1 file changed

+7
-2
lines changed

1 file changed

+7
-2
lines changed

sound/pci/hda/patch_hdmi.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,7 +1405,6 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
14051405
bool ret;
14061406
bool do_repoll = false;
14071407

1408-
snd_hda_power_up_pm(codec);
14091408
present = snd_hda_pin_sense(codec, pin_nid);
14101409

14111410
mutex_lock(&per_pin->lock);
@@ -1444,7 +1443,6 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
14441443
jack->block_report = !ret;
14451444

14461445
mutex_unlock(&per_pin->lock);
1447-
snd_hda_power_down_pm(codec);
14481446
return ret;
14491447
}
14501448

@@ -1522,6 +1520,10 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
15221520
struct hdmi_spec *spec = codec->spec;
15231521
int ret;
15241522

1523+
/* no temporary power up/down needed for component notifier */
1524+
if (!codec_has_acomp(codec))
1525+
snd_hda_power_up_pm(codec);
1526+
15251527
mutex_lock(&spec->pcm_lock);
15261528
if (codec_has_acomp(codec)) {
15271529
sync_eld_via_acomp(codec, per_pin);
@@ -1531,6 +1533,9 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
15311533
}
15321534
mutex_unlock(&spec->pcm_lock);
15331535

1536+
if (!codec_has_acomp(codec))
1537+
snd_hda_power_down_pm(codec);
1538+
15341539
return ret;
15351540
}
15361541

0 commit comments

Comments
 (0)