summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKai Vehmanen <kai.vehmanen@linux.intel.com>2019-11-29 15:37:55 +0100
committerTakashi Iwai <tiwai@suse.de>2019-11-29 15:41:35 +0100
commit0c0fe9e6b95ce2e9e2c83bef5563cf223e849eda (patch)
treef15fa9bc7be4cf9ee2f7c1bccfbce847715656e8
parentALSA: hda/realtek - Fix inverted bass GPIO pin on Acer 8951G (diff)
downloadlinux-0c0fe9e6b95ce2e9e2c83bef5563cf223e849eda.tar.xz
linux-0c0fe9e6b95ce2e9e2c83bef5563cf223e849eda.zip
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: 5398e94fb753 ALSA: hda - Add DP-MST support for NVIDIA codecs Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> Link: https://lore.kernel.org/r/20191129143756.23941-1-kai.vehmanen@linux.intel.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/pci/hda/patch_hdmi.c22
1 files changed, 11 insertions, 11 deletions
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 6de82c96cf47..a50736269584 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1335,24 +1335,24 @@ static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
int i;
/*
- * generic_hdmi_build_pcms() allocates (num_nids + dev_num - 1)
- * number of pcms.
+ * generic_hdmi_build_pcms() may allocate extra PCMs on some
+ * 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
* 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.
*
* 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 &&
- !(test_bit(spec->num_nids + (per_pin->dev_id - 1),
- &spec->pcm_bitmap))) {
- return spec->num_nids + (per_pin->dev_id - 1);
+
+ if (per_pin->dev_id == 0) {
+ if (!test_bit(per_pin->pin_nid_idx, &spec->pcm_bitmap))
+ return per_pin->pin_nid_idx;
+ } 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 */