[PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic

Imre Deak
2026-04-28T12:52:48Z

This series separates DP link capability handling from link training and
recovery and introduces a consistent model for link configuration
selection during state computation and fallback, with KUnit tests
validating the behavior. The patchset is also available at [1].

The issues addressed are as follows:

Link state computation:
- Diverging logic for selecting a link configuration for eDP, DP SST,
and DP MST, for both non-DSC and DSC cases.

Link training fallback:
- Diverging policies for selecting fallback link configurations after
link training failures for eDP, DP SST, and DP MST.
- Inflexible fallback selection, setting a maximum link rate/lane count
for subsequent modesets, preventing the use of link configurations
that have not failed during link training and so could still work.
- eDP and DP SST fallback order not compliant with the DP standard,
using a descending lane/rate order instead of bandwidth order.
- eDP and DP SST fallback lane/rate order not matching the link
state compuation's rate/lane order.
- The above inflexible fallback order resulting in inconsistent
reporting of the valid connector modes for eDP and DP SST after a
link training failure. Modes may disappear and reappear during the
fallback sequence.

Link training recovery:
- Unclear semantics between driver-driven and userspace-driven recovery.
- Unclear distinction between modeset failures and actual link training
failures during automatic retraining, and lack of proper handling of
the former.

Interaction of link state computation, fallback and recovery:
- Handling of the supported-, allowed-, forced-, fallback-link
configurations, and link recovery decisions are intertwined across
multiple modules with direct access/mutation of the relevant state,
instead of having clear interfaces for these.
- Lack of documentation and unit test coverage for the handling of
link-capabilities, -configurations and for the fallback/recovery
logic.

This patchset addresses the above primarily by introducing a central
link capability module (intel_dp_link_caps.c) and restructuring the
detection of link capabilities, link state computation, fallback and
recovery to query and adjust link configurations exclusively via that
interface.

The current behavior is preserved for both modeset state computation and
link training fallback/recovery logic. For now this patchset will enable
setting a particular link configuration ordering on a per-connector
basis (both as a default based on the connector type and as a dynamic
setting); that in turn allows - as a follow-up to this patchset - to
switch over to a unified, bandwidth-based fallback policy by simply
changing the ordering for a given connector type.

The changes in more detail are (everywhere assuming the switch-over to
the new scheme as a follow-up based on the above):

Link state computation:
- Unify link configuration selection logic for eDP, DP SST, and DP
MST, for both non-DSC and DSC cases, using the same interface to
query and adjust the allowed link configuration set, using the same
configuration ordering for this.

Link training fallback:
- Unified fallback selection mechanism across connector types,
matching the mechanism of the link state computation phase.
- Enable a more fine-grained fallback policy by disabling only the
link configuration that failed link training, preserving the rest
for subsequent modesets.
- Align fallback ordering with that of the link state computation.
- Ensure a consistent view of supported connector modes across
fallback sequences.

Link training recovery:
- Clarify and separate driver-driven and userspace-driven recovery
semantics, and document these.
- Distinguish modeset failures from link training failures during
automatic retraining and handle modeset failures appropriately.

Interaction of link state computation, fallback and recovery:
- Separate the tracking of supported link configurations - based on
the sink's detected capabilities - and selection of fallback
configurations into their dedicated modules, with a well-defined
interface to query and adjust the configurations available for a
modeset:

Detection Computation (intel_dp.c)
| |
| adjust query |
| |
+----> Capabilities <------+ (intel_dp_link_caps.c)
^
| adjust/query
|
Fallback (intel_dp_link_training.c)

- Ensure consistent link configuration ordering across computation
and fallback phases.
- Add detailed documentation and test coverage for the link
capabilities interface and the link recovery logic.

Patchset layout:

This is a large series because the interfaces and state tracking for
link-state computation, fallback, and recovery are intertwined across
multiple modules. They also rely on direct access to, and mutation of,
state instead of a proper interface, so untangling this was involved.

Nevertheless, most changes are mechanical code movement and renaming:
separating link training and link capability handling from the generic
DP code and moving them into dedicated modules.

A large part of both the link training and link caps portions of this
series follows the same idea:

1. Move existing helpers accessing link training or link caps state.
2. Add new helpers for accessing that state, converting all direct
users to use them.
3. Move the state to be internal to the respective module.

Later parts (notably the link capability module) depend on earlier
refactoring of link training. The rationale for submitting all the
changes in a single patchset is twofold:

1. The last segment, adding the link capability interface, requires all
previous refactoring to both generic DP and link training code.
2. The purpose of much of the earlier refactoring only becomes clear
in the context of the last segment adding the link capability
interface. All intermediate steps in those segments prepare for the
introduction of the link capability interface, which at the end
connects link-capability detection, -state computation and
-fallback/recovery functionality in a unified way.

The series is therefore kept as a single unit, but organized into the
following segments of patches to allow incremental review and merging:

- Link training refactoring: 1-26
- Link capabilities refactoring: 27-89
- Unify configuration selection for modeset and fallback: 90-99
- Kunit tests for configuration selection: 100-108

[1] https://github.com/ideak/linux/commits/dp-link-caps

Imre Deak (108):
drm/i915/dp: Move clamping max link rate to common rates setup
drm/i915/dp: Clamp max lane count to max common lane count
drm/i915/dp: Bump connector epoch on link capability changes
drm/i915/dp_link_training: Introduce link training state struct
drm/i915/dp_link_training: Factor out link training state reset helper
drm/i915/dp_link_training: Reset link training state on link
capability change
drm/i915/dp_link_training: Flush commits in debugfs entries
drm/i915/dp_link_training: Move link training helpers to link training
code
drm/i915/dp_link_training: Use link_training as base pointer in
debugfs
drm/i915/dp_link_training: Add helpers to access force retrain state
drm/i915/dp_link_training: Move link recovery/debug state to
link_training
drm/i915/dp_link_training: Prevent repeated autoretrain attempts
drm/i915/dp_link_training: Clamp sequential link training failure
counter
drm/i915/dp_link_training: Check for pending autoretrain explicitly
drm/i915/dp_link_training: Add helper to query pending autoretrain
drm/i915/dp_link_training: Add helper to query allowed autoretrain
drm/i915/dp_link_training: Add helper to mark link training failure
drm/i915/dp_link_training: Add helper to reset link recovery state
drm/i915/dp_link_training: Track link recovery state with an enum
drm/i915/dp_link_training: Add no-fallback link recovery state
drm/i915/display: Factor out a helper to modeset a pipe with atomic
state
drm/i915/display: Simplify
intel_modeset_commit_pipes_for_atomic_state()
drm/i915/dp_link_training: Allocate atomic state for autoretrain
modeset
drm/i915/dp_link_training: Disallow autoretrains after failed modeset
drm/i915/dp_link_training: Fix kernel-doc of
intel_dp_init_lttpr_and_dprx_caps()
drm/i915/dp_link_training: Document DP link recovery logic
drm/i915/dp: Rename intel_dp_link_config to intel_dp_link_config_entry
drm/i915/dp: Add struct intel_dp_link_config
drm/i915/dp_link_caps: Introduce DP link capability module
drm/i915/dp_link_caps: Move common rate helpers to link caps
drm/i915/dp_link_caps: Move forced link param helpers to link caps
drm/i915/dp: Simplify querying of forced link parameters
drm/i915/dp_link_caps: Move forced and max link debugfs entries to
link caps
drm/i915/dp_link_training: Use helpers to get forced link params
drm/i915/dp_link_caps: Move forced link params to link_caps
drm/i915/dp_link_caps: Move link config helpers to link caps
drm/i915/dp_link_caps: Move link config tracking to link_caps
drm/i915/dp_link_caps: Rename helper updating the link configurations
drm/i915/dp: Factor out helper to get link rate capabilities
drm/i915/dp_link_caps: Pass supported link rates to link caps update
drm/i915/dp_link_caps: Add helper to get all supported link rates
drm/i915/dp_link_caps: Add helper to get the number of supported link
rates
drm/i915/dp_link_caps: Add helper to get common rate index
drm/i915/dp_link_caps: Move tracking of common rates to link_caps
struct
drm/i915/dp_link_caps: Track max common lane count in link_caps
drm/i915/dp_link_caps: Move max lane count change detection to
link_caps
drm/i915/dp_link_caps: Use max common lane count from link_caps
drm/i915/dp_link_caps: Move updating max link limits to link_caps
update
drm/i915/dp_link_caps: Add helpers to get max link limits
drm/i915/dp_link_caps: Add helpers to set max link limits
drm/i915/dp_link_caps: Validate max link limits
drm/i915/dp_link_caps: Add helper to reset max link limits
drm/i915/dp_link_caps: Add helper to reset link_caps state
drm/i915/dp_link_caps: Move max link limits to link_caps
drm/i915/dp_link_caps: Pass link_caps to static functions
drm/i915/dp_link_caps: Pass link_caps to config update/lookup helpers
drm/i915/dp_link_caps: Pass link_caps to common rate helpers
drm/i915/dp_link_caps: Add link_caps prefix to common rate helpers
drm/i915/dp_link_caps: Add missing documentation to exported functions
drm/i915/dp_link_caps: Set forced link params before resetting link
params
drm/i915/dp_link_caps: Adjust max_limits during link config update
drm/i915/dp_link_caps: Adjust max_limits when setting or resetting it
drm/i915/dp: Simplify the modeset max link rate limit computation
drm/i915/dp: Query max limits via link_caps during mode validation
drm/i915/dp_tunnel: Query max link limits via link_caps for BW
computation
drm/i915/doc: Document DP link capabilities
drm/i915/dp_link_caps: Move config table members to a substruct
drm/i915/dp_link_caps: Factor out a helper to look up a config table
rate
drm/i915/dp_link_caps: Pass config table pointer to rate lookup helper
drm/i915/dp_link_caps: Factor out helper to get link config from table
by index
drm/i915/dp_link_caps: Add helper to get config at iterator position
drm/i915/dp_link_caps: Add helper to find position of matching config
drm/i915/dp_link_training: Reset the max link limits in the fallback
code
drm/i915/dp_link_training: Use config iterator for BW-order fallback
drm/i915/dp_link_training: Look up configurations using fuzzy rate
matching
drm/i915/dp_link_caps: Pass table pointer to the sort compare function
drm/i915/dp_link_caps: Compare config tables instead of link
parameters
drm/i915/dp_link_caps: Precompute config table before update
drm/i915/dp_link_caps: Compare internal config entries during table
matching
drm/i915/dp_link_caps: Use virtual config indexing in config table
drm/i915/dp_link_caps: Simplify idx->link rate/lane count lookup
drm/i915/dp_link_caps: Simplify BW order pos->config index array
drm/i915/dp_link_caps: Add helper to get iteration order for a
connector
drm/i915/dp_link_caps: Add reset and merge update modes
drm/i915/dp_link_caps: Add mask for disabled link configurations
drm/i915/dp_link_caps: Add link configuration iterators
drm/i915/dp_link_caps: Preserve disabled config mask during merge
update
drm/i915/dp_link_caps: Account for disabled configs during max link
info update
drm/i915/dp_link_caps: Add debugfs entry showing allowed
configurations
drm/i915/dp: Add a mask of valid configurations for modeset
computation
drm/i915/dp: Iterate configurations via link_caps for SST non-DSC
drm/i915/dp: Iterate configurations via link_caps for SST DSC
drm/i915/dp: Use link caps for eDP DSC config selection
drm/i915/dp_mst: Use link caps for non-DSC config selection
drm/i915/dp_mst: Use link caps for MST DSC config selection
drm/i915/dp_test: Use link caps for compliance link configs
drm/i915/dp: Remove min/max link config limits
drm/i915/dp_link_training: Account for disabled configs during SST
fallback
drm/i915/dp_link_training: Disable failed config during fallback
drm/i915/kunit: Enable KUnit tests
drm/i915/kunit: Add DP link test stub
drm/xe/kunit: Add display test config
drm/xe/kunit: Build DP link display tests
drm/i915/kunit: setup DP link test context
drm/i915/kunit: Export link training and caps funcs for testing
drm/i915/kunit: DP link: add baseline fixed table reference test
drm/i915/kunit: DP link: add update config tests
drm/i915/kunit: DP link: add fallback tests

Documentation/gpu/i915.rst | 21 +
drivers/gpu/drm/i915/.kunitconfig | 12 +
drivers/gpu/drm/i915/Kconfig.debug | 12 +
drivers/gpu/drm/i915/Makefile | 3 +
drivers/gpu/drm/i915/display/g4x_dp.c | 10 +-
drivers/gpu/drm/i915/display/intel_ddi.c | 18 +-
drivers/gpu/drm/i915/display/intel_display.c | 42 +-
drivers/gpu/drm/i915/display/intel_display.h | 3 +
.../drm/i915/display/intel_display_debugfs.c | 2 +
.../drm/i915/display/intel_display_types.h | 38 +-
drivers/gpu/drm/i915/display/intel_dp.c | 741 +++----
drivers/gpu/drm/i915/display/intel_dp.h | 22 +-
.../gpu/drm/i915/display/intel_dp_link_caps.c | 1752 +++++++++++++++++
.../gpu/drm/i915/display/intel_dp_link_caps.h | 262 +++
.../drm/i915/display/intel_dp_link_training.c | 1257 +++++++++---
.../drm/i915/display/intel_dp_link_training.h | 44 +
drivers/gpu/drm/i915/display/intel_dp_mst.c | 80 +-
drivers/gpu/drm/i915/display/intel_dp_test.c | 95 +-
drivers/gpu/drm/i915/display/intel_dp_test.h | 3 +-
.../gpu/drm/i915/display/intel_dp_tunnel.c | 14 +-
drivers/gpu/drm/i915/display/tests/Makefile | 7 +
.../i915/display/tests/intel_dp_link_test.c | 1427 ++++++++++++++
drivers/gpu/drm/xe/.gitignore | 1 +
drivers/gpu/drm/xe/.kunitconfig-display | 11 +
drivers/gpu/drm/xe/Makefile | 4 +
drivers/gpu/drm/xe/display/tests/Makefile | 11 +
26 files changed, 5033 insertions(+), 859 deletions(-)
create mode 100644 drivers/gpu/drm/i915/.kunitconfig
create mode 100644 drivers/gpu/drm/i915/display/intel_dp_link_caps.c
create mode 100644 drivers/gpu/drm/i915/display/intel_dp_link_caps.h
create mode 100644 drivers/gpu/drm/i915/display/tests/Makefile
create mode 100644 drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
create mode 100644 drivers/gpu/drm/xe/.kunitconfig-display
create mode 100644 drivers/gpu/drm/xe/display/tests/Makefile

--
2.49.1