diff options
author | Kai Vehmanen <kai.vehmanen@linux.intel.com> | 2019-11-29 16:37:55 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2019-11-29 15:41:35 +0100 |
commit | 0c0fe9e6b95ce2e9e2c83bef5563cf223e849eda (patch) | |
tree | f15fa9bc7be4cf9ee2f7c1bccfbce847715656e8 /sound | |
parent | 336820c4374bc065317f247dc2bb37c0e41b64a6 (diff) |
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>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/patch_hdmi.c | 22 |
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 */ |