aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2016-03-17 09:48:13 -0400
committerTakashi Iwai <tiwai@suse.de>2016-03-17 10:38:35 -0400
commit222bde03881c470de8aa4ca8e58f5950c2b84d12 (patch)
tree42308cac88baba0e3400ea2414514320a44e532e /sound
parent6f0217441839c258b82dd83ee15082666d6ab9c2 (diff)
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: a76056f2e57e ('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>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/patch_hdmi.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index cde9746cda8e..49ee4e55dd16 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1405,7 +1405,6 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
1405 bool ret; 1405 bool ret;
1406 bool do_repoll = false; 1406 bool do_repoll = false;
1407 1407
1408 snd_hda_power_up_pm(codec);
1409 present = snd_hda_pin_sense(codec, pin_nid); 1408 present = snd_hda_pin_sense(codec, pin_nid);
1410 1409
1411 mutex_lock(&per_pin->lock); 1410 mutex_lock(&per_pin->lock);
@@ -1444,7 +1443,6 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
1444 jack->block_report = !ret; 1443 jack->block_report = !ret;
1445 1444
1446 mutex_unlock(&per_pin->lock); 1445 mutex_unlock(&per_pin->lock);
1447 snd_hda_power_down_pm(codec);
1448 return ret; 1446 return ret;
1449} 1447}
1450 1448
@@ -1522,6 +1520,10 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
1522 struct hdmi_spec *spec = codec->spec; 1520 struct hdmi_spec *spec = codec->spec;
1523 int ret; 1521 int ret;
1524 1522
1523 /* no temporary power up/down needed for component notifier */
1524 if (!codec_has_acomp(codec))
1525 snd_hda_power_up_pm(codec);
1526
1525 mutex_lock(&spec->pcm_lock); 1527 mutex_lock(&spec->pcm_lock);
1526 if (codec_has_acomp(codec)) { 1528 if (codec_has_acomp(codec)) {
1527 sync_eld_via_acomp(codec, per_pin); 1529 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)
1531 } 1533 }
1532 mutex_unlock(&spec->pcm_lock); 1534 mutex_unlock(&spec->pcm_lock);
1533 1535
1536 if (!codec_has_acomp(codec))
1537 snd_hda_power_down_pm(codec);
1538
1534 return ret; 1539 return ret;
1535} 1540}
1536 1541