Lyude Paul
2018-Aug-09 22:22 UTC
[Nouveau] [PATCH 0/2] Fix display detection issues with P50-P52 docks
This fixes some annoying issues on the P50-P52 with displays not being detected if they aren't plugged in at boot, and sometimes even when they are plugged in at boot. See: https://bugzilla.redhat.com/show_bug.cgi?id=1477182 Lyude Paul (2): drm/nouveau: Only write DP_MSTM_CTRL when needed drm/nouveau: Reset MST branching unit before enabling drivers/gpu/drm/nouveau/dispnv50/disp.c | 65 ++++++++++++++++++------- 1 file changed, 48 insertions(+), 17 deletions(-) -- 2.17.1
Lyude Paul
2018-Aug-09 22:22 UTC
[Nouveau] [PATCH 1/2] drm/nouveau: Only write DP_MSTM_CTRL when needed
Currently, nouveau will re-write the DP_MSTM_CTRL register for an MST hub every time it receives a long HPD pulse on DP. This isn't actually necessary and additionally, has some unintended side effects. With the P50 I've got here, rewriting DP_MSTM_CTRL constantly seems to make it rather likely (1 out of 5 times usually) that bringing up MST with it's ThinkPad dock will fail and result in sideband messages timing out in the middle. Afterwards, successive probes don't manage to get the dock to communicate properly over MST sideband properly. Many times sideband message timeouts from MST hubs are indicative of either the source or the sink dropping an ESI event, which can cause DRM's perspective of the topology's current state to go out of sync with reality. While it's tough to really know for sure what's happening to the dock, using userspace tools to write to DP_MSTM_CTRL in the middle of the MST link probing process does appear to make things flaky. It's possible that when we write to DP_MSTM_CTRL, the function that gets triggered to respond in the dock's firmware temporarily puts it in a state where it might end up not reporting an ESI to the source, or ends up dropping a sideband message we sent it. So, to fix this we make it so that when probing an MST topology, we respect it's current state. If the dock's already enabled, we simply read DP_MSTM_CTRL and disable the topology if it's value is not what we expected. Otherwise, we perform the normal MST probing dance. We avoid taking any action except if the state of the MST topology actually changes. This fixes MST sideband message timeouts and detection failures on my P50 with its ThinkPad dock. Signed-off-by: Lyude Paul <lyude at redhat.com> Cc: stable at vger.kernel.org Cc: Karol Herbst <karolherbst at gmail.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 45 ++++++++++++++++++++----- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index f6c0b2aa9857..cdb3ef7c5d86 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1117,31 +1117,58 @@ nv50_mstm_enable(struct nv50_mstm *mstm, u8 dpcd, int state) int nv50_mstm_detect(struct nv50_mstm *mstm, u8 dpcd[8], int allow) { - int ret, state = 0; + struct drm_dp_aux *aux; + int ret; + bool old_state, new_state; + u8 mstm_ctrl; if (!mstm) return 0; - if (dpcd[0] >= 0x12) { - ret = drm_dp_dpcd_readb(mstm->mgr.aux, DP_MSTM_CAP, &dpcd[1]); + mutex_lock(&mstm->mgr.lock); + + old_state = mstm->mgr.mst_state; + new_state = old_state; + aux = mstm->mgr.aux; + + if (old_state) { + /* Just check that the MST hub is still as we expect it */ + ret = drm_dp_dpcd_readb(aux, DP_MSTM_CTRL, &mstm_ctrl); + if (ret < 0 || !(mstm_ctrl & DP_MST_EN)) { + DRM_DEBUG_KMS("Hub gone, disabling MST topology\n"); + new_state = false; + } + } else if (dpcd[0] >= 0x12) { + ret = drm_dp_dpcd_readb(aux, DP_MSTM_CAP, &dpcd[1]); if (ret < 0) - return ret; + goto probe_error; if (!(dpcd[1] & DP_MST_CAP)) dpcd[0] = 0x11; else - state = allow; + new_state = allow; } - ret = nv50_mstm_enable(mstm, dpcd[0], state); + if (new_state == old_state) { + mutex_unlock(&mstm->mgr.lock); + return new_state; + } + + ret = nv50_mstm_enable(mstm, dpcd[0], new_state); if (ret) - return ret; + goto probe_error; + + mutex_unlock(&mstm->mgr.lock); - ret = drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, state); + ret = drm_dp_mst_topology_mgr_set_mst(&mstm->mgr, new_state); if (ret) return nv50_mstm_enable(mstm, dpcd[0], 0); - return mstm->mgr.mst_state; + return new_state; + +probe_error: + mutex_unlock(&mstm->mgr.lock); + return ret; } static void -- 2.17.1
Lyude Paul
2018-Aug-09 22:22 UTC
[Nouveau] [PATCH 2/2] drm/nouveau: Reset MST branching unit before enabling
When probing a new MST device, it's not safe to make any assumptions about it's current state. While most well mannered MST hubs will just disable the branching unit on hotplug disconnects, this isn't enough to save us from various other scenarios that might have resulted in something writing to the MST branching unit before we got control of it. This could happen if a previous probe we tried failed, if we're booting in kexec context and the hub is still in the state the last kernel put it in, etc. Luckily; there is no reason we can't just reset the branching unit every time we enable a new topology. So, fix this by resetting it on enabling new topologies to ensure that we always start off with a clean, unmodified topology state on MST sinks. This fixes occasional hard-lockups on my P50's laptop dock (e.g. AUX times out all DPCD trasactions) observed after multiple docks, undocks, and module reloads. Signed-off-by: Lyude Paul <lyude at redhat.com> Cc: stable at vger.kernel.org Cc: Karol Herbst <karolherbst at gmail.com> --- drivers/gpu/drm/nouveau/dispnv50/disp.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index cdb3ef7c5d86..61bc36e9c915 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1098,17 +1098,21 @@ nv50_mstm_enable(struct nv50_mstm *mstm, u8 dpcd, int state) int ret; if (dpcd >= 0x12) { - ret = drm_dp_dpcd_readb(mstm->mgr.aux, DP_MSTM_CTRL, &dpcd); + /* Even if we're enabling MST, start with disabling the + * branching unit to clear any sink-side MST topology state + * that wasn't set by us + */ + ret = drm_dp_dpcd_writeb(mstm->mgr.aux, DP_MSTM_CTRL, 0); if (ret < 0) return ret; - dpcd &= ~DP_MST_EN; - if (state) - dpcd |= DP_MST_EN; - - ret = drm_dp_dpcd_writeb(mstm->mgr.aux, DP_MSTM_CTRL, dpcd); - if (ret < 0) - return ret; + if (state) { + /* Now, start initializing */ + ret = drm_dp_dpcd_writeb(mstm->mgr.aux, DP_MSTM_CTRL, + DP_MST_EN); + if (ret < 0) + return ret; + } } return nvif_mthd(disp, 0, &args, sizeof(args)); -- 2.17.1
Apparently Analagous Threads
- [RFC v4 00/20] drm/dp, i915, nouveau: Cleanup nouveau HPD and add DP features from i915
- [PATCH v5 00/20] drm/dp, i915, nouveau: Cleanup nouveau HPD and add DP features from i915
- [RFC v2 00/20] drm/dp, i915, nouveau: Cleanup nouveau HPD and add DP features from i915
- [RFC 00/20] drm/dp, i915, nouveau: Cleanup nouveau HPD and add DP features from i915
- [PATCH 00/26] DP MST Refactors + debugging tools + suspend/resume reprobing