From: "David R. Hedges" <[email protected]>

nouveau_connector_create() caches the connector's DP encoder in
nv_connector->dp_encoder using find_encoder().  On nv50+ it's called
from nv50_display_create() before nv50_sor_create() has created the
encoder and attached it to the connector, so possible_encoders is
still empty, find_encoder() returns NULL, and dp_encoder is never set.
Two things depend on it:

 - nouveau_dp_link_check(), which the HPD worker calls on IRQ_HPD,
   reports the link as fine without looking at it when there's no DP
   encoder.  Until commit 633716501c94 ("drm/nouveau/disp: add dp
   train method") it looked the encoder up each time; since then, a
   sink that reports link loss with IRQ_HPD hasn't been retrained.

 - nouveau_connector_atomic_check() has never called
   drm_dp_mst_root_conn_atomic_check() for MST-capable root
   connectors.

Set dp_encoder in nv50_sor_create() right after the SOR is attached to
the connector, and drop the assignment that can't succeed.  This also
covers eDP, whose SOR is a DCB_OUTPUT_DP encoder too.  On a GA102 with
GSP-RM 570.144, an IRQ_HPD now leads to a read of the sink's link
status, where before it produced no AUX traffic at all.

This depends on "drm/nouveau/kms/nv50-: reject DP modesets the link
can't carry" and "drm/nouveau/dp: restart lost links with a modeset on
GSP-RM".  Without them, enabling the link check would have nouveau
retrain active links in place on GSP-RM, or restart them with a mode
the link can no longer carry, either of which can hang the display
engine.  The MST atomic check this enables hasn't been tested.

Fixes: 11d2738940eb ("drm/nouveau/kms: Cache DP encoders in nouveau_connector")
Fixes: 633716501c94 ("drm/nouveau/disp: add dp train method")
Link: https://gitlab.freedesktop.org/drm/nouveau/-/work_items/515
Signed-off-by: David R. Hedges <[email protected]>
---
 drivers/gpu/drm/nouveau/dispnv50/disp.c     | 1 +
 drivers/gpu/drm/nouveau/nouveau_connector.c | 2 --
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c 
b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index 7f55c016d846..583368914bf0 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -1941,6 +1941,7 @@ nv50_sor_create(struct nouveau_encoder *nv_encoder)
 
        if (dcbe->type == DCB_OUTPUT_DP) {
                mutex_init(&nv_encoder->dp.hpd_irq_lock);
+               nv_connector->dp_encoder = nv_encoder;
 
                if (disp->disp->object.oclass < GF110_DISP) {
                        /* HW has no support for address-only
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c 
b/drivers/gpu/drm/nouveau/nouveau_connector.c
index cae4e35c30aa..845f284f3a20 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -1573,8 +1573,6 @@ nouveau_connector_create(struct drm_device *dev, int 
index)
 
        switch (type) {
        case DRM_MODE_CONNECTOR_DisplayPort:
-               nv_connector->dp_encoder = find_encoder(&nv_connector->base, 
DCB_OUTPUT_DP);
-               fallthrough;
        case DRM_MODE_CONNECTOR_eDP:
                drm_dp_cec_register_connector(&nv_connector->aux, connector);
                break;

-- 
2.55.0


Reply via email to