Skip to content

Intermittent monitor activation failure on USB-C dock due to EDID race condition #3410

@coleleavitt

Description

@coleleavitt

Problem

Monitors connected via USB-C dock (Lenovo ThinkPad USB-C Dock Gen 2) intermittently fail to activate on boot or dock reconnection. One or both external monitors stay dark permanently until the dock is re-plugged.

Root Cause

The failure is caused by a timing race between the kernel DRM subsystem and EDID firmware negotiation:

  1. USB-C dock DP alt-mode + MST link negotiation takes hundreds of milliseconds
  2. Kernel reports connector as State::Connected before EDID is read → connector.modes() returns empty
  3. pick_mode() returns Noneconnector_connected() skips activation with "no mode"
  4. Smithay's ConnectorScanner treats (Connected, Connected) as a no-op — subsequent scans do not re-emit events for already-connected connectors even when modes become available
  5. The connector is stuck in a permanent dead state

Whether activation succeeds depends entirely on whether EDID is ready before the first scan completes, making the bug intermittent.

Upstream Root Cause

The underlying issue is in smithay's ConnectorScanner (smithay-drm-extras), which does not detect mode-list changes on already-connected connectors:

Workaround (implemented)

PR #3409 adds a bounded rescan timer in backend/tty.rs:

  • After device_changed() processes connectors, schedule_rescan_if_needed() checks for connected-but-unactivated connectors
  • If found, schedules a 2-second delayed rescan (up to 3 retries)
  • This gives the kernel time to complete EDID reads

This workaround is valuable even after the smithay fix lands, because it handles the case where no subsequent udev event fires at all.

Hardware

  • Laptop: ThinkPad P16 Gen 3
  • GPU: NVIDIA RTX PRO 4000 (nvidia-drm 590.48.01, kernel-open), Intel iGPU (i915)
  • Dock: Lenovo ThinkPad USB-C Dock Gen 2
  • Monitors: Two LEN S27q-10 (2560x1440@60Hz) — one HDMI, one DP MST
  • Kernel: 6.19.0-rc8

Cross-Compositor Analysis

Compositor EDID Race Handling
Mutter 3-second debounce timer per connector + mode-change detection → full reload
wlroots No retry — accepts connected+empty-modes, relies on udev events
KWin isConnected() requires non-empty modes — connected+no-modes treated as disconnected; no retry
niri (with PR #3409) Bounded rescan timer: 3 retries × 2s delay

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:outputMonitors, scaling, VRR, DPMS

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions