lkml.org 
[lkml]   [2020]   [Feb]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.5 071/367] ALSA: hda - Fix DP-MST support for NVIDIA codecs
    Date
    From: Nikhil Mahale <nmahale@nvidia.com>

    commit c7e661a1c2ae98a4754db6a85fc686b4a89322ad upstream.

    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(). Update
    hdmi_present_sense_via_verbs() to report plug state of pcm jack
    object. Unlike sync_eld_via_acomp(), for !acomp drivers the pcm
    jack's plug state must be consistent with plug state
    of pin's jack.

    Fixes: 5398e94fb753 ("ALSA: hda - Add DP-MST support for NVIDIA codecs")
    Reported-and-tested-by: Martin Regner <martin@larkos.de>
    Signed-off-by: Nikhil Mahale <nmahale@nvidia.com>
    Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
    Cc: <stable@vger.kernel.org>
    Link: https://lore.kernel.org/r/20200204102746.1356-1-nmahale@nvidia.com
    Signed-off-by: Takashi Iwai <tiwai@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    sound/pci/hda/patch_hdmi.c | 94 ++++++++++++++++++++++++++++++---------------
    1 file changed, 63 insertions(+), 31 deletions(-)

    --- a/sound/pci/hda/patch_hdmi.c
    +++ b/sound/pci/hda/patch_hdmi.c
    @@ -1547,6 +1547,34 @@ static bool update_eld(struct hda_codec
    return eld_changed;
    }

    +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 ELD and jack state via HD-audio verbs */
    static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
    int repoll)
    @@ -1568,6 +1596,7 @@ static bool hdmi_present_sense_via_verbs
    int present;
    bool ret;
    bool do_repoll = false;
    + struct snd_jack *pcm_jack = NULL;

    present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id);

    @@ -1595,10 +1624,19 @@ static bool hdmi_present_sense_via_verbs
    do_repoll = true;
    }

    - if (do_repoll)
    + if (do_repoll) {
    schedule_delayed_work(&per_pin->work, msecs_to_jiffies(300));
    - else
    + } else {
    + /*
    + * 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);
    update_eld(codec, per_pin, eld);
    + if (!pcm_jack)
    + pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
    + }

    ret = !repoll || !eld->monitor_present || eld->eld_valid;

    @@ -1607,38 +1645,32 @@ static bool hdmi_present_sense_via_verbs
    jack->block_report = !ret;
    jack->pin_sense = (eld->monitor_present && eld->eld_valid) ?
    AC_PINSENSE_PRESENCE : 0;
    - }
    - mutex_unlock(&per_pin->lock);
    - 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 (spec->dyn_pcm_assign && pcm_jack && !do_repoll) {
    + int state = 0;
    +
    + if (jack->pin_sense & AC_PINSENSE_PRESENCE)
    + state = SND_JACK_AVOUT;
    + snd_jack_report(pcm_jack, state);
    + }

    - /* 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
    + * snd_hda_jack_pin_sense() call at the beginning of this
    + * function, updates jack->pins_sense and clears
    + * jack->jack_dirty, therefore snd_hda_jack_report_sync() will
    + * not override the jack->pin_sense.
    + *
    + * snd_hda_jack_report_sync() is superfluous for dyn_pcm_assign
    + * case. The jack->pin_sense update was already performed, and
    + * hda_jack->jack is NULL for dyn_pcm_assign.
    + *
    + * Don't call snd_hda_jack_report_sync() for
    + * dyn_pcm_assign.
    */
    - jack_tbl = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
    - per_pin->dev_id);
    - if (jack_tbl)
    - jack = jack_tbl->jack;
    + ret = ret && !spec->dyn_pcm_assign;
    }
    - return jack;
    + mutex_unlock(&per_pin->lock);
    + return ret;
    }

    /* update ELD and jack state via audio component */
    @@ -1674,10 +1706,10 @@ static void sync_eld_via_acomp(struct hd
    /* 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);
    + jack = pin_idx_to_pcm_jack(codec, per_pin);
    changed = update_eld(codec, per_pin, eld);
    if (jack == NULL)
    - jack = pin_idx_to_jack(codec, per_pin);
    + jack = pin_idx_to_pcm_jack(codec, per_pin);
    if (changed && jack)
    snd_jack_report(jack,
    (eld->monitor_present && eld->eld_valid) ?

    \
     
     \ /
      Last update: 2020-02-10 14:06    [W:2.566 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site