Commit 0c0fe9e6 authored by Kai Vehmanen's avatar Kai Vehmanen Committed by Takashi Iwai

ALSA: hda: hdmi - fix kernel oops caused by invalid PCM idx

Add additional check in hdmi_find_pcm_slot() to not return
a pcm index that points to unallocated pcm. This could happen
if codec driver is set up in codec->mst_no_extra_pcms mode.
On some platforms, this leads to a kernel oops in snd_ctl_notify(),
called via update_eld().

BugLink: https://github.com/thesofproject/linux/issues/1536
Fixes: 5398e94f ALSA: hda - Add DP-MST support for NVIDIA codecs
Signed-off-by: default avatarKai Vehmanen <kai.vehmanen@linux.intel.com>
Link: https://lore.kernel.org/r/20191129143756.23941-1-kai.vehmanen@linux.intel.comSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 336820c4
...@@ -1335,24 +1335,24 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec, ...@@ -1335,24 +1335,24 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
int i; int i;
/* /*
* generic_hdmi_build_pcms() allocates (num_nids + dev_num - 1) * generic_hdmi_build_pcms() may allocate extra PCMs on some
* number of pcms. * platforms (with maximum of 'num_nids + dev_num - 1')
* *
* The per_pin of pin_nid_idx=n and dev_id=m prefers to get pcm-n * The per_pin of pin_nid_idx=n and dev_id=m prefers to get pcm-n
* if m==0. This guarantees that dynamic pcm assignments are compatible * if m==0. This guarantees that dynamic pcm assignments are compatible
* with the legacy static per_pin-pmc assignment that existed in the * with the legacy static per_pin-pcm assignment that existed in the
* days before DP-MST. * days before DP-MST.
* *
* per_pin of m!=0 prefers to get pcm=(num_nids + (m - 1)). * per_pin of m!=0 prefers to get pcm=(num_nids + (m - 1)).
*/ */
if (per_pin->dev_id == 0 &&
!test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap))
return per_pin->pin_nid_idx;
if (per_pin->dev_id != 0 && if (per_pin->dev_id == 0) {
!(test_bit(spec->num_nids + (per_pin->dev_id - 1), if (!test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap))
&spec->pcm_bitmap))) { return per_pin->pin_nid_idx;
return spec->num_nids + (per_pin->dev_id - 1); } else {
i = spec->num_nids + (per_pin->dev_id - 1);
if (i < spec->pcm_used && !(test_bit(i, &spec->pcm_bitmap)))
return i;
} }
/* have a second try; check the area over num_nids */ /* have a second try; check the area over num_nids */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment