When a connector has DRM_FORCE_ON (set via video=CONNECTOR:e), check_connector_changed() calls the driver's detect() callback. Well-behaved drivers (e.g. NVIDIA's open kernel module) check connector->force and return connector_status_connected regardless of actual hardware state. This means the epoch counter never increments and no uevent reaches userspace.
However, the HPD interrupt itself indicates a physical state change on the link. A common scenario is an HDMI-connected TV switching to built-in apps (Netflix, etc.), which causes the TV's HDMI receiver to stop listening to TMDS signals. When the TV returns to the HDMI input, the GPU needs to re-negotiate the link, but no component in the stack detects this because the forced status masks the physical change. Add an epoch counter increment for force-enabled connectors after detect() returns. This ensures the hotplug uevent reaches userspace compositors so they can trigger a modeset for link re-training. Note that detect() is still called normally before the epoch bump. This preserves driver-side effects like scrambler re-initialization on vc4/i915. This approach differs from a prior patch [1] which skipped detect() entirely for forced connectors and was rejected due to regression concerns on scrambler re-init. The software polling path (output_poll_execute) already skips forced connectors with an explicit guard. This patch addresses only the hardware HPD IRQ path, which was previously unguarded. [1] https://patchwork.kernel.org/project/dri-devel/patch/[email protected]/ Tested with: - GPU: NVIDIA RTX 5070 Ti (nvidia-open 595.58.03) - Display: Samsung 75" 4K TV via HDMI-A-1 (force-enabled) - Kernel: 6.19.10 (CachyOS) - Compositor: KWin 6.6.3 (Wayland) Signed-off-by: Miguel Sedek <[email protected]> --- drm_probe_helper.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drm_probe_helper.c b/drm_probe_helper.c index 92f2176..b7d60e2 100644 --- a/drm_probe_helper.c +++ b/drm_probe_helper.c @@ -984,6 +984,23 @@ static bool check_connector_changed(struct drm_connector *connector) old_epoch_counter = connector->epoch_counter; connector->status = drm_helper_probe_detect(connector, NULL, false); + /* + * For force-enabled connectors, the driver's detect() returns the + * forced status, so the epoch counter never increments. But an HPD + * event on a forced connector still indicates a physical link state + * change (e.g. a TV switching inputs). Signal the change to + * userspace so the compositor can trigger a modeset for link + * re-training. Note: detect() is still called above so driver-side + * effects (scrambler re-init, etc.) are preserved. + */ + if (connector->force && old_epoch_counter == connector->epoch_counter) { + connector->epoch_counter += 1; + drm_dbg_kms(dev, + "[CONNECTOR:%d:%s] HPD on force-enabled connector, signaling link re-train\n", + connector->base.id, connector->name); + return true; + } + if (old_epoch_counter == connector->epoch_counter) { drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Same epoch counter %llu\n", connector->base.id, -- 2.53.0
