From 016dacb60e6d4b301c5941a0dedb49d337926832 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 1 Jun 2022 20:46:34 +1000 Subject: [PATCH] drm/nouveau/kms: pass event mask to hpd handler Will be moving the DP link status check / re-train here so it's safe from racing with modeset routing changes. MST message handling etc. will remain where it is. Signed-off-by: Ben Skeggs Reviewed-by: Lyude Paul --- drivers/gpu/drm/nouveau/nouveau_connector.c | 11 +++++------ drivers/gpu/drm/nouveau/nouveau_connector.h | 3 ++- drivers/gpu/drm/nouveau/nouveau_display.c | 20 +++++++++++++++++--- drivers/gpu/drm/nouveau/nouveau_dp.c | 12 +++++------- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index c2ff8e91d90d..bbd17ee60853 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1162,14 +1162,15 @@ nouveau_connector_funcs_lvds = { }; void -nouveau_connector_hpd(struct drm_connector *connector) +nouveau_connector_hpd(struct nouveau_connector *nv_connector, u64 bits) { - struct nouveau_drm *drm = nouveau_drm(connector->dev); - u32 mask = drm_connector_mask(connector); + struct nouveau_drm *drm = nouveau_drm(nv_connector->base.dev); + u32 mask = drm_connector_mask(&nv_connector->base); unsigned long flags; spin_lock_irqsave(&drm->hpd_lock, flags); if (!(drm->hpd_pending & mask)) { + nv_connector->hpd_pending |= bits; drm->hpd_pending |= mask; schedule_work(&drm->hpd_work); } @@ -1185,15 +1186,13 @@ nouveau_connector_hotplug(struct nvif_notify *notify) struct drm_device *dev = connector->dev; struct nouveau_drm *drm = nouveau_drm(dev); const struct nvif_notify_conn_rep_v0 *rep = notify->data; - bool plugged = (rep->mask != NVIF_NOTIFY_CONN_V0_UNPLUG); if (rep->mask & NVIF_NOTIFY_CONN_V0_IRQ) { nouveau_dp_irq(drm, nv_connector); return NVIF_NOTIFY_KEEP; } - NV_DEBUG(drm, "%splugged %s\n", plugged ? "" : "un", connector->name); - nouveau_connector_hpd(connector); + nouveau_connector_hpd(nv_connector, rep->mask); return NVIF_NOTIFY_KEEP; } diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h index f4e17ff68bf9..1bbf8bf6ba44 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.h +++ b/drivers/gpu/drm/nouveau/nouveau_connector.h @@ -124,6 +124,7 @@ struct nouveau_connector { u8 *dcb; struct nvif_conn conn; + u64 hpd_pending; struct nvif_notify hpd; struct drm_dp_aux aux; @@ -198,7 +199,7 @@ nouveau_crtc_connector_get(struct nouveau_crtc *nv_crtc) struct drm_connector * nouveau_connector_create(struct drm_device *, const struct dcb_output *); -void nouveau_connector_hpd(struct drm_connector *connector); +void nouveau_connector_hpd(struct nouveau_connector *, u64 bits); extern int nouveau_tv_disable; extern int nouveau_ignorelid; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index fb22ebed5424..a21dc2a0f92b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -488,14 +488,28 @@ nouveau_display_hpd_work(struct work_struct *work) drm_connector_list_iter_begin(dev, &conn_iter); nouveau_for_each_non_mst_connector_iter(connector, &conn_iter) { + struct nouveau_connector *nv_connector = nouveau_connector(connector); enum drm_connector_status old_status = connector->status; - u64 old_epoch_counter = connector->epoch_counter; + u64 bits, old_epoch_counter = connector->epoch_counter; if (!(pending & drm_connector_mask(connector))) continue; - connector->status = drm_helper_probe_detect(connector, NULL, - false); + spin_lock_irq(&drm->hpd_lock); + bits = nv_connector->hpd_pending; + nv_connector->hpd_pending = 0; + spin_unlock_irq(&drm->hpd_lock); + + drm_dbg_kms(dev, "[CONNECTOR:%d:%s] plug:%d unplug:%d irq:%d\n", + connector->base.id, connector->name, + !!(bits & NVIF_NOTIFY_CONN_V0_PLUG), + !!(bits & NVIF_NOTIFY_CONN_V0_UNPLUG), + !!(bits & NVIF_NOTIFY_CONN_V0_IRQ)); + + if (bits & NVIF_NOTIFY_CONN_V0_IRQ) + continue; + + connector->status = drm_helper_probe_detect(connector, NULL, false); if (old_epoch_counter == connector->epoch_counter) continue; diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index b7104e676eb2..d349dc24a003 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -29,8 +29,7 @@ #include "nouveau_encoder.h" #include "nouveau_crtc.h" -#include -#include +#include MODULE_PARM_DESC(mst, "Enable DisplayPort multi-stream (default: enabled)"); static int nouveau_mst = 1; @@ -218,8 +217,8 @@ void nouveau_dp_irq(struct nouveau_drm *drm, struct drm_connector *connector = &nv_connector->base; struct nouveau_encoder *outp = find_encoder(connector, DCB_OUTPUT_DP); struct nv50_mstm *mstm; + u64 hpd = 0; int ret; - bool send_hpd = false; if (!outp) return; @@ -231,14 +230,14 @@ void nouveau_dp_irq(struct nouveau_drm *drm, if (mstm && mstm->is_mst) { if (!nv50_mstm_service(drm, nv_connector, mstm)) - send_hpd = true; + hpd |= NVIF_NOTIFY_CONN_V0_UNPLUG; } else { drm_dp_cec_irq(&nv_connector->aux); if (nouveau_dp_has_sink_count(connector, outp)) { ret = drm_dp_read_sink_count(&nv_connector->aux); if (ret != outp->dp.sink_count) - send_hpd = true; + hpd |= NVIF_NOTIFY_CONN_V0_PLUG; if (ret >= 0) outp->dp.sink_count = ret; } @@ -246,8 +245,7 @@ void nouveau_dp_irq(struct nouveau_drm *drm, mutex_unlock(&outp->dp.hpd_irq_lock); - if (send_hpd) - nouveau_connector_hpd(connector); + nouveau_connector_hpd(nv_connector, NVIF_NOTIFY_CONN_V0_IRQ | hpd); } /* TODO: -- 2.11.0