summaryrefslogtreecommitdiff
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2016-03-17 14:48:13 +0100
committerTakashi Iwai <tiwai@suse.de>2016-03-17 15:38:35 +0100
commit222bde03881c470de8aa4ca8e58f5950c2b84d12 (patch)
tree42308cac88baba0e3400ea2414514320a44e532e /sound/pci/hda
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/pci/hda')
-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,
bool ret;
bool do_repoll = false;
- snd_hda_power_up_pm(codec);
present = snd_hda_pin_sense(codec, pin_nid);
mutex_lock(&per_pin->lock);
@@ -1444,7 +1443,6 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
jack->block_report = !ret;
mutex_unlock(&per_pin->lock);
- snd_hda_power_down_pm(codec);
return ret;
}
@@ -1522,6 +1520,10 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
struct hdmi_spec *spec = codec->spec;
int ret;
+ /* no temporary power up/down needed for component notifier */
+ if (!codec_has_acomp(codec))
+ snd_hda_power_up_pm(codec);
+
mutex_lock(&spec->pcm_lock);
if (codec_has_acomp(codec)) {
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)
}
mutex_unlock(&spec->pcm_lock);
+ if (!codec_has_acomp(codec))
+ snd_hda_power_down_pm(codec);
+
return ret;
}