[alsa-devel] [PATCH] ALSA: hda - Fix DP-MST support for NVIDIA codecs
Takashi Iwai
tiwai at suse.de
Mon Feb 3 11:40:08 CET 2020
On Mon, 03 Feb 2020 11:06:17 +0100,
Nikhil Mahale wrote:
>
> If dyn_pcm_assign is set, different jack objects are being created
> for pcm and pins.
>
> If dyn_pcm_assign is set, generic_hdmi_build_jack() calls into
> add_hdmi_jack_kctl() to create and track separate jack object for
> pcm. Like sync_eld_via_acomp(), hdmi_present_sense_via_verbs() also
> need to report status change of the pcm jack.
>
> Rename pin_idx_to_jack() to pin_idx_to_pcm_jack(). The code to
> report status change of pcm jack, move it to update_eld() which is
> common for acomp and !acomp code paths.
Thanks, that's the cause of the regression.
However, this needs yet more careful handling, I'm afraid.
- hdmi_present_sense_via_verbs() may return true, and its callers
(both check_presence_and_report() and hdmi_repoll_eld()) do call
snd_hda_jack_report_sync() again.
- For non-dyn_pcm_assign case, we shouldn't call jack report there,
but rather simply return true for calling report sync.
- There is another workaround to block the jack report in
hdmi_present_sense_via_verbs() which is applied after update_eld(),
and this will be ignored.
So, I guess that we need the conditional application of the individual
snd_jack_report() only for spec->dyn_pcm_assign==true, and assure that
hdmi_present() returns false.
The last item (the jack report block) is still unclear to me; it's a
workaround that was needed for Nvidia drivers in the past due to
instability. If this is still needed for DP-MST case, we have to
reconsider how to deal with it. Otherwise, this can be applied only
for non-dyn_pcm_assign case.
BTW, the condition for jack->block_report and return value in
hdmi_present_sense_via_verbs() looks currently complicated, but it
could have been simplified like:
-- 8< --
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1569,7 +1569,6 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
* the unsolicited response to avoid custom WARs.
*/
int present;
- bool ret;
bool do_repoll = false;
present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id);
@@ -1603,16 +1602,14 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
else
update_eld(codec, per_pin, eld);
- ret = !repoll || !eld->monitor_present || eld->eld_valid;
-
jack = snd_hda_jack_tbl_get_mst(codec, pin_nid, per_pin->dev_id);
if (jack) {
- jack->block_report = !ret;
+ jack->block_report = do_repoll;
jack->pin_sense = (eld->monitor_present && eld->eld_valid) ?
AC_PINSENSE_PRESENCE : 0;
}
mutex_unlock(&per_pin->lock);
- return ret;
+ return !do_repoll;
}
static struct snd_jack *pin_idx_to_jack(struct hda_codec *codec,
-- 8< --
Takashi
>
> Fixes: 5398e94fb753 ALSA: hda - Add DP-MST support for NVIDIA codecs
> Signed-off-by: Nikhil Mahale <nmahale at nvidia.com>
> ---
> sound/pci/hda/patch_hdmi.c | 87 ++++++++++++++++++++++++----------------------
> 1 file changed, 45 insertions(+), 42 deletions(-)
>
> diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
> index 48bddc218829..7b5360037217 100644
> --- a/sound/pci/hda/patch_hdmi.c
> +++ b/sound/pci/hda/patch_hdmi.c
> @@ -1480,6 +1480,35 @@ static void hdmi_pcm_reset_pin(struct hdmi_spec *spec,
> per_pin->channels = 0;
> }
>
> +static struct snd_jack *pin_idx_to_pcm_jack(struct hda_codec *codec,
> + struct hdmi_spec_per_pin *per_pin)
> +{
> + struct hdmi_spec *spec = codec->spec;
> + struct snd_jack *jack = NULL;
> + struct hda_jack_tbl *jack_tbl;
> +
> + /* if !dyn_pcm_assign, get jack from hda_jack_tbl
> + * in !dyn_pcm_assign case, spec->pcm_rec[].jack is not
> + * NULL even after snd_hda_jack_tbl_clear() is called to
> + * free snd_jack. This may cause access invalid memory
> + * when calling snd_jack_report
> + */
> + if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign) {
> + jack = spec->pcm_rec[per_pin->pcm_idx].jack;
> + } else if (!spec->dyn_pcm_assign) {
> + /*
> + * jack tbl doesn't support DP MST
> + * DP MST will use dyn_pcm_assign,
> + * so DP MST will never come here
> + */
> + jack_tbl = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
> + per_pin->dev_id);
> + if (jack_tbl)
> + jack = jack_tbl->jack;
> + }
> + return jack;
> +}
> +
> /* update per_pin ELD from the given new ELD;
> * setup info frame and notification accordingly
> */
> @@ -1490,9 +1519,15 @@ static bool update_eld(struct hda_codec *codec,
> struct hdmi_eld *pin_eld = &per_pin->sink_eld;
> struct hdmi_spec *spec = codec->spec;
> bool old_eld_valid = pin_eld->eld_valid;
> + struct snd_jack *pcm_jack;
> bool eld_changed;
> int pcm_idx;
>
> + /* pcm_idx >=0 before update_eld() means it is in monitor
> + * disconnected event. Jack must be fetched before update_eld()
> + */
> + pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
> +
> /* for monitor disconnection, save pcm_idx firstly */
> pcm_idx = per_pin->pcm_idx;
> if (spec->dyn_pcm_assign) {
> @@ -1547,6 +1582,14 @@ static bool update_eld(struct hda_codec *codec,
> SNDRV_CTL_EVENT_MASK_VALUE |
> SNDRV_CTL_EVENT_MASK_INFO,
> &get_hdmi_pcm(spec, pcm_idx)->eld_ctl->id);
> +
> + if (!pcm_jack)
> + pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
> + if (eld_changed && pcm_jack)
> + snd_jack_report(pcm_jack,
> + (eld->monitor_present && eld->eld_valid) ?
> + SND_JACK_AVOUT : 0);
> +
> return eld_changed;
> }
>
> @@ -1615,43 +1658,12 @@ static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
> return ret;
> }
>
> -static struct snd_jack *pin_idx_to_jack(struct hda_codec *codec,
> - struct hdmi_spec_per_pin *per_pin)
> -{
> - struct hdmi_spec *spec = codec->spec;
> - struct snd_jack *jack = NULL;
> - struct hda_jack_tbl *jack_tbl;
> -
> - /* if !dyn_pcm_assign, get jack from hda_jack_tbl
> - * in !dyn_pcm_assign case, spec->pcm_rec[].jack is not
> - * NULL even after snd_hda_jack_tbl_clear() is called to
> - * free snd_jack. This may cause access invalid memory
> - * when calling snd_jack_report
> - */
> - if (per_pin->pcm_idx >= 0 && spec->dyn_pcm_assign)
> - jack = spec->pcm_rec[per_pin->pcm_idx].jack;
> - else if (!spec->dyn_pcm_assign) {
> - /*
> - * jack tbl doesn't support DP MST
> - * DP MST will use dyn_pcm_assign,
> - * so DP MST will never come here
> - */
> - jack_tbl = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
> - per_pin->dev_id);
> - if (jack_tbl)
> - jack = jack_tbl->jack;
> - }
> - return jack;
> -}
> -
> /* update ELD and jack state via audio component */
> static void sync_eld_via_acomp(struct hda_codec *codec,
> struct hdmi_spec_per_pin *per_pin)
> {
> struct hdmi_spec *spec = codec->spec;
> struct hdmi_eld *eld = &spec->temp_eld;
> - struct snd_jack *jack = NULL;
> - bool changed;
> int size;
>
> mutex_lock(&per_pin->lock);
> @@ -1674,17 +1686,8 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
> eld->eld_size = 0;
> }
>
> - /* pcm_idx >=0 before update_eld() means it is in monitor
> - * disconnected event. Jack must be fetched before update_eld()
> - */
> - jack = pin_idx_to_jack(codec, per_pin);
> - changed = update_eld(codec, per_pin, eld);
> - if (jack == NULL)
> - jack = pin_idx_to_jack(codec, per_pin);
> - if (changed && jack)
> - snd_jack_report(jack,
> - (eld->monitor_present && eld->eld_valid) ?
> - SND_JACK_AVOUT : 0);
> + update_eld(codec, per_pin, eld);
> +
> mutex_unlock(&per_pin->lock);
> }
>
> --
> 2.16.4
>
More information about the Alsa-devel
mailing list