[alsa-devel] [PATCH] ALSA: hda - Fix DP-MST support for NVIDIA codecs
Nikhil Mahale
nmahale at nvidia.com
Tue Feb 4 06:08:19 CET 2020
On 2/3/20 4:10 PM, Takashi Iwai wrote:
> External email: Use caution opening links or attachments
>
>
> 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.
Yeah, you are right. But I don't think we should return false from
hdmi_present().
Before dyn_pcm_assign support for non-acomp drivers:
1) pcm and pin plug detection were controlled by same jack object, and
2) change in plug status was reported from snd_hda_jack_report_sync().
If dyn_pcm_assign support is enabled for non-acomp drivers, then pcm
and pin detection are controlled by different jack object. Now, report
for plug status change of both jack object, requires to be in sync.
snd_hda_jack_report_sync() reports change in plug status of pin jack
object. I think after snd_hda_jack_report_sync() we should loop over
all pins, detect change in plug status, and report change in plug
status of pcm jack.
> 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.
The jack report block, was added by commit 464837a7bc0a (ALSA: hda -
block HDMI jack reports while repolling), to avoid race condition
with repolling. That is not NVIDIA specific.
> 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< --
Yeah, this is simple to understand.
I am sending fresh patches, see if they make sense.
Thanks,
Nikhil Mahale
>
> 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