public inbox for intel-gfx@lists.freedesktop.org
 help / color / mirror / Atom feed
* [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic
@ 2026-04-28 12:50 Imre Deak
  2026-04-28 12:50 ` [PATCH 001/108] drm/i915/dp: Move clamping max link rate to common rates setup Imre Deak
                   ` (110 more replies)
  0 siblings, 111 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

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


^ permalink raw reply	[flat|nested] 113+ messages in thread

* [PATCH 001/108] drm/i915/dp: Move clamping max link rate to common rates setup
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 002/108] drm/i915/dp: Clamp max lane count to max common lane count Imre Deak
                   ` (109 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Limit intel_dp->link.max_rate already in intel_dp_set_common_rates(), so
it always gets updated alongside the common rates.

This prepares for detecting changes in the supported link capabilities
(common rates, lane count, and max_rate) in follow-up changes in this
patchset, allowing automatic link retraining to be re-enabled and the
maximum link parameters to be updated after such capability changes.

During the first connector probing after a sink is connected, the common
rates will be detected in intel_dp_set_common_rates() without
intel_dp->link.max_rate being set (after driver loading) or reset (after
the previous sink got disconnected) to the current sink's maximum
supported rate. In those cases max_rate will be reset in
intel_dp_reset_link_params() called after the common rates detection.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 8631df908b07f..c6a961d02a4bc 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -790,6 +790,7 @@ int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lan
 static void intel_dp_set_common_rates(struct intel_dp *intel_dp)
 {
 	struct intel_display *display = to_intel_display(intel_dp);
+	int len;
 
 	drm_WARN_ON(display->drm,
 		    !intel_dp->num_source_rates || !intel_dp->num_sink_rates);
@@ -807,6 +808,10 @@ static void intel_dp_set_common_rates(struct intel_dp *intel_dp)
 	}
 
 	intel_dp_link_config_init(intel_dp);
+
+	len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.max_rate);
+	if (len > 0)
+		intel_dp->link.max_rate = intel_dp_common_rate(intel_dp, len - 1);
 }
 
 bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
@@ -1677,14 +1682,10 @@ static int forced_link_rate(struct intel_dp *intel_dp)
 int
 intel_dp_max_link_rate(struct intel_dp *intel_dp)
 {
-	int len;
-
 	if (intel_dp->link.force_rate)
 		return forced_link_rate(intel_dp);
 
-	len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.max_rate);
-
-	return intel_dp_common_rate(intel_dp, len - 1);
+	return intel_dp->link.max_rate;
 }
 
 static int
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 002/108] drm/i915/dp: Clamp max lane count to max common lane count
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
  2026-04-28 12:50 ` [PATCH 001/108] drm/i915/dp: Move clamping max link rate to common rates setup Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 003/108] drm/i915/dp: Bump connector epoch on link capability changes Imre Deak
                   ` (108 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Clamp the maximum lane count after sink capability updates, matching
the earlier max link rate clamping done when updating common rates.

This prepares for detecting supported link capability changes in one
place in follow-up changes.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index c6a961d02a4bc..cb81a9864d8c4 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -4856,9 +4856,15 @@ intel_dp_has_sink_count(struct intel_dp *intel_dp)
 
 void intel_dp_update_sink_caps(struct intel_dp *intel_dp)
 {
+	int current_max_common_lane_count;
+
 	intel_dp_set_sink_rates(intel_dp);
 	intel_dp_set_max_sink_lane_count(intel_dp);
 	intel_dp_set_common_rates(intel_dp);
+
+	current_max_common_lane_count = intel_dp_max_common_lane_count(intel_dp);
+	intel_dp->link.max_lane_count = min(intel_dp->link.max_lane_count,
+					    current_max_common_lane_count);
 }
 
 static bool
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 003/108] drm/i915/dp: Bump connector epoch on link capability changes
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
  2026-04-28 12:50 ` [PATCH 001/108] drm/i915/dp: Move clamping max link rate to common rates setup Imre Deak
  2026-04-28 12:50 ` [PATCH 002/108] drm/i915/dp: Clamp max lane count to max common lane count Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 004/108] drm/i915/dp_link_training: Introduce link training state struct Imre Deak
                   ` (107 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Bump the connector epoch when the common link capabilities change after
the sink reports updated capabilities. This covers the common rates and
the maximum common lane count, which are derived from the source and
sink capabilities.

Also bump the epoch when the maximum link limits change. These limits
are initialized from the common capabilities, but can later change due
to either sink capability updates or fallback selection.

Follow-up changes move both the change detection and the updates to the
maximum link limits, along with other derived maximum link information,
into the link capability module, where dependencies among all these can
ben handled consistently.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 49 ++++++++++++++++++++++++-
 1 file changed, 47 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index cb81a9864d8c4..df34df6610ac2 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -787,14 +787,37 @@ int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lan
 	return -1;
 }
 
-static void intel_dp_set_common_rates(struct intel_dp *intel_dp)
+static bool current_common_caps_match(struct intel_dp *intel_dp,
+				      const int *rates, int num_rates)
+{
+	const int *current_rates = intel_dp->common_rates;
+	int num_current_rates = intel_dp->num_common_rates;
+
+	if (num_current_rates != num_rates)
+		return false;
+
+	if (memcmp(current_rates, rates, num_rates * sizeof(rates[0])))
+		return false;
+
+	return true;
+}
+
+/* Return %true if any supported or maximum link param changed. */
+static bool intel_dp_set_common_rates(struct intel_dp *intel_dp)
 {
 	struct intel_display *display = to_intel_display(intel_dp);
+	int num_old_common_rates = intel_dp->num_common_rates;
+	int old_max_rate_limit = intel_dp->link.max_rate;
+	int old_common_rates[DP_MAX_SUPPORTED_RATES];
+	bool link_params_changed = false;
 	int len;
 
 	drm_WARN_ON(display->drm,
 		    !intel_dp->num_source_rates || !intel_dp->num_sink_rates);
 
+	static_assert(sizeof(old_common_rates) == sizeof(intel_dp->common_rates));
+	memcpy(old_common_rates, intel_dp->common_rates, sizeof(old_common_rates));
+
 	intel_dp->num_common_rates = intersect_rates(intel_dp->source_rates,
 						     intel_dp->num_source_rates,
 						     intel_dp->sink_rates,
@@ -807,11 +830,19 @@ static void intel_dp_set_common_rates(struct intel_dp *intel_dp)
 		intel_dp->num_common_rates = 1;
 	}
 
+	if (!current_common_caps_match(intel_dp, old_common_rates, num_old_common_rates))
+		link_params_changed = true;
+
 	intel_dp_link_config_init(intel_dp);
 
 	len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.max_rate);
 	if (len > 0)
 		intel_dp->link.max_rate = intel_dp_common_rate(intel_dp, len - 1);
+
+	if (intel_dp->link.max_rate != old_max_rate_limit)
+		link_params_changed = true;
+
+	return link_params_changed;
 }
 
 bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
@@ -4856,15 +4887,29 @@ intel_dp_has_sink_count(struct intel_dp *intel_dp)
 
 void intel_dp_update_sink_caps(struct intel_dp *intel_dp)
 {
+	struct intel_connector *connector = intel_dp->attached_connector;
+	int old_max_common_lane_count = intel_dp_max_common_lane_count(intel_dp);
+	int old_max_lane_count_limit = intel_dp->link.max_lane_count;
 	int current_max_common_lane_count;
+	bool link_params_changed = false;
 
 	intel_dp_set_sink_rates(intel_dp);
 	intel_dp_set_max_sink_lane_count(intel_dp);
-	intel_dp_set_common_rates(intel_dp);
+	if (intel_dp_set_common_rates(intel_dp))
+		link_params_changed = true;
 
 	current_max_common_lane_count = intel_dp_max_common_lane_count(intel_dp);
+	if (current_max_common_lane_count != old_max_common_lane_count)
+		link_params_changed = true;
+
 	intel_dp->link.max_lane_count = min(intel_dp->link.max_lane_count,
 					    current_max_common_lane_count);
+
+	if (intel_dp->link.max_lane_count != old_max_lane_count_limit)
+		link_params_changed = true;
+
+	if (link_params_changed)
+		connector->base.epoch_counter++;
 }
 
 static bool
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 004/108] drm/i915/dp_link_training: Introduce link training state struct
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (2 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 003/108] drm/i915/dp: Bump connector epoch on link capability changes Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 005/108] drm/i915/dp_link_training: Factor out link training state reset helper Imre Deak
                   ` (106 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Start isolating the link training state from the generic DP code by
introducing a separate intel_dp_link_training state struct.

Allocate the state so it can remain opaque within its own module.

Follow-up changes will move link training fields from the DP struct to
the link training state.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/g4x_dp.c         | 10 ++++-
 drivers/gpu/drm/i915/display/intel_ddi.c      | 18 ++++++++-
 .../drm/i915/display/intel_display_types.h    |  2 +
 drivers/gpu/drm/i915/display/intel_dp.c       | 31 +++++++++++++++
 drivers/gpu/drm/i915/display/intel_dp.h       |  3 ++
 .../drm/i915/display/intel_dp_link_training.c | 39 +++++++++++++++++++
 .../drm/i915/display/intel_dp_link_training.h |  4 ++
 7 files changed, 104 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c
index 5e74d8a3ba5c8..e1698172a8163 100644
--- a/drivers/gpu/drm/i915/display/g4x_dp.c
+++ b/drivers/gpu/drm/i915/display/g4x_dp.c
@@ -1252,10 +1252,13 @@ static void g4x_dp_suspend_complete(struct intel_encoder *encoder)
 
 static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
 {
+	struct intel_digital_port *dig_port = enc_to_dig_port(to_intel_encoder(encoder));
+
 	intel_dp_encoder_flush_work(encoder);
 
 	drm_encoder_cleanup(encoder);
-	kfree(enc_to_dig_port(to_intel_encoder(encoder)));
+	intel_dp_link_cleanup(&dig_port->dp);
+	kfree(dig_port);
 }
 
 static void intel_dp_encoder_reset(struct drm_encoder *encoder)
@@ -1350,6 +1353,9 @@ bool g4x_dp_init(struct intel_display *display,
 	intel_encoder->audio_enable = g4x_dp_audio_enable;
 	intel_encoder->audio_disable = g4x_dp_audio_disable;
 
+	if (intel_dp_link_init(&dig_port->dp) != 0)
+		goto err_dp_init;
+
 	if ((display->platform.ivybridge && port == PORT_A) ||
 	    (HAS_PCH_CPT(display) && port != PORT_A)) {
 		dig_port->dp.set_link_train = cpt_set_link_train;
@@ -1419,6 +1425,8 @@ bool g4x_dp_init(struct intel_display *display,
 	return true;
 
 err_init_connector:
+	intel_dp_link_cleanup(&dig_port->dp);
+err_dp_init:
 	drm_encoder_cleanup(encoder);
 err_encoder_init:
 	kfree(intel_connector);
diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c
index 2681940a5cfe3..f094830d34b92 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi.c
@@ -4656,6 +4656,7 @@ static void intel_ddi_encoder_destroy(struct drm_encoder *encoder)
 
 	drm_encoder_cleanup(encoder);
 	kfree(dig_port->hdcp.port_data.streams);
+	intel_dp_link_cleanup(&dig_port->dp);
 	kfree(dig_port);
 }
 
@@ -4693,11 +4694,16 @@ static int intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
 	struct intel_display *display = to_intel_display(dig_port);
 	struct intel_connector *connector;
 	enum port port = dig_port->base.port;
+	int err;
 
 	connector = intel_connector_alloc();
 	if (!connector)
 		return -ENOMEM;
 
+	err = intel_dp_link_init(&dig_port->dp);
+	if (err)
+		goto err_dp_init;
+
 	dig_port->dp.output_reg = DDI_BUF_CTL(port);
 	if (DISPLAY_VER(display) >= 14)
 		dig_port->dp.prepare_link_retrain = mtl_ddi_prepare_link_retrain;
@@ -4710,8 +4716,9 @@ static int intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
 	dig_port->dp.preemph_max = intel_ddi_dp_preemph_max;
 
 	if (!intel_dp_init_connector(dig_port, connector)) {
-		kfree(connector);
-		return -EINVAL;
+		err = -EINVAL;
+
+		goto err_init_connector;
 	}
 
 	if (dig_port->base.type == INTEL_OUTPUT_EDP) {
@@ -4727,6 +4734,13 @@ static int intel_ddi_init_dp_connector(struct intel_digital_port *dig_port)
 	}
 
 	return 0;
+
+err_init_connector:
+	intel_dp_link_cleanup(&dig_port->dp);
+err_dp_init:
+	kfree(connector);
+
+	return err;
 }
 
 static int intel_hdmi_reset_link(struct intel_encoder *encoder,
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index c819167618502..27714e4cffcdf 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -58,6 +58,7 @@ struct cec_notifier;
 struct drm_printer;
 struct intel_connector;
 struct intel_ddi_buf_trans;
+struct intel_dp_link_training;
 struct intel_fbc;
 struct intel_global_objs_state;
 struct intel_hdcp_shim;
@@ -1853,6 +1854,7 @@ struct intel_dp {
 		int seq_train_failures;
 		int force_train_failure;
 		bool force_retrain;
+		struct intel_dp_link_training *training;
 	} link;
 	bool reset_link_params;
 	int mso_link_count;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index df34df6610ac2..442610054d7f7 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -7526,3 +7526,34 @@ bool intel_dp_joiner_candidate_valid(struct intel_connector *connector,
 
 	return true;
 }
+
+/**
+ * intel_dp_link_init - initialize link state
+ * @intel_dp: DP encoder state
+ *
+ * Initialize the link state for @intel_dp and the connectors attached
+ * to it.
+ *
+ * Return:
+ * - %0 in case of successful initialization.
+ * - negative error code in case of failure.
+ */
+int intel_dp_link_init(struct intel_dp *intel_dp)
+{
+	intel_dp->link.training = intel_dp_link_training_init(intel_dp);
+	if (!intel_dp->link.training)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * intel_dp_link_cleanup - clean up link state
+ * @intel_dp: DP encoder state
+ *
+ * Clean up the link state for @intel_dp.
+ */
+void intel_dp_link_cleanup(struct intel_dp *intel_dp)
+{
+	intel_dp_link_training_cleanup(intel_dp->link.training);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 2849b9ecdc71a..f2abd6059a22a 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -238,4 +238,7 @@ bool intel_dp_joiner_candidate_valid(struct intel_connector *connector,
 	for ((__num_joined_pipes) = 1; (__num_joined_pipes) <= (I915_MAX_PIPES); (__num_joined_pipes)++) \
 		for_each_if(intel_dp_joiner_candidate_valid(__connector, (__mode)->hdisplay, __num_joined_pipes))
 
+int intel_dp_link_init(struct intel_dp *intel_dp);
+void intel_dp_link_cleanup(struct intel_dp *intel_dp);
+
 #endif /* __INTEL_DP_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index a26094223f780..c4e461d24e2ed 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -60,6 +60,10 @@
 
 #define MAX_SEQ_TRAIN_FAILURES 2
 
+struct intel_dp_link_training {
+	struct intel_dp *dp;
+};
+
 static void intel_dp_reset_lttpr_common_caps(struct intel_dp *intel_dp)
 {
 	memset(intel_dp->lttpr_common_caps, 0, sizeof(intel_dp->lttpr_common_caps));
@@ -2217,3 +2221,38 @@ void intel_dp_link_training_debugfs_add(struct intel_connector *connector)
 	debugfs_create_file("i915_dp_link_retrain_disabled", 0444, root,
 			    connector, &i915_dp_link_retrain_disabled_fops);
 }
+
+/**
+ * intel_dp_link_training_init - allocate and initialize link training state
+ * @intel_dp: DP encoder state
+ *
+ * Allocate and initialize the link training state for @intel_dp and the
+ * connectors attached to it.
+ *
+ * Return:
+ * - Pointer to the newly allocated link training state.
+ * - %NULL if allocation fails.
+ */
+struct intel_dp_link_training *intel_dp_link_training_init(struct intel_dp *intel_dp)
+{
+	struct intel_dp_link_training *link_training;
+
+	link_training = kzalloc_obj(*link_training);
+	if (!link_training)
+		return NULL;
+
+	link_training->dp = intel_dp;
+
+	return link_training;
+}
+
+/**
+ * intel_dp_link_training_cleanup - free link training state
+ * @link_training: link training state to free
+ *
+ * Free @link_training.
+ */
+void intel_dp_link_training_cleanup(struct intel_dp_link_training *link_training)
+{
+	kfree(link_training);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
index 33dcbde6a4089..e68d51bcb42e1 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
@@ -12,6 +12,7 @@ struct intel_atomic_state;
 struct intel_connector;
 struct intel_crtc_state;
 struct intel_dp;
+struct intel_dp_link_training;
 
 int intel_dp_read_dprx_caps(struct intel_dp *intel_dp, u8 dpcd[DP_RECEIVER_CAP_SIZE]);
 int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp);
@@ -55,4 +56,7 @@ void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp,
 
 void intel_dp_link_training_debugfs_add(struct intel_connector *connector);
 
+struct intel_dp_link_training *intel_dp_link_training_init(struct intel_dp *intel_dp);
+void intel_dp_link_training_cleanup(struct intel_dp_link_training *link_training);
+
 #endif /* __INTEL_DP_LINK_TRAINING_H__ */
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 005/108] drm/i915/dp_link_training: Factor out link training state reset helper
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (3 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 004/108] drm/i915/dp_link_training: Introduce link training state struct Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 006/108] drm/i915/dp_link_training: Reset link training state on link capability change Imre Deak
                   ` (105 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Factor out the link training state reset into a helper in
intel_dp_link_training.c to prepare for isolating the link training state
from the generic DP code.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c               | 3 +--
 drivers/gpu/drm/i915/display/intel_dp_link_training.c | 8 ++++++++
 drivers/gpu/drm/i915/display/intel_dp_link_training.h | 2 ++
 3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 442610054d7f7..ef7d5e55cc468 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -3728,8 +3728,7 @@ void intel_dp_reset_link_params(struct intel_dp *intel_dp)
 	intel_dp->link.max_rate = intel_dp_max_common_rate(intel_dp);
 	intel_dp->link.mst_probed_lane_count = 0;
 	intel_dp->link.mst_probed_rate = 0;
-	intel_dp->link.retrain_disabled = false;
-	intel_dp->link.seq_train_failures = 0;
+	intel_dp_link_training_reset(intel_dp->link.training);
 }
 
 /* Enable backlight PWM and backlight PP control. */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index c4e461d24e2ed..653b974e925c2 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -2222,6 +2222,14 @@ void intel_dp_link_training_debugfs_add(struct intel_connector *connector)
 			    connector, &i915_dp_link_retrain_disabled_fops);
 }
 
+void intel_dp_link_training_reset(struct intel_dp_link_training *link_training)
+{
+	struct intel_dp *intel_dp = link_training->dp;
+
+	intel_dp->link.retrain_disabled = false;
+	intel_dp->link.seq_train_failures = 0;
+}
+
 /**
  * intel_dp_link_training_init - allocate and initialize link training state
  * @intel_dp: DP encoder state
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
index e68d51bcb42e1..6c0c74e31a3c5 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
@@ -56,6 +56,8 @@ void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp,
 
 void intel_dp_link_training_debugfs_add(struct intel_connector *connector);
 
+void intel_dp_link_training_reset(struct intel_dp_link_training *link_training);
+
 struct intel_dp_link_training *intel_dp_link_training_init(struct intel_dp *intel_dp);
 void intel_dp_link_training_cleanup(struct intel_dp_link_training *link_training);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 006/108] drm/i915/dp_link_training: Reset link training state on link capability change
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (4 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 005/108] drm/i915/dp_link_training: Factor out link training state reset helper Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 007/108] drm/i915/dp_link_training: Flush commits in debugfs entries Imre Deak
                   ` (104 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Reset the link training state if the link capabilities change. This
re-enables automatic link retraining after it was disabled following
link training failures when fallback left no usable configuration. The
capability changes may enable a valid configuration, allowing retraining.

Also update the connector detect handler comment to note that link
state recheck may be needed due to re-enabled autoretraining.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index ef7d5e55cc468..d7c8ace38a01c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -6439,6 +6439,8 @@ intel_dp_detect(struct drm_connector *_connector,
 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
 	struct intel_encoder *encoder = &dig_port->base;
 	enum drm_connector_status status;
+	int old_epoch_counter =
+		connector->base.epoch_counter;
 	int ret;
 
 	drm_dbg_kms(display->drm, "[CONNECTOR:%d:%s]\n",
@@ -6522,6 +6524,8 @@ intel_dp_detect(struct drm_connector *_connector,
 	if (intel_dp->reset_link_params) {
 		intel_dp_reset_link_params(intel_dp);
 		intel_dp->reset_link_params = false;
+	} else if (connector->base.epoch_counter != old_epoch_counter) {
+		intel_dp_link_training_reset(intel_dp->link.training);
 	}
 
 	intel_dp_mst_configure(intel_dp);
@@ -6542,9 +6546,16 @@ intel_dp_detect(struct drm_connector *_connector,
 	 * Some external monitors do not signal loss of link synchronization
 	 * with an IRQ_HPD, so force a link status check.
 	 *
-	 * TODO: this probably became redundant, so remove it: the link state
-	 * is rechecked/recovered now after modesets, where the loss of
-	 * synchronization tends to occur.
+	 * NOTE: Handling link synchronization loss here is probably not
+	 * needed, since such loss tends to occur right after modesets, and
+	 * modesets already schedule a work item to recheck the link state.
+	 *
+	 * However, if the link is in an active unretrainable state and the
+	 * supported link configurations changed, either after an HPD
+	 * pulse-triggered link reset (via intel_dp_reset_link_params()) or
+	 * after a sink capability update without such a reset (via
+	 * intel_dp_set_common_rates()), the link state should be rechecked in
+	 * case the link became retrainable.
 	 */
 	if (!intel_dp_is_edp(intel_dp))
 		intel_dp_check_link_state(intel_dp);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 007/108] drm/i915/dp_link_training: Flush commits in debugfs entries
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (5 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 006/108] drm/i915/dp_link_training: Reset link training state on link capability change Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 008/108] drm/i915/dp_link_training: Move link training helpers to link training code Imre Deak
                   ` (103 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Flush pending connector commits before accessing the link training state
from debugfs. Access to connector state - like the link training state -
that may be updated from an asynchronous commit tail must hold the
connection mutex and wait for the tail to complete. The commit tail
cannot hold the connection mutex, so all other accessors must wait for
it explicitly.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c | 23 +++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 653b974e925c2..6dfb6b8db235e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1866,8 +1866,11 @@ static int i915_dp_force_link_rate_show(struct seq_file *m, void *data)
 	if (err)
 		return err;
 
+	intel_dp_flush_connector_commits(connector);
+
 	if (intel_dp->link.active)
 		current_rate = intel_dp->link_rate;
+
 	force_rate = intel_dp->link.force_rate;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
@@ -1939,6 +1942,8 @@ static ssize_t i915_dp_force_link_rate_write(struct file *file,
 	if (err)
 		return err;
 
+	intel_dp_flush_connector_commits(connector);
+
 	intel_dp_reset_link_params(intel_dp);
 	intel_dp->link.force_rate = rate;
 
@@ -1964,6 +1969,8 @@ static int i915_dp_force_lane_count_show(struct seq_file *m, void *data)
 	if (err)
 		return err;
 
+	intel_dp_flush_connector_commits(connector);
+
 	if (intel_dp->link.active)
 		current_lane_count = intel_dp->lane_count;
 	force_lane_count = intel_dp->link.force_lane_count;
@@ -2041,6 +2048,8 @@ static ssize_t i915_dp_force_lane_count_write(struct file *file,
 	if (err)
 		return err;
 
+	intel_dp_flush_connector_commits(connector);
+
 	intel_dp_reset_link_params(intel_dp);
 	intel_dp->link.force_lane_count = lane_count;
 
@@ -2063,6 +2072,8 @@ static int i915_dp_max_link_rate_show(void *data, u64 *val)
 	if (err)
 		return err;
 
+	intel_dp_flush_connector_commits(connector);
+
 	*val = intel_dp->link.max_rate;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
@@ -2082,6 +2093,8 @@ static int i915_dp_max_lane_count_show(void *data, u64 *val)
 	if (err)
 		return err;
 
+	intel_dp_flush_connector_commits(connector);
+
 	*val = intel_dp->link.max_lane_count;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
@@ -2101,6 +2114,8 @@ static int i915_dp_force_link_training_failure_show(void *data, u64 *val)
 	if (err)
 		return err;
 
+	intel_dp_flush_connector_commits(connector);
+
 	*val = intel_dp->link.force_train_failure;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
@@ -2122,6 +2137,8 @@ static int i915_dp_force_link_training_failure_write(void *data, u64 val)
 	if (err)
 		return err;
 
+	intel_dp_flush_connector_commits(connector);
+
 	intel_dp->link.force_train_failure = val;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
@@ -2143,6 +2160,8 @@ static int i915_dp_force_link_retrain_show(void *data, u64 *val)
 	if (err)
 		return err;
 
+	intel_dp_flush_connector_commits(connector);
+
 	*val = intel_dp->link.force_retrain;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
@@ -2161,6 +2180,8 @@ static int i915_dp_force_link_retrain_write(void *data, u64 val)
 	if (err)
 		return err;
 
+	intel_dp_flush_connector_commits(connector);
+
 	intel_dp->link.force_retrain = val;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
@@ -2184,6 +2205,8 @@ static int i915_dp_link_retrain_disabled_show(struct seq_file *m, void *data)
 	if (err)
 		return err;
 
+	intel_dp_flush_connector_commits(connector);
+
 	seq_printf(m, "%s\n", str_yes_no(intel_dp->link.retrain_disabled));
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 008/108] drm/i915/dp_link_training: Move link training helpers to link training code
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (6 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 007/108] drm/i915/dp_link_training: Flush commits in debugfs entries Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 009/108] drm/i915/dp_link_training: Use link_training as base pointer in debugfs Imre Deak
                   ` (102 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Move the link retraining helpers to intel_dp_link_training.c, next to the
other link training helpers.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       | 197 -----------------
 drivers/gpu/drm/i915/display/intel_dp.h       |   4 -
 .../drm/i915/display/intel_dp_link_training.c | 200 ++++++++++++++++++
 .../drm/i915/display/intel_dp_link_training.h |   7 +
 4 files changed, 207 insertions(+), 201 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index d7c8ace38a01c..3821686484483 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -845,25 +845,6 @@ static bool intel_dp_set_common_rates(struct intel_dp *intel_dp)
 	return link_params_changed;
 }
 
-bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
-				u8 lane_count)
-{
-	/*
-	 * FIXME: we need to synchronize the current link parameters with
-	 * hardware readout. Currently fast link training doesn't work on
-	 * boot-up.
-	 */
-	if (link_rate == 0 ||
-	    link_rate > intel_dp->link.max_rate)
-		return false;
-
-	if (lane_count == 0 ||
-	    lane_count > intel_dp_max_lane_count(intel_dp))
-		return false;
-
-	return true;
-}
-
 u32 intel_dp_mode_to_fec_clock(u32 mode_clock)
 {
 	return div_u64(mul_u32_u32(mode_clock, DP_DSC_FEC_OVERHEAD_FACTOR),
@@ -5626,32 +5607,6 @@ void intel_read_dp_sdp(struct intel_encoder *encoder,
 	}
 }
 
-static bool intel_dp_link_ok(struct intel_dp *intel_dp,
-			     u8 link_status[DP_LINK_STATUS_SIZE])
-{
-	struct intel_display *display = to_intel_display(intel_dp);
-	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
-	bool uhbr = intel_dp->link_rate >= 1000000;
-	bool ok;
-
-	if (uhbr)
-		ok = drm_dp_128b132b_lane_channel_eq_done(link_status,
-							  intel_dp->lane_count);
-	else
-		ok = drm_dp_channel_eq_ok(link_status, intel_dp->lane_count);
-
-	if (ok)
-		return true;
-
-	intel_dp_dump_link_status(intel_dp, DP_PHY_DPRX, link_status);
-	drm_dbg_kms(display->drm,
-		    "[ENCODER:%d:%s] %s link not ok, retraining\n",
-		    encoder->base.base.id, encoder->base.name,
-		    uhbr ? "128b/132b" : "8b/10b");
-
-	return false;
-}
-
 static void
 intel_dp_mst_hpd_irq(struct intel_dp *intel_dp, u8 *esi, u8 *ack)
 {
@@ -5758,78 +5713,6 @@ intel_dp_handle_hdmi_link_status_change(struct intel_dp *intel_dp)
 	}
 }
 
-static int
-intel_dp_read_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
-{
-	int err;
-
-	memset(link_status, 0, DP_LINK_STATUS_SIZE);
-
-	if (intel_dp_mst_active_streams(intel_dp) > 0)
-		err = drm_dp_dpcd_read_data(&intel_dp->aux, DP_LANE0_1_STATUS_ESI,
-					    link_status, DP_LINK_STATUS_SIZE - 2);
-	else
-		err = drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX,
-						       link_status);
-
-	if (err)
-		return err;
-
-	if (link_status[DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS] &
-	    DP_DOWNSTREAM_PORT_STATUS_CHANGED)
-		WRITE_ONCE(intel_dp->downstream_port_changed, true);
-
-	return 0;
-}
-
-static bool
-intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
-{
-	u8 link_status[DP_LINK_STATUS_SIZE];
-
-	if (!intel_dp->link.active)
-		return false;
-
-	/*
-	 * While PSR source HW is enabled, it will control main-link sending
-	 * frames, enabling and disabling it so trying to do a retrain will fail
-	 * as the link would or not be on or it could mix training patterns
-	 * and frame data at the same time causing retrain to fail.
-	 * Also when exiting PSR, HW will retrain the link anyways fixing
-	 * any link status error.
-	 */
-	if (intel_psr_enabled(intel_dp))
-		return false;
-
-	if (intel_dp->link.force_retrain)
-		return true;
-
-	if (intel_dp_read_link_status(intel_dp, link_status) < 0)
-		return false;
-
-	/*
-	 * Validate the cached values of intel_dp->link_rate and
-	 * intel_dp->lane_count before attempting to retrain.
-	 *
-	 * FIXME would be nice to user the crtc state here, but since
-	 * we need to call this from the short HPD handler that seems
-	 * a bit hard.
-	 */
-	if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
-					intel_dp->lane_count))
-		return false;
-
-	if (intel_dp->link.retrain_disabled)
-		return false;
-
-	if (intel_dp->link.seq_train_failures)
-		return true;
-
-	/* Retrain if link not ok */
-	return !intel_dp_link_ok(intel_dp, link_status) &&
-		!intel_psr_link_ok(intel_dp);
-}
-
 bool intel_dp_has_connector(struct intel_dp *intel_dp,
 			    const struct drm_connector_state *conn_state)
 {
@@ -5921,86 +5804,6 @@ void intel_dp_flush_connector_commits(struct intel_connector *connector)
 	wait_for_connector_hw_done(connector->base.state);
 }
 
-static bool intel_dp_is_connected(struct intel_dp *intel_dp)
-{
-	struct intel_connector *connector = intel_dp->attached_connector;
-
-	return connector->base.status == connector_status_connected ||
-		intel_dp->is_mst;
-}
-
-static int intel_dp_retrain_link(struct intel_encoder *encoder,
-				 struct drm_modeset_acquire_ctx *ctx)
-{
-	struct intel_display *display = to_intel_display(encoder);
-	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-	u8 pipe_mask;
-	int ret;
-
-	if (!intel_dp_is_connected(intel_dp))
-		return 0;
-
-	ret = drm_modeset_lock(&display->drm->mode_config.connection_mutex,
-			       ctx);
-	if (ret)
-		return ret;
-
-	if (!intel_dp_needs_link_retrain(intel_dp))
-		return 0;
-
-	ret = intel_dp_get_active_pipes(intel_dp, ctx, &pipe_mask);
-	if (ret)
-		return ret;
-
-	if (pipe_mask == 0)
-		return 0;
-
-	if (!intel_dp_needs_link_retrain(intel_dp))
-		return 0;
-
-	drm_dbg_kms(display->drm,
-		    "[ENCODER:%d:%s] retraining link (forced %s)\n",
-		    encoder->base.base.id, encoder->base.name,
-		    str_yes_no(intel_dp->link.force_retrain));
-
-	ret = intel_modeset_commit_pipes(display, pipe_mask, ctx);
-	if (ret == -EDEADLK)
-		return ret;
-
-	intel_dp->link.force_retrain = false;
-
-	if (ret)
-		drm_dbg_kms(display->drm,
-			    "[ENCODER:%d:%s] link retraining failed: %pe\n",
-			    encoder->base.base.id, encoder->base.name,
-			    ERR_PTR(ret));
-
-	return ret;
-}
-
-void intel_dp_link_check(struct intel_encoder *encoder)
-{
-	struct drm_modeset_acquire_ctx ctx;
-	int ret;
-
-	intel_modeset_lock_ctx_retry(&ctx, NULL, 0, ret)
-		ret = intel_dp_retrain_link(encoder, &ctx);
-}
-
-void intel_dp_check_link_state(struct intel_dp *intel_dp)
-{
-	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
-	struct intel_encoder *encoder = &dig_port->base;
-
-	if (!intel_dp_is_connected(intel_dp))
-		return;
-
-	if (!intel_dp_needs_link_retrain(intel_dp))
-		return;
-
-	intel_encoder_link_check_queue_work(encoder, 0);
-}
-
 static void intel_dp_handle_device_service_irq(struct intel_dp *intel_dp, u8 irq_mask)
 {
 	struct intel_display *display = to_intel_display(intel_dp);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index f2abd6059a22a..3c0d229eb1f55 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -56,8 +56,6 @@ int intel_dp_get_active_pipes(struct intel_dp *intel_dp,
 			      struct drm_modeset_acquire_ctx *ctx,
 			      u8 *pipe_mask);
 void intel_dp_flush_connector_commits(struct intel_connector *connector);
-void intel_dp_link_check(struct intel_encoder *encoder);
-void intel_dp_check_link_state(struct intel_dp *intel_dp);
 void intel_dp_set_power(struct intel_dp *intel_dp, u8 mode);
 void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp,
 					   const struct intel_crtc_state *crtc_state);
@@ -206,8 +204,6 @@ void intel_dp_get_dsc_sink_cap(u8 dpcd_rev,
 			       struct intel_connector *connector);
 bool intel_dp_has_gamut_metadata_dip(struct intel_encoder *encoder);
 
-bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
-				u8 lane_count);
 bool intel_dp_has_connector(struct intel_dp *intel_dp,
 			    const struct drm_connector_state *conn_state);
 int intel_dp_dsc_max_src_input_bpc(struct intel_display *display);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 6dfb6b8db235e..c2f9af251b6a9 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -33,9 +33,12 @@
 #include "intel_display_utils.h"
 #include "intel_dp.h"
 #include "intel_dp_link_training.h"
+#include "intel_dp_mst.h"
 #include "intel_encoder.h"
 #include "intel_hotplug.h"
+#include "intel_modeset_lock.h"
 #include "intel_panel.h"
+#include "intel_psr.h"
 
 #define LT_MSG_PREFIX			"[CONNECTOR:%d:%s][ENCODER:%d:%s][%s] "
 #define LT_MSG_ARGS(_intel_dp, _dp_phy)	(_intel_dp)->attached_connector->base.base.id, \
@@ -1852,6 +1855,203 @@ void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp,
 	lt_dbg(intel_dp, DP_PHY_DPRX, "DP2.0 SDP CRC16 for 128b/132b enabled\n");
 }
 
+bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
+				u8 lane_count)
+{
+	/*
+	 * FIXME: we need to synchronize the current link parameters with
+	 * hardware readout. Currently fast link training doesn't work on
+	 * boot-up.
+	 */
+	if (link_rate == 0 ||
+	    link_rate > intel_dp->link.max_rate)
+		return false;
+
+	if (lane_count == 0 ||
+	    lane_count > intel_dp_max_lane_count(intel_dp))
+		return false;
+
+	return true;
+}
+
+static bool intel_dp_link_ok(struct intel_dp *intel_dp,
+			     u8 link_status[DP_LINK_STATUS_SIZE])
+{
+	struct intel_display *display = to_intel_display(intel_dp);
+	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+	bool uhbr = intel_dp->link_rate >= 1000000;
+	bool ok;
+
+	if (uhbr)
+		ok = drm_dp_128b132b_lane_channel_eq_done(link_status,
+							  intel_dp->lane_count);
+	else
+		ok = drm_dp_channel_eq_ok(link_status, intel_dp->lane_count);
+
+	if (ok)
+		return true;
+
+	intel_dp_dump_link_status(intel_dp, DP_PHY_DPRX, link_status);
+	drm_dbg_kms(display->drm,
+		    "[ENCODER:%d:%s] %s link not ok, retraining\n",
+		    encoder->base.base.id, encoder->base.name,
+		    uhbr ? "128b/132b" : "8b/10b");
+
+	return false;
+}
+
+static int
+intel_dp_read_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
+{
+	int err;
+
+	memset(link_status, 0, DP_LINK_STATUS_SIZE);
+
+	if (intel_dp_mst_active_streams(intel_dp) > 0)
+		err = drm_dp_dpcd_read_data(&intel_dp->aux, DP_LANE0_1_STATUS_ESI,
+					    link_status, DP_LINK_STATUS_SIZE - 2);
+	else
+		err = drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX,
+						       link_status);
+
+	if (err)
+		return err;
+
+	if (link_status[DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS] &
+	    DP_DOWNSTREAM_PORT_STATUS_CHANGED)
+		WRITE_ONCE(intel_dp->downstream_port_changed, true);
+
+	return 0;
+}
+
+static bool
+intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
+{
+	u8 link_status[DP_LINK_STATUS_SIZE];
+
+	if (!intel_dp->link.active)
+		return false;
+
+	/*
+	 * While PSR source HW is enabled, it will control main-link sending
+	 * frames, enabling and disabling it so trying to do a retrain will fail
+	 * as the link would or not be on or it could mix training patterns
+	 * and frame data at the same time causing retrain to fail.
+	 * Also when exiting PSR, HW will retrain the link anyways fixing
+	 * any link status error.
+	 */
+	if (intel_psr_enabled(intel_dp))
+		return false;
+
+	if (intel_dp->link.force_retrain)
+		return true;
+
+	if (intel_dp_read_link_status(intel_dp, link_status) < 0)
+		return false;
+
+	/*
+	 * Validate the cached values of intel_dp->link_rate and
+	 * intel_dp->lane_count before attempting to retrain.
+	 *
+	 * FIXME would be nice to user the crtc state here, but since
+	 * we need to call this from the short HPD handler that seems
+	 * a bit hard.
+	 */
+	if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
+					intel_dp->lane_count))
+		return false;
+
+	if (intel_dp->link.retrain_disabled)
+		return false;
+
+	if (intel_dp->link.seq_train_failures)
+		return true;
+
+	/* Retrain if link not ok */
+	return !intel_dp_link_ok(intel_dp, link_status) &&
+		!intel_psr_link_ok(intel_dp);
+}
+
+static bool intel_dp_is_connected(struct intel_dp *intel_dp)
+{
+	struct intel_connector *connector = intel_dp->attached_connector;
+
+	return connector->base.status == connector_status_connected ||
+		intel_dp->is_mst;
+}
+
+static int intel_dp_retrain_link(struct intel_encoder *encoder,
+				 struct drm_modeset_acquire_ctx *ctx)
+{
+	struct intel_display *display = to_intel_display(encoder);
+	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+	u8 pipe_mask;
+	int ret;
+
+	if (!intel_dp_is_connected(intel_dp))
+		return 0;
+
+	ret = drm_modeset_lock(&display->drm->mode_config.connection_mutex,
+			       ctx);
+	if (ret)
+		return ret;
+
+	if (!intel_dp_needs_link_retrain(intel_dp))
+		return 0;
+
+	ret = intel_dp_get_active_pipes(intel_dp, ctx, &pipe_mask);
+	if (ret)
+		return ret;
+
+	if (pipe_mask == 0)
+		return 0;
+
+	if (!intel_dp_needs_link_retrain(intel_dp))
+		return 0;
+
+	drm_dbg_kms(display->drm,
+		    "[ENCODER:%d:%s] retraining link (forced %s)\n",
+		    encoder->base.base.id, encoder->base.name,
+		    str_yes_no(intel_dp->link.force_retrain));
+
+	ret = intel_modeset_commit_pipes(display, pipe_mask, ctx);
+	if (ret == -EDEADLK)
+		return ret;
+
+	intel_dp->link.force_retrain = false;
+
+	if (ret)
+		drm_dbg_kms(display->drm,
+			    "[ENCODER:%d:%s] link retraining failed: %pe\n",
+			    encoder->base.base.id, encoder->base.name,
+			    ERR_PTR(ret));
+
+	return ret;
+}
+
+void intel_dp_link_check(struct intel_encoder *encoder)
+{
+	struct drm_modeset_acquire_ctx ctx;
+	int ret;
+
+	intel_modeset_lock_ctx_retry(&ctx, NULL, 0, ret)
+		ret = intel_dp_retrain_link(encoder, &ctx);
+}
+
+void intel_dp_check_link_state(struct intel_dp *intel_dp)
+{
+	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+	struct intel_encoder *encoder = &dig_port->base;
+
+	if (!intel_dp_is_connected(intel_dp))
+		return;
+
+	if (!intel_dp_needs_link_retrain(intel_dp))
+		return;
+
+	intel_encoder_link_check_queue_work(encoder, 0);
+}
+
 static int i915_dp_force_link_rate_show(struct seq_file *m, void *data)
 {
 	struct intel_connector *connector = to_intel_connector(m->private);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
index 6c0c74e31a3c5..c1e57c6aa3a7d 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
@@ -13,6 +13,7 @@ struct intel_connector;
 struct intel_crtc_state;
 struct intel_dp;
 struct intel_dp_link_training;
+struct intel_encoder;
 
 int intel_dp_read_dprx_caps(struct intel_dp *intel_dp, u8 dpcd[DP_RECEIVER_CAP_SIZE]);
 int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp);
@@ -54,6 +55,12 @@ static inline u8 intel_dp_training_pattern_symbol(u8 pattern)
 void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp,
 				 const struct intel_crtc_state *crtc_state);
 
+bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
+				u8 lane_count);
+
+void intel_dp_link_check(struct intel_encoder *encoder);
+void intel_dp_check_link_state(struct intel_dp *intel_dp);
+
 void intel_dp_link_training_debugfs_add(struct intel_connector *connector);
 
 void intel_dp_link_training_reset(struct intel_dp_link_training *link_training);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 009/108] drm/i915/dp_link_training: Use link_training as base pointer in debugfs
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (7 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 008/108] drm/i915/dp_link_training: Move link training helpers to link training code Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 010/108] drm/i915/dp_link_training: Add helpers to access force retrain state Imre Deak
                   ` (101 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Retrieve the link_training pointer from the connector and derive the DP
pointer from it in debugfs entries.

This prepares for a follow-up change where values exposed via debugfs
entries will be retrieved from the link training state.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c | 25 +++++++++++++++----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index c2f9af251b6a9..1762e507dd1ec 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -67,6 +67,11 @@ struct intel_dp_link_training {
 	struct intel_dp *dp;
 };
 
+static struct intel_dp_link_training *connector_to_link_training(struct intel_connector *connector)
+{
+	return intel_attached_dp(connector)->link.training;
+}
+
 static void intel_dp_reset_lttpr_common_caps(struct intel_dp *intel_dp)
 {
 	memset(intel_dp->lttpr_common_caps, 0, sizeof(intel_dp->lttpr_common_caps));
@@ -2307,7 +2312,9 @@ static int i915_dp_force_link_training_failure_show(void *data, u64 *val)
 {
 	struct intel_connector *connector = to_intel_connector(data);
 	struct intel_display *display = to_intel_display(connector);
-	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_training *link_training =
+		connector_to_link_training(connector);
+	struct intel_dp *intel_dp = link_training->dp;
 	int err;
 
 	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
@@ -2327,7 +2334,9 @@ static int i915_dp_force_link_training_failure_write(void *data, u64 val)
 {
 	struct intel_connector *connector = to_intel_connector(data);
 	struct intel_display *display = to_intel_display(connector);
-	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_training *link_training =
+		connector_to_link_training(connector);
+	struct intel_dp *intel_dp = link_training->dp;
 	int err;
 
 	if (val > 2)
@@ -2353,7 +2362,9 @@ static int i915_dp_force_link_retrain_show(void *data, u64 *val)
 {
 	struct intel_connector *connector = to_intel_connector(data);
 	struct intel_display *display = to_intel_display(connector);
-	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_training *link_training =
+		connector_to_link_training(connector);
+	struct intel_dp *intel_dp = link_training->dp;
 	int err;
 
 	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
@@ -2373,7 +2384,9 @@ static int i915_dp_force_link_retrain_write(void *data, u64 val)
 {
 	struct intel_connector *connector = to_intel_connector(data);
 	struct intel_display *display = to_intel_display(connector);
-	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_training *link_training =
+		connector_to_link_training(connector);
+	struct intel_dp *intel_dp = link_training->dp;
 	int err;
 
 	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
@@ -2398,7 +2411,9 @@ static int i915_dp_link_retrain_disabled_show(struct seq_file *m, void *data)
 {
 	struct intel_connector *connector = to_intel_connector(m->private);
 	struct intel_display *display = to_intel_display(connector);
-	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_training *link_training =
+		connector_to_link_training(connector);
+	struct intel_dp *intel_dp = link_training->dp;
 	int err;
 
 	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 010/108] drm/i915/dp_link_training: Add helpers to access force retrain state
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (8 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 009/108] drm/i915/dp_link_training: Use link_training as base pointer in debugfs Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 011/108] drm/i915/dp_link_training: Move link recovery/debug state to link_training Imre Deak
                   ` (100 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add helpers to get and set the force retrain state in preparation for
moving the state from the DP struct to the link training state.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       |  2 +-
 .../drm/i915/display/intel_dp_link_training.c | 29 +++++++++++++++----
 .../drm/i915/display/intel_dp_link_training.h |  2 ++
 3 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 3821686484483..2ad65ef0f697e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -5640,7 +5640,7 @@ static bool
 intel_dp_check_mst_status(struct intel_dp *intel_dp)
 {
 	struct intel_display *display = to_intel_display(intel_dp);
-	bool force_retrain = intel_dp->link.force_retrain;
+	bool force_retrain = intel_dp_link_training_get_force_retrain(intel_dp->link.training);
 	bool reprobe_needed = false;
 
 	for (;;) {
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 1762e507dd1ec..72e023b733b33 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1929,9 +1929,25 @@ intel_dp_read_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STAT
 	return 0;
 }
 
+bool intel_dp_link_training_get_force_retrain(struct intel_dp_link_training *link_training)
+{
+	struct intel_dp *intel_dp = link_training->dp;
+
+	return intel_dp->link.force_retrain;
+}
+
+static void intel_dp_link_training_set_force_retrain(struct intel_dp_link_training *link_training,
+						     bool forced)
+{
+	struct intel_dp *intel_dp = link_training->dp;
+
+	intel_dp->link.force_retrain = forced;
+}
+
 static bool
 intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
 {
+	struct intel_dp_link_training *link_training = intel_dp->link.training;
 	u8 link_status[DP_LINK_STATUS_SIZE];
 
 	if (!intel_dp->link.active)
@@ -1948,7 +1964,7 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
 	if (intel_psr_enabled(intel_dp))
 		return false;
 
-	if (intel_dp->link.force_retrain)
+	if (intel_dp_link_training_get_force_retrain(link_training))
 		return true;
 
 	if (intel_dp_read_link_status(intel_dp, link_status) < 0)
@@ -1990,6 +2006,8 @@ static int intel_dp_retrain_link(struct intel_encoder *encoder,
 {
 	struct intel_display *display = to_intel_display(encoder);
 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+	struct intel_dp_link_training *link_training =
+		intel_dp->link.training;
 	u8 pipe_mask;
 	int ret;
 
@@ -2017,13 +2035,13 @@ static int intel_dp_retrain_link(struct intel_encoder *encoder,
 	drm_dbg_kms(display->drm,
 		    "[ENCODER:%d:%s] retraining link (forced %s)\n",
 		    encoder->base.base.id, encoder->base.name,
-		    str_yes_no(intel_dp->link.force_retrain));
+		    str_yes_no(intel_dp_link_training_get_force_retrain(link_training)));
 
 	ret = intel_modeset_commit_pipes(display, pipe_mask, ctx);
 	if (ret == -EDEADLK)
 		return ret;
 
-	intel_dp->link.force_retrain = false;
+	intel_dp_link_training_set_force_retrain(link_training, false);
 
 	if (ret)
 		drm_dbg_kms(display->drm,
@@ -2364,7 +2382,6 @@ static int i915_dp_force_link_retrain_show(void *data, u64 *val)
 	struct intel_display *display = to_intel_display(connector);
 	struct intel_dp_link_training *link_training =
 		connector_to_link_training(connector);
-	struct intel_dp *intel_dp = link_training->dp;
 	int err;
 
 	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
@@ -2373,7 +2390,7 @@ static int i915_dp_force_link_retrain_show(void *data, u64 *val)
 
 	intel_dp_flush_connector_commits(connector);
 
-	*val = intel_dp->link.force_retrain;
+	*val = intel_dp_link_training_get_force_retrain(link_training);
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
@@ -2395,7 +2412,7 @@ static int i915_dp_force_link_retrain_write(void *data, u64 val)
 
 	intel_dp_flush_connector_commits(connector);
 
-	intel_dp->link.force_retrain = val;
+	intel_dp_link_training_set_force_retrain(link_training, val);
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
index c1e57c6aa3a7d..f80e979f7436c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
@@ -58,6 +58,8 @@ void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp,
 bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
 				u8 lane_count);
 
+bool intel_dp_link_training_get_force_retrain(struct intel_dp_link_training *link_training);
+
 void intel_dp_link_check(struct intel_encoder *encoder);
 void intel_dp_check_link_state(struct intel_dp *intel_dp);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 011/108] drm/i915/dp_link_training: Move link recovery/debug state to link_training
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (9 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 010/108] drm/i915/dp_link_training: Add helpers to access force retrain state Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 012/108] drm/i915/dp_link_training: Prevent repeated autoretrain attempts Imre Deak
                   ` (99 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Move all state related to link recovery and link training debugging from
struct intel_dp to struct intel_dp_link_training.

This moves towards grouping all link training and recovery state and
logic in a single place and prepares for follow-up changes in the link
recovery state handling.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_display_types.h    |  5 --
 drivers/gpu/drm/i915/display/intel_dp.c       |  2 +-
 .../drm/i915/display/intel_dp_link_training.c | 52 +++++++++----------
 3 files changed, 27 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 27714e4cffcdf..dd61d958d5b6c 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1849,11 +1849,6 @@ struct intel_dp {
 		int mst_probed_rate;
 		int force_lane_count;
 		int force_rate;
-		bool retrain_disabled;
-		/* Sequential link training failures after a passing LT */
-		int seq_train_failures;
-		int force_train_failure;
-		bool force_retrain;
 		struct intel_dp_link_training *training;
 	} link;
 	bool reset_link_params;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 2ad65ef0f697e..3dc27dbf2bce8 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -5897,7 +5897,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
 	/*
 	 * Force checking the link status for DPCD_REV < 1.2
 	 * TODO: let the link status check depend on LINK_STATUS_CHANGED
-	 * or intel_dp->link.force_retrain for DPCD_REV >= 1.2
+	 * or intel_dp->link.training.force_retrain for DPCD_REV >= 1.2
 	 */
 	esi[3] |= LINK_STATUS_CHANGED;
 	if (intel_dp_handle_link_service_irq(intel_dp, esi[3]))
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 72e023b733b33..db1e03c15596d 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -65,6 +65,12 @@
 
 struct intel_dp_link_training {
 	struct intel_dp *dp;
+
+	bool retrain_disabled;
+	/* Sequential link training failures after a passing LT */
+	int seq_train_failures;
+	int force_train_failure;
+	bool force_retrain;
 };
 
 static struct intel_dp_link_training *connector_to_link_training(struct intel_connector *connector)
@@ -1262,6 +1268,7 @@ intel_dp_128b132b_intra_hop(struct intel_dp *intel_dp,
 void intel_dp_stop_link_train(struct intel_dp *intel_dp,
 			      const struct intel_crtc_state *crtc_state)
 {
+	struct intel_dp_link_training *link_training = intel_dp->link.training;
 	struct intel_display *display = to_intel_display(intel_dp);
 	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
 	int ret;
@@ -1282,8 +1289,8 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp,
 	intel_hpd_unblock(encoder);
 
 	if (!display->hotplug.ignore_long_hpd &&
-	    intel_dp->link.seq_train_failures < MAX_SEQ_TRAIN_FAILURES) {
-		int delay_ms = intel_dp->link.seq_train_failures ? 0 : 2000;
+	    link_training->seq_train_failures < MAX_SEQ_TRAIN_FAILURES) {
+		int delay_ms = link_training->seq_train_failures ? 0 : 2000;
 
 		intel_encoder_link_check_queue_work(encoder, delay_ms);
 	}
@@ -1776,6 +1783,8 @@ void intel_dp_start_link_train(struct intel_atomic_state *state,
 	struct intel_display *display = to_intel_display(state);
 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
 	struct intel_encoder *encoder = &dig_port->base;
+	struct intel_dp_link_training *link_training =
+		intel_dp->link.training;
 	bool passed;
 	/*
 	 * Reinit the LTTPRs here to ensure that they are switched to
@@ -1799,15 +1808,15 @@ void intel_dp_start_link_train(struct intel_atomic_state *state,
 	else
 		passed = intel_dp_link_train_all_phys(intel_dp, crtc_state, lttpr_count);
 
-	if (intel_dp->link.force_train_failure) {
-		intel_dp->link.force_train_failure--;
+	if (link_training->force_train_failure) {
+		link_training->force_train_failure--;
 		lt_dbg(intel_dp, DP_PHY_DPRX, "Forcing link training failure\n");
 	} else if (passed) {
-		intel_dp->link.seq_train_failures = 0;
+		link_training->seq_train_failures = 0;
 		return;
 	}
 
-	intel_dp->link.seq_train_failures++;
+	link_training->seq_train_failures++;
 
 	/*
 	 * Ignore the link failure in CI
@@ -1826,13 +1835,13 @@ void intel_dp_start_link_train(struct intel_atomic_state *state,
 		return;
 	}
 
-	if (intel_dp->link.seq_train_failures < MAX_SEQ_TRAIN_FAILURES)
+	if (link_training->seq_train_failures < MAX_SEQ_TRAIN_FAILURES)
 		return;
 
 	if (intel_dp_schedule_fallback_link_training(state, intel_dp, crtc_state))
 		return;
 
-	intel_dp->link.retrain_disabled = true;
+	link_training->retrain_disabled = true;
 
 	if (!passed)
 		lt_err(intel_dp, DP_PHY_DPRX, "Can't reduce link training parameters after failure\n");
@@ -1931,17 +1940,13 @@ intel_dp_read_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STAT
 
 bool intel_dp_link_training_get_force_retrain(struct intel_dp_link_training *link_training)
 {
-	struct intel_dp *intel_dp = link_training->dp;
-
-	return intel_dp->link.force_retrain;
+	return link_training->force_retrain;
 }
 
 static void intel_dp_link_training_set_force_retrain(struct intel_dp_link_training *link_training,
 						     bool forced)
 {
-	struct intel_dp *intel_dp = link_training->dp;
-
-	intel_dp->link.force_retrain = forced;
+	link_training->force_retrain = forced;
 }
 
 static bool
@@ -1982,10 +1987,10 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
 					intel_dp->lane_count))
 		return false;
 
-	if (intel_dp->link.retrain_disabled)
+	if (link_training->retrain_disabled)
 		return false;
 
-	if (intel_dp->link.seq_train_failures)
+	if (link_training->seq_train_failures)
 		return true;
 
 	/* Retrain if link not ok */
@@ -2332,7 +2337,6 @@ static int i915_dp_force_link_training_failure_show(void *data, u64 *val)
 	struct intel_display *display = to_intel_display(connector);
 	struct intel_dp_link_training *link_training =
 		connector_to_link_training(connector);
-	struct intel_dp *intel_dp = link_training->dp;
 	int err;
 
 	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
@@ -2341,7 +2345,7 @@ static int i915_dp_force_link_training_failure_show(void *data, u64 *val)
 
 	intel_dp_flush_connector_commits(connector);
 
-	*val = intel_dp->link.force_train_failure;
+	*val = link_training->force_train_failure;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
@@ -2354,7 +2358,6 @@ static int i915_dp_force_link_training_failure_write(void *data, u64 val)
 	struct intel_display *display = to_intel_display(connector);
 	struct intel_dp_link_training *link_training =
 		connector_to_link_training(connector);
-	struct intel_dp *intel_dp = link_training->dp;
 	int err;
 
 	if (val > 2)
@@ -2366,7 +2369,7 @@ static int i915_dp_force_link_training_failure_write(void *data, u64 val)
 
 	intel_dp_flush_connector_commits(connector);
 
-	intel_dp->link.force_train_failure = val;
+	link_training->force_train_failure = val;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
@@ -2430,7 +2433,6 @@ static int i915_dp_link_retrain_disabled_show(struct seq_file *m, void *data)
 	struct intel_display *display = to_intel_display(connector);
 	struct intel_dp_link_training *link_training =
 		connector_to_link_training(connector);
-	struct intel_dp *intel_dp = link_training->dp;
 	int err;
 
 	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
@@ -2439,7 +2441,7 @@ static int i915_dp_link_retrain_disabled_show(struct seq_file *m, void *data)
 
 	intel_dp_flush_connector_commits(connector);
 
-	seq_printf(m, "%s\n", str_yes_no(intel_dp->link.retrain_disabled));
+	seq_printf(m, "%s\n", str_yes_no(link_training->retrain_disabled));
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
@@ -2479,10 +2481,8 @@ void intel_dp_link_training_debugfs_add(struct intel_connector *connector)
 
 void intel_dp_link_training_reset(struct intel_dp_link_training *link_training)
 {
-	struct intel_dp *intel_dp = link_training->dp;
-
-	intel_dp->link.retrain_disabled = false;
-	intel_dp->link.seq_train_failures = 0;
+	link_training->retrain_disabled = false;
+	link_training->seq_train_failures = 0;
 }
 
 /**
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 012/108] drm/i915/dp_link_training: Prevent repeated autoretrain attempts
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (10 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 011/108] drm/i915/dp_link_training: Move link recovery/debug state to link_training Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 013/108] drm/i915/dp_link_training: Clamp sequential link training failure counter Imre Deak
                   ` (98 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

After a regular modeset link training failure, the driver attempts to
recover the link via an autoretrain using the same link parameters as
the modeset.

If the autoretrain fails as well, the set of allowed link configurations
is reduced via a fallback mechanism. For further link training, the
modeset parameters will likely need to change. This lowers the required
link bandwidth and allows selecting a link configuration from the
fallback-reduced set. Only userspace can perform such a modeset change.
Therefore, the driver notifies userspace to take over link recovery.

Userspace is expected to continue with the recovery attempt via a
modeset with updated parameters. The driver must not interfere with
these modesets.

link_training->seq_train_failures is set to MAX_SEQ_TRAIN_FAILURES after
the autoretrain fails. If a fallback selection also fails after this,
as no link configurations remain, retrain_disabled is set as well.

retrain_disabled is therefore somewhat misnamed: it indicates that no
fallback is available, not that autoretraining is disabled. This will be
addressed in a follow-up change by renaming the flag. For now, prevent
further autoretrain attempts based on the correct condition:
seq_train_failures == MAX_SEQ_TRAIN_FAILURES.

This also prepares for replacing the counter with an enum in a follow-up
change.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp_link_training.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index db1e03c15596d..54f506bbd6d1d 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1987,7 +1987,7 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
 					intel_dp->lane_count))
 		return false;
 
-	if (link_training->retrain_disabled)
+	if (link_training->seq_train_failures >= MAX_SEQ_TRAIN_FAILURES)
 		return false;
 
 	if (link_training->seq_train_failures)
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 013/108] drm/i915/dp_link_training: Clamp sequential link training failure counter
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (11 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 012/108] drm/i915/dp_link_training: Prevent repeated autoretrain attempts Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 014/108] drm/i915/dp_link_training: Check for pending autoretrain explicitly Imre Deak
                   ` (97 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Clamp link_training->seq_train_failures to MAX_SEQ_TRAIN_FAILURES to
avoid - an unlikely - overflow. This is ok, because the code only makes
a distinction between the cases where the counter is below or at the
limit.

This also prepares for replacing the counter with an enum in a follow-up
change.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp_link_training.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 54f506bbd6d1d..f58bce3e0a1d3 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1816,7 +1816,8 @@ void intel_dp_start_link_train(struct intel_atomic_state *state,
 		return;
 	}
 
-	link_training->seq_train_failures++;
+	if (link_training->seq_train_failures < MAX_SEQ_TRAIN_FAILURES)
+		link_training->seq_train_failures++;
 
 	/*
 	 * Ignore the link failure in CI
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 014/108] drm/i915/dp_link_training: Check for pending autoretrain explicitly
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (12 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 013/108] drm/i915/dp_link_training: Clamp sequential link training failure counter Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 015/108] drm/i915/dp_link_training: Add helper to query pending autoretrain Imre Deak
                   ` (96 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Check explicitly for a pending autoretrain by matching
seq_train_failures == 1.

This makes the actual condition clear, since at the point where the
counter is checked it is also below MAX_SEQ_TRAIN_FAILURES.

This also prepares for replacing the counter with an enum in a follow-up
change.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp_link_training.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index f58bce3e0a1d3..0c5b7816dfff9 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1290,7 +1290,7 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp,
 
 	if (!display->hotplug.ignore_long_hpd &&
 	    link_training->seq_train_failures < MAX_SEQ_TRAIN_FAILURES) {
-		int delay_ms = link_training->seq_train_failures ? 0 : 2000;
+		int delay_ms = link_training->seq_train_failures == 1 ? 0 : 2000;
 
 		intel_encoder_link_check_queue_work(encoder, delay_ms);
 	}
@@ -1991,7 +1991,7 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
 	if (link_training->seq_train_failures >= MAX_SEQ_TRAIN_FAILURES)
 		return false;
 
-	if (link_training->seq_train_failures)
+	if (link_training->seq_train_failures == 1)
 		return true;
 
 	/* Retrain if link not ok */
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 015/108] drm/i915/dp_link_training: Add helper to query pending autoretrain
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (13 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 014/108] drm/i915/dp_link_training: Check for pending autoretrain explicitly Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 016/108] drm/i915/dp_link_training: Add helper to query allowed autoretrain Imre Deak
                   ` (95 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add link_recovery_autoretrain_pending() to make it clearer what the
condition is about at its callers: an autoretrain work has been queued.

This also prepares for replacing the sequential link training failure
counter with an enum in a follow-up change.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c  | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 0c5b7816dfff9..77697a7619812 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1249,6 +1249,20 @@ intel_dp_128b132b_intra_hop(struct intel_dp *intel_dp,
 	return sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION ? 1 : 0;
 }
 
+/**
+ * link_recovery_autoretrain_pending - check for a pending automatic retraining
+ * @link_training: link training state
+ *
+ * Return:
+ * - %true  if automatic retraining is pending.
+ * - %false otherwise.
+ */
+static bool
+link_recovery_autoretrain_pending(struct intel_dp_link_training *link_training)
+{
+	return link_training->seq_train_failures == 1;
+}
+
 /**
  * intel_dp_stop_link_train - stop link training
  * @intel_dp: DP struct
@@ -1290,7 +1304,7 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp,
 
 	if (!display->hotplug.ignore_long_hpd &&
 	    link_training->seq_train_failures < MAX_SEQ_TRAIN_FAILURES) {
-		int delay_ms = link_training->seq_train_failures == 1 ? 0 : 2000;
+		int delay_ms = link_recovery_autoretrain_pending(link_training) ? 0 : 2000;
 
 		intel_encoder_link_check_queue_work(encoder, delay_ms);
 	}
@@ -1991,7 +2005,7 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
 	if (link_training->seq_train_failures >= MAX_SEQ_TRAIN_FAILURES)
 		return false;
 
-	if (link_training->seq_train_failures == 1)
+	if (link_recovery_autoretrain_pending(link_training))
 		return true;
 
 	/* Retrain if link not ok */
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 016/108] drm/i915/dp_link_training: Add helper to query allowed autoretrain
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (14 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 015/108] drm/i915/dp_link_training: Add helper to query pending autoretrain Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 017/108] drm/i915/dp_link_training: Add helper to mark link training failure Imre Deak
                   ` (94 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add link_recovery_autoretrain_allowed() to make it clearer what the
condition is about at its callers: queuing work for and starting an
autoretrain is allowed.

This also prepares for replacing the sequential link training failure
counter with an enum in a follow-up change.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c | 22 +++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 77697a7619812..1c2cef7d61f37 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1263,6 +1263,20 @@ link_recovery_autoretrain_pending(struct intel_dp_link_training *link_training)
 	return link_training->seq_train_failures == 1;
 }
 
+/**
+ * link_recovery_autoretrain_allowed - check for an allowed automatic retraining
+ * @link_training: link training state
+ *
+ * Return:
+ * - %true  if automatic retraining is allowed.
+ * - %false otherwise.
+ */
+static bool
+link_recovery_autoretrain_allowed(struct intel_dp_link_training *link_training)
+{
+	return link_training->seq_train_failures < MAX_SEQ_TRAIN_FAILURES;
+}
+
 /**
  * intel_dp_stop_link_train - stop link training
  * @intel_dp: DP struct
@@ -1303,7 +1317,7 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp,
 	intel_hpd_unblock(encoder);
 
 	if (!display->hotplug.ignore_long_hpd &&
-	    link_training->seq_train_failures < MAX_SEQ_TRAIN_FAILURES) {
+	    link_recovery_autoretrain_allowed(link_training)) {
 		int delay_ms = link_recovery_autoretrain_pending(link_training) ? 0 : 2000;
 
 		intel_encoder_link_check_queue_work(encoder, delay_ms);
@@ -1830,7 +1844,7 @@ void intel_dp_start_link_train(struct intel_atomic_state *state,
 		return;
 	}
 
-	if (link_training->seq_train_failures < MAX_SEQ_TRAIN_FAILURES)
+	if (link_recovery_autoretrain_allowed(link_training))
 		link_training->seq_train_failures++;
 
 	/*
@@ -1850,7 +1864,7 @@ void intel_dp_start_link_train(struct intel_atomic_state *state,
 		return;
 	}
 
-	if (link_training->seq_train_failures < MAX_SEQ_TRAIN_FAILURES)
+	if (link_recovery_autoretrain_allowed(link_training))
 		return;
 
 	if (intel_dp_schedule_fallback_link_training(state, intel_dp, crtc_state))
@@ -2002,7 +2016,7 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
 					intel_dp->lane_count))
 		return false;
 
-	if (link_training->seq_train_failures >= MAX_SEQ_TRAIN_FAILURES)
+	if (!link_recovery_autoretrain_allowed(link_training))
 		return false;
 
 	if (link_recovery_autoretrain_pending(link_training))
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 017/108] drm/i915/dp_link_training: Add helper to mark link training failure
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (15 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 016/108] drm/i915/dp_link_training: Add helper to query allowed autoretrain Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:50 ` [PATCH 018/108] drm/i915/dp_link_training: Add helper to reset link recovery state Imre Deak
                   ` (93 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add link_recovery_mark_train_failure() to record the failure and make
the link recovery state transition explicit after a link training
failure: recovery can continue with an autoretrain, or must be handed
over to userspace after fallback selection.

This also prepares for replacing the sequential link training failure
counter with an enum in a follow-up change.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c | 33 +++++++++++++++++--
 1 file changed, 30 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 1c2cef7d61f37..eb922dca69c5b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1277,6 +1277,33 @@ link_recovery_autoretrain_allowed(struct intel_dp_link_training *link_training)
 	return link_training->seq_train_failures < MAX_SEQ_TRAIN_FAILURES;
 }
 
+/**
+ * link_recovery_mark_train_failure - record a link training failure
+ * @link_training: link training state
+ *
+ * Record a link training failure and advance the recovery state to
+ * indicate the next required recovery step.
+ *
+ * The caller must proceed with recovery as instructed by the return
+ * value, either via automatic retraining or, once automatic retraining
+ * is no longer possible, via userspace modesets after fallback
+ * selection.
+ *
+ * Return:
+ * - %true  if recovery should continue via automatic retraining.
+ * - %false if automatic retraining is no longer possible and recovery
+ *          must be delegated to userspace.
+ */
+static bool
+link_recovery_mark_train_failure(struct intel_dp_link_training *link_training)
+{
+	if (link_recovery_autoretrain_allowed(link_training))
+		/* Move to autoretrain pending or autoretrain disabled state. */
+		link_training->seq_train_failures++;
+
+	return link_recovery_autoretrain_allowed(link_training);
+}
+
 /**
  * intel_dp_stop_link_train - stop link training
  * @intel_dp: DP struct
@@ -1813,6 +1840,7 @@ void intel_dp_start_link_train(struct intel_atomic_state *state,
 	struct intel_encoder *encoder = &dig_port->base;
 	struct intel_dp_link_training *link_training =
 		intel_dp->link.training;
+	bool can_autoretrain;
 	bool passed;
 	/*
 	 * Reinit the LTTPRs here to ensure that they are switched to
@@ -1844,8 +1872,7 @@ void intel_dp_start_link_train(struct intel_atomic_state *state,
 		return;
 	}
 
-	if (link_recovery_autoretrain_allowed(link_training))
-		link_training->seq_train_failures++;
+	can_autoretrain = link_recovery_mark_train_failure(link_training);
 
 	/*
 	 * Ignore the link failure in CI
@@ -1864,7 +1891,7 @@ void intel_dp_start_link_train(struct intel_atomic_state *state,
 		return;
 	}
 
-	if (link_recovery_autoretrain_allowed(link_training))
+	if (can_autoretrain)
 		return;
 
 	if (intel_dp_schedule_fallback_link_training(state, intel_dp, crtc_state))
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 018/108] drm/i915/dp_link_training: Add helper to reset link recovery state
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (16 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 017/108] drm/i915/dp_link_training: Add helper to mark link training failure Imre Deak
@ 2026-04-28 12:50 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 019/108] drm/i915/dp_link_training: Track link recovery state with an enum Imre Deak
                   ` (92 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:50 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add link_recovery_reset() to make it explicit when link recovery is no
longer needed and the recovery state can be cleared.

This also prepares for replacing the sequential link training failure
counter with an enum in a follow-up change.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c    | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index eb922dca69c5b..90bd1b0f1ab7d 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1304,6 +1304,18 @@ link_recovery_mark_train_failure(struct intel_dp_link_training *link_training)
 	return link_recovery_autoretrain_allowed(link_training);
 }
 
+/**
+ * link_recovery_reset - reset the link recovery state
+ * @link_training: link training state
+ *
+ * Reset the link recovery state to indicate that no link recovery is
+ * required.
+ */
+static void link_recovery_reset(struct intel_dp_link_training *link_training)
+{
+	link_training->seq_train_failures = 0;
+}
+
 /**
  * intel_dp_stop_link_train - stop link training
  * @intel_dp: DP struct
@@ -1868,7 +1880,7 @@ void intel_dp_start_link_train(struct intel_atomic_state *state,
 		link_training->force_train_failure--;
 		lt_dbg(intel_dp, DP_PHY_DPRX, "Forcing link training failure\n");
 	} else if (passed) {
-		link_training->seq_train_failures = 0;
+		link_recovery_reset(link_training);
 		return;
 	}
 
@@ -2538,7 +2550,7 @@ void intel_dp_link_training_debugfs_add(struct intel_connector *connector)
 void intel_dp_link_training_reset(struct intel_dp_link_training *link_training)
 {
 	link_training->retrain_disabled = false;
-	link_training->seq_train_failures = 0;
+	link_recovery_reset(link_training);
 }
 
 /**
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 019/108] drm/i915/dp_link_training: Track link recovery state with an enum
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (17 preceding siblings ...)
  2026-04-28 12:50 ` [PATCH 018/108] drm/i915/dp_link_training: Add helper to reset link recovery state Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 020/108] drm/i915/dp_link_training: Add no-fallback link recovery state Imre Deak
                   ` (91 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Replace the sequential link training failure counter with an explicit
link recovery state enum.

This makes the recovery states and transitions clearer: idle, automatic
retraining pending, and automatic retraining disabled.

A follow-up change will also move the retrain_disabled flag into this
enum.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c | 55 ++++++++++++++++---
 1 file changed, 48 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 90bd1b0f1ab7d..c44416e0e328f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -61,14 +61,54 @@
 		lt_dbg(_intel_dp, _dp_phy, "Sink disconnected: " _format, ## __VA_ARGS__); \
 } while (0)
 
-#define MAX_SEQ_TRAIN_FAILURES 2
+/**
+ * enum intel_dp_link_recovery_state - LT recovery state
+ * @INTEL_DP_LINK_RECOVERY_IDLE:
+ *   No link training failure is currently tracked and no recovery is
+ *   in progress. This is the initial state after driver initialization,
+ *   power state transitions, sink (re-)connection, or after a successful
+ *   link training.
+ *
+ * @INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING:
+ *   A first link training failure has been observed and an automatic
+ *   retraining attempt with the same link parameters is pending. Exactly
+ *   one such attempt is allowed before switching to userspace-driven
+ *   recovery.
+ *
+ * @INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED:
+ *   Automatic retraining is no longer possible. At this point, a
+ *   fallback selection is made and userspace is notified to take over
+ *   recovery, performing modesets with parameters it determines are
+ *   required. The driver then selects a link configuration from the
+ *   remaining fallback configuration set. Subsequent link training
+ *   failures trigger further fallback selections and userspace
+ *   notifications.
+ *
+ * Describes the link recovery state used by the Intel DP link recovery
+ * logic.
+ *
+ * See also:
+ *   - link_recovery_autoretrain_pending()
+ *   - link_recovery_autoretrain_allowed()
+ *   - link_recovery_mark_train_failure()
+ *   - link_recovery_reset()
+ */
+enum intel_dp_link_recovery_state {
+	/*
+	 * Keep the enum values ordered from least to most severe
+	 * recovery state; helper logic relies on that ordering.
+	 */
+	INTEL_DP_LINK_RECOVERY_IDLE,
+	INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING,
+	INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED,
+};
 
 struct intel_dp_link_training {
 	struct intel_dp *dp;
 
+	enum intel_dp_link_recovery_state recovery_state;
+
 	bool retrain_disabled;
-	/* Sequential link training failures after a passing LT */
-	int seq_train_failures;
 	int force_train_failure;
 	bool force_retrain;
 };
@@ -1260,7 +1300,7 @@ intel_dp_128b132b_intra_hop(struct intel_dp *intel_dp,
 static bool
 link_recovery_autoretrain_pending(struct intel_dp_link_training *link_training)
 {
-	return link_training->seq_train_failures == 1;
+	return link_training->recovery_state == INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING;
 }
 
 /**
@@ -1274,7 +1314,7 @@ link_recovery_autoretrain_pending(struct intel_dp_link_training *link_training)
 static bool
 link_recovery_autoretrain_allowed(struct intel_dp_link_training *link_training)
 {
-	return link_training->seq_train_failures < MAX_SEQ_TRAIN_FAILURES;
+	return link_training->recovery_state < INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED;
 }
 
 /**
@@ -1299,11 +1339,12 @@ link_recovery_mark_train_failure(struct intel_dp_link_training *link_training)
 {
 	if (link_recovery_autoretrain_allowed(link_training))
 		/* Move to autoretrain pending or autoretrain disabled state. */
-		link_training->seq_train_failures++;
+		link_training->recovery_state++;
 
 	return link_recovery_autoretrain_allowed(link_training);
 }
 
+
 /**
  * link_recovery_reset - reset the link recovery state
  * @link_training: link training state
@@ -1313,7 +1354,7 @@ link_recovery_mark_train_failure(struct intel_dp_link_training *link_training)
  */
 static void link_recovery_reset(struct intel_dp_link_training *link_training)
 {
-	link_training->seq_train_failures = 0;
+	link_training->recovery_state = INTEL_DP_LINK_RECOVERY_IDLE;
 }
 
 /**
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 020/108] drm/i915/dp_link_training: Add no-fallback link recovery state
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (18 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 019/108] drm/i915/dp_link_training: Track link recovery state with an enum Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 021/108] drm/i915/display: Factor out a helper to modeset a pipe with atomic state Imre Deak
                   ` (90 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Replace the misnamed retrain_disabled flag with a dedicated link
recovery state indicating that no fallback link configurations remain.

This clarifies the meaning of the state: it has always represented the
situation where no further fallback link configurations are available.

While at it, add a TODO comment to the debugfs entry, to expose this
state via a more appropriately named entry.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c | 43 +++++++++++++++++--
 1 file changed, 39 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index c44416e0e328f..cbabf01d4b670 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -84,13 +84,21 @@
  *   failures trigger further fallback selections and userspace
  *   notifications.
  *
+ * @INTEL_DP_LINK_RECOVERY_NO_FALLBACK:
+ *   Fallback selection is no longer possible, as no usable fallback link
+ *   configurations remain. Recovery must proceed via userspace modesets
+ *   using the remaining allowed link configuration. Userspace continues
+ *   to be notified of subsequent link training failures.
+ *
  * Describes the link recovery state used by the Intel DP link recovery
  * logic.
  *
  * See also:
  *   - link_recovery_autoretrain_pending()
  *   - link_recovery_autoretrain_allowed()
+ *   - link_recovery_has_no_fallback()
  *   - link_recovery_mark_train_failure()
+ *   - link_recovery_mark_no_fallback()
  *   - link_recovery_reset()
  */
 enum intel_dp_link_recovery_state {
@@ -101,6 +109,7 @@ enum intel_dp_link_recovery_state {
 	INTEL_DP_LINK_RECOVERY_IDLE,
 	INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING,
 	INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED,
+	INTEL_DP_LINK_RECOVERY_NO_FALLBACK,
 };
 
 struct intel_dp_link_training {
@@ -108,7 +117,6 @@ struct intel_dp_link_training {
 
 	enum intel_dp_link_recovery_state recovery_state;
 
-	bool retrain_disabled;
 	int force_train_failure;
 	bool force_retrain;
 };
@@ -1317,6 +1325,22 @@ link_recovery_autoretrain_allowed(struct intel_dp_link_training *link_training)
 	return link_training->recovery_state < INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED;
 }
 
+/**
+ * link_recovery_has_no_fallback - check whether fallback is unavailable
+ * @link_training: link training state
+ *
+ * Check whether link fallback configurations are unavailable.
+ *
+ * Return:
+ * - %true  if fallback is unavailable.
+ * - %false otherwise.
+ */
+static bool
+link_recovery_has_no_fallback(struct intel_dp_link_training *link_training)
+{
+	return link_training->recovery_state == INTEL_DP_LINK_RECOVERY_NO_FALLBACK;
+}
+
 /**
  * link_recovery_mark_train_failure - record a link training failure
  * @link_training: link training state
@@ -1344,6 +1368,17 @@ link_recovery_mark_train_failure(struct intel_dp_link_training *link_training)
 	return link_recovery_autoretrain_allowed(link_training);
 }
 
+/**
+ * link_recovery_mark_no_fallback - record that fallback is unavailable
+ * @link_training: link training state
+ *
+ * Record that no more link fallback configuration is available.
+ */
+static void
+link_recovery_mark_no_fallback(struct intel_dp_link_training *link_training)
+{
+	link_training->recovery_state = INTEL_DP_LINK_RECOVERY_NO_FALLBACK;
+}
 
 /**
  * link_recovery_reset - reset the link recovery state
@@ -1950,7 +1985,7 @@ void intel_dp_start_link_train(struct intel_atomic_state *state,
 	if (intel_dp_schedule_fallback_link_training(state, intel_dp, crtc_state))
 		return;
 
-	link_training->retrain_disabled = true;
+	link_recovery_mark_no_fallback(link_training);
 
 	if (!passed)
 		lt_err(intel_dp, DP_PHY_DPRX, "Can't reduce link training parameters after failure\n");
@@ -2550,7 +2585,8 @@ static int i915_dp_link_retrain_disabled_show(struct seq_file *m, void *data)
 
 	intel_dp_flush_connector_commits(connector);
 
-	seq_printf(m, "%s\n", str_yes_no(link_training->retrain_disabled));
+	/* TODO: Expose this via a debugfs entry reflecting what the state represents. */
+	seq_printf(m, "%s\n", str_yes_no(link_recovery_has_no_fallback(link_training)));
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
@@ -2590,7 +2626,6 @@ void intel_dp_link_training_debugfs_add(struct intel_connector *connector)
 
 void intel_dp_link_training_reset(struct intel_dp_link_training *link_training)
 {
-	link_training->retrain_disabled = false;
 	link_recovery_reset(link_training);
 }
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 021/108] drm/i915/display: Factor out a helper to modeset a pipe with atomic state
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (19 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 020/108] drm/i915/dp_link_training: Add no-fallback link recovery state Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 022/108] drm/i915/display: Simplify intel_modeset_commit_pipes_for_atomic_state() Imre Deak
                   ` (89 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Factor out a helper modesetting a pipe that accepts an existing atomic
state. This prepares for a follow-up change that needs to allocate its
own atomic state.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_display.c | 30 ++++++++++++++------
 drivers/gpu/drm/i915/display/intel_display.h |  3 ++
 2 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 674a4ece6d0f9..560b057ec163d 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -5629,18 +5629,15 @@ int intel_modeset_all_pipes_late(struct intel_atomic_state *state,
 	return 0;
 }
 
-int intel_modeset_commit_pipes(struct intel_display *display,
-			       u8 pipe_mask,
-			       struct drm_modeset_acquire_ctx *ctx)
+int intel_modeset_commit_pipes_for_atomic_state(struct intel_atomic_state *intel_state,
+						u8 pipe_mask,
+						struct drm_modeset_acquire_ctx *ctx)
 {
-	struct drm_atomic_state *state;
+	struct drm_atomic_state *state = &intel_state->base;
+	struct intel_display *display = to_intel_display(intel_state);
 	struct intel_crtc *crtc;
 	int ret;
 
-	state = drm_atomic_state_alloc(display->drm);
-	if (!state)
-		return -ENOMEM;
-
 	state->acquire_ctx = ctx;
 	to_intel_atomic_state(state)->internal = true;
 
@@ -5658,6 +5655,23 @@ int intel_modeset_commit_pipes(struct intel_display *display,
 
 	ret = drm_atomic_commit(state);
 out:
+	return ret;
+}
+
+int intel_modeset_commit_pipes(struct intel_display *display,
+			       u8 pipe_mask,
+			       struct drm_modeset_acquire_ctx *ctx)
+{
+	struct drm_atomic_state *state;
+	int ret;
+
+	state = drm_atomic_state_alloc(display->drm);
+	if (!state)
+		return -ENOMEM;
+
+	ret = intel_modeset_commit_pipes_for_atomic_state(to_intel_atomic_state(state),
+							  pipe_mask, ctx);
+
 	drm_atomic_state_put(state);
 
 	return ret;
diff --git a/drivers/gpu/drm/i915/display/intel_display.h b/drivers/gpu/drm/i915/display/intel_display.h
index 1e76a455d7c43..79e42bfd15e70 100644
--- a/drivers/gpu/drm/i915/display/intel_display.h
+++ b/drivers/gpu/drm/i915/display/intel_display.h
@@ -478,6 +478,9 @@ int intel_modeset_pipes_in_mask_early(struct intel_atomic_state *state,
 				      const char *reason, u8 pipe_mask);
 int intel_modeset_all_pipes_late(struct intel_atomic_state *state,
 				 const char *reason);
+int intel_modeset_commit_pipes_for_atomic_state(struct intel_atomic_state *state,
+						u8 pipe_mask,
+						struct drm_modeset_acquire_ctx *ctx);
 int intel_modeset_commit_pipes(struct intel_display *display,
 			       u8 pipe_mask,
 			       struct drm_modeset_acquire_ctx *ctx);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 022/108] drm/i915/display: Simplify intel_modeset_commit_pipes_for_atomic_state()
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (20 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 021/108] drm/i915/display: Factor out a helper to modeset a pipe with atomic state Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 023/108] drm/i915/dp_link_training: Allocate atomic state for autoretrain modeset Imre Deak
                   ` (88 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Simplify accessing the DRM atomic state via the intel atomic state
in intel_modeset_commit_pipes_for_atomic_state(), which also allows
dropping the cached DRM state pointer. Also streamline the success/error
return flows.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_display.c | 22 +++++++-------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 560b057ec163d..f13aaaf2ea1de 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -5629,33 +5629,27 @@ int intel_modeset_all_pipes_late(struct intel_atomic_state *state,
 	return 0;
 }
 
-int intel_modeset_commit_pipes_for_atomic_state(struct intel_atomic_state *intel_state,
+int intel_modeset_commit_pipes_for_atomic_state(struct intel_atomic_state *state,
 						u8 pipe_mask,
 						struct drm_modeset_acquire_ctx *ctx)
 {
-	struct drm_atomic_state *state = &intel_state->base;
-	struct intel_display *display = to_intel_display(intel_state);
+	struct intel_display *display = to_intel_display(state);
 	struct intel_crtc *crtc;
-	int ret;
 
-	state->acquire_ctx = ctx;
-	to_intel_atomic_state(state)->internal = true;
+	state->base.acquire_ctx = ctx;
+	state->internal = true;
 
 	for_each_intel_crtc_in_pipe_mask(display->drm, crtc, pipe_mask) {
 		struct intel_crtc_state *crtc_state =
-			intel_atomic_get_crtc_state(state, crtc);
+			intel_atomic_get_crtc_state(&state->base, crtc);
 
-		if (IS_ERR(crtc_state)) {
-			ret = PTR_ERR(crtc_state);
-			goto out;
-		}
+		if (IS_ERR(crtc_state))
+			return PTR_ERR(crtc_state);
 
 		crtc_state->uapi.connectors_changed = true;
 	}
 
-	ret = drm_atomic_commit(state);
-out:
-	return ret;
+	return drm_atomic_commit(&state->base);
 }
 
 int intel_modeset_commit_pipes(struct intel_display *display,
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 023/108] drm/i915/dp_link_training: Allocate atomic state for autoretrain modeset
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (21 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 022/108] drm/i915/display: Simplify intel_modeset_commit_pipes_for_atomic_state() Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 024/108] drm/i915/dp_link_training: Disallow autoretrains after failed modeset Imre Deak
                   ` (87 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Allocate a local atomic state for the autoretrain modeset. This
prepares for a follow-up change that needs to access the state after
the modeset for sending userspace notifications.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_training.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index cbabf01d4b670..b446a3523b94c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -27,6 +27,7 @@
 #include <drm/display/drm_dp_helper.h>
 #include <drm/drm_print.h>
 
+#include "intel_display.h"
 #include "intel_display_core.h"
 #include "intel_display_jiffies.h"
 #include "intel_display_types.h"
@@ -2157,6 +2158,8 @@ static int intel_dp_retrain_link(struct intel_encoder *encoder,
 	struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 	struct intel_dp_link_training *link_training =
 		intel_dp->link.training;
+	struct intel_atomic_state *state;
+	struct drm_atomic_state *_state;
 	u8 pipe_mask;
 	int ret;
 
@@ -2186,9 +2189,15 @@ static int intel_dp_retrain_link(struct intel_encoder *encoder,
 		    encoder->base.base.id, encoder->base.name,
 		    str_yes_no(intel_dp_link_training_get_force_retrain(link_training)));
 
-	ret = intel_modeset_commit_pipes(display, pipe_mask, ctx);
+	_state = drm_atomic_state_alloc(display->drm);
+	if (!_state)
+		return -ENOMEM;
+
+	state = to_intel_atomic_state(_state);
+
+	ret = intel_modeset_commit_pipes_for_atomic_state(state, pipe_mask, ctx);
 	if (ret == -EDEADLK)
-		return ret;
+		goto out;
 
 	intel_dp_link_training_set_force_retrain(link_training, false);
 
@@ -2197,6 +2206,8 @@ static int intel_dp_retrain_link(struct intel_encoder *encoder,
 			    "[ENCODER:%d:%s] link retraining failed: %pe\n",
 			    encoder->base.base.id, encoder->base.name,
 			    ERR_PTR(ret));
+out:
+	drm_atomic_state_put(&state->base);
 
 	return ret;
 }
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 024/108] drm/i915/dp_link_training: Disallow autoretrains after failed modeset
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (22 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 023/108] drm/i915/dp_link_training: Allocate atomic state for autoretrain modeset Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 025/108] drm/i915/dp_link_training: Fix kernel-doc of intel_dp_init_lttpr_and_dprx_caps() Imre Deak
                   ` (86 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

intel_dp_check_link_state() and intel_dp_link_params_valid() perform
only a coarse validation of the link configuration used by the active
mode against the available configurations (as constrained by the link
training fallback code after a previous LT failure). Even if these
coarse checks find a seemingly usable configuration, the modeset check,
which performs full verification, may still fail.

Disallow further autoretrain attempts if an autoretrain modeset fails.
Further attempts would just reuse the same modeset parameters and fail
in the same way. Autoretrain will be reallowed unconditionally when the
sink reports a change in its capabilities. This allows an autoretrain to
proceed once both the link validation and modeset checks confirm a
usable configuration.

Also clarify in intel_dp_check_link_state() and
intel_dp_link_params_valid() that these checks are coarse and that a
full validation is only performed by the subsequent atomic modeset
check.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c | 98 ++++++++++++++++++-
 1 file changed, 96 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index b446a3523b94c..37862b915cf6e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -99,6 +99,7 @@
  *   - link_recovery_autoretrain_allowed()
  *   - link_recovery_has_no_fallback()
  *   - link_recovery_mark_train_failure()
+ *   - link_recovery_mark_autoretrain_modeset_failure()
  *   - link_recovery_mark_no_fallback()
  *   - link_recovery_reset()
  */
@@ -1354,6 +1355,13 @@ link_recovery_has_no_fallback(struct intel_dp_link_training *link_training)
  * is no longer possible, via userspace modesets after fallback
  * selection.
  *
+ * Note that the error reported via this function is the error seen by
+ * the link training failure handler proper after an actual link
+ * training failure indicated by the sink device, and so the error and
+ * corresponding actions required are distinct from an autoretrain
+ * modeset failure. See link_recovery_mark_autoretrain_modeset_failure() to
+ * report a modeset failure.
+ *
  * Return:
  * - %true  if recovery should continue via automatic retraining.
  * - %false if automatic retraining is no longer possible and recovery
@@ -1370,7 +1378,30 @@ link_recovery_mark_train_failure(struct intel_dp_link_training *link_training)
 }
 
 /**
- * link_recovery_mark_no_fallback - record that fallback is unavailable
+ * link_recovery_mark_autoretrain_modeset_failure - record an autoretrain modeset failure
+ * @link_training: link training state
+ *
+ * Record a failure of the autoretrain modeset before link training
+ * itself could run.
+ *
+ * Note that the error reported via this function and the corresponding
+ * expected actions are distinct from an actual link training failure:
+ * the modeset failed before a link training attempt could be performed.
+ * See link_recovery_mark_train_failure() to report an actual link
+ * training failure.
+ *
+ * Update the state to indicate that further recovery is to be delegated to
+ * userspace via a regular modeset.
+ */
+static void
+link_recovery_mark_autoretrain_modeset_failure(struct intel_dp_link_training *link_training)
+{
+	if (link_recovery_autoretrain_allowed(link_training))
+		link_training->recovery_state = INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED;
+}
+
+/**
+ * link_recovery_mark_no_fallback - record that no fallback is possible
  * @link_training: link training state
  *
  * Record that no more link fallback configuration is available.
@@ -2021,6 +2052,23 @@ bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
 	 * FIXME: we need to synchronize the current link parameters with
 	 * hardware readout. Currently fast link training doesn't work on
 	 * boot-up.
+	 *
+	 * NOTE:
+	 * This may be called from both serialized (locked and synced against
+	 * async commit tails) and unserialized (e.g. HPD IRQ) contexts. It
+	 * uses the current max link limits as upper bounds to reject
+	 * obviously bogus values, even if those bounds may be observed in a
+	 * transient or slightly stale state.
+	 *
+	 * This is not a full validation of the link configuration. Even in
+	 * serialized contexts, additional constraints (e.g. source limitations,
+	 * bandwidth checks, and other atomic state dependencies) are only
+	 * verified during the atomic check of the subsequent commit.
+	 *
+	 * max_link_limits only provides independent upper bounds for rate and
+	 * lane count. Callers must not assume it is itself an allowed link
+	 * configuration. Although that happens to be true for now, it will
+	 * stop being guaranteed once fallback depends only on disabled configs.
 	 */
 	if (link_rate == 0 ||
 	    link_rate > intel_dp->link.max_rate)
@@ -2151,6 +2199,22 @@ static bool intel_dp_is_connected(struct intel_dp *intel_dp)
 		intel_dp->is_mst;
 }
 
+static void queue_modeset_retry_for_links_in_state(struct intel_atomic_state *state,
+						   struct intel_encoder *encoder,
+						   u8 pipe_mask)
+{
+	const struct intel_crtc_state *crtc_state;
+	struct intel_crtc *crtc;
+	int i;
+
+	for_each_new_intel_crtc_in_state(state, crtc, crtc_state, i) {
+		if (!(BIT(crtc->pipe) & pipe_mask))
+			continue;
+
+		intel_dp_queue_modeset_retry_for_link(state, encoder, crtc_state);
+	}
+}
+
 static int intel_dp_retrain_link(struct intel_encoder *encoder,
 				 struct drm_modeset_acquire_ctx *ctx)
 {
@@ -2201,11 +2265,23 @@ static int intel_dp_retrain_link(struct intel_encoder *encoder,
 
 	intel_dp_link_training_set_force_retrain(link_training, false);
 
-	if (ret)
+	if (ret) {
 		drm_dbg_kms(display->drm,
 			    "[ENCODER:%d:%s] link retraining failed: %pe\n",
 			    encoder->base.base.id, encoder->base.name,
 			    ERR_PTR(ret));
+		/*
+		 * intel_dp_needs_link_retrain() only performs a coarse check of
+		 * retrainability, so the modeset commit may still fail. Disable
+		 * further auto-retrain attempts in that case.
+		 *
+		 * A sink capability change may restore the retrainable state (see
+		 * intel_dp_update_sink_caps(), intel_dp_reset_link_params()),
+		 * allowing retraining to be attempted again.
+		 */
+		link_recovery_mark_autoretrain_modeset_failure(link_training);
+		queue_modeset_retry_for_links_in_state(state, encoder, pipe_mask);
+	}
 out:
 	drm_atomic_state_put(&state->base);
 
@@ -2229,6 +2305,24 @@ void intel_dp_check_link_state(struct intel_dp *intel_dp)
 	if (!intel_dp_is_connected(intel_dp))
 		return;
 
+	/*
+	 * NOTE:
+	 * This may race with an ongoing modeset updating the max link limits
+	 * and, with that, the link's retrainability, so
+	 * intel_dp_needs_link_retrain() may observe stale state.
+	 *
+	 * This is harmless: stale params captured as valid may spuriously
+	 * allow retraining here, but the decision is rechecked later in a
+	 * properly serialized context.
+	 *
+	 * Conversely, stale params captured as invalid may skip retraining,
+	 * but that can only happen before the modeset has completed its own
+	 * link training for the new, valid configuration, after which the
+	 * link state is rechecked.
+	 *
+	 * See intel_dp_link_params_valid() for capturing and validating the
+	 * params.
+	 */
 	if (!intel_dp_needs_link_retrain(intel_dp))
 		return;
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 025/108] drm/i915/dp_link_training: Fix kernel-doc of intel_dp_init_lttpr_and_dprx_caps()
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (23 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 024/108] drm/i915/dp_link_training: Disallow autoretrains after failed modeset Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 026/108] drm/i915/dp_link_training: Document DP link recovery logic Imre Deak
                   ` (85 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Fix the list formatting of return values in intel_dp_read_dprx_caps()'s
kernel-doc.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp_link_training.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 37862b915cf6e..35f160761e182 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -311,12 +311,12 @@ int intel_dp_read_dprx_caps(struct intel_dp *intel_dp, u8 dpcd[DP_RECEIVER_CAP_S
  * transparent mode link training mode.
  *
  * Returns:
- *   >0  if LTTPRs were detected and the non-transparent LT mode was set. The
+ * - >0  if LTTPRs were detected and the non-transparent LT mode was
+ *       set. The DPRX capabilities are read out.
+ * -  0  if no LTTPRs or more than 8 LTTPRs were detected or in case of
+ *       a detection failure and the transparent LT mode was set. The
  *       DPRX capabilities are read out.
- *    0  if no LTTPRs or more than 8 LTTPRs were detected or in case of a
- *       detection failure and the transparent LT mode was set. The DPRX
- *       capabilities are read out.
- *   <0  Reading out the DPRX capabilities failed.
+ * - <0  Reading out the DPRX capabilities failed.
  */
 int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp)
 {
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 026/108] drm/i915/dp_link_training: Document DP link recovery logic
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (24 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 025/108] drm/i915/dp_link_training: Fix kernel-doc of intel_dp_init_lttpr_and_dprx_caps() Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 027/108] drm/i915/dp: Rename intel_dp_link_config to intel_dp_link_config_entry Imre Deak
                   ` (84 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add kernel-doc documentation describing the Intel DP link training
recovery state machine and the sequence of automatic retraining,
fallback selection, and userspace notification.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 Documentation/gpu/i915.rst                    |   9 +
 .../drm/i915/display/intel_dp_link_training.c | 241 ++++++++++++++++++
 2 files changed, 250 insertions(+)

diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst
index eba09c3ddce42..34556b2104aa5 100644
--- a/Documentation/gpu/i915.rst
+++ b/Documentation/gpu/i915.rst
@@ -141,6 +141,15 @@ Hotplug
 .. kernel-doc:: drivers/gpu/drm/i915/display/intel_hotplug.c
    :internal:
 
+DisplayPort Link Training
+-------------------------
+
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp_link_training.c
+   :doc: DisplayPort link training
+
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp_link_training.c
+   :internal:
+
 High Definition Audio
 ---------------------
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 35f160761e182..810227328d002 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -41,6 +41,246 @@
 #include "intel_panel.h"
 #include "intel_psr.h"
 
+/**
+ * DOC: DisplayPort link training
+ *
+ * This documents the Intel DisplayPort link training implementation and
+ * its internal interfaces, with a current focus on link recovery.
+ *
+ * Documentation of the full link training procedure is not yet included.
+ *
+ * The Intel DP link recovery logic governs how the driver reacts to link
+ * training (LT) failures and to links that degrade asynchronously after a
+ * previously successful training. Recovery is first attempted via
+ * automatic retraining (autoretrain) and, when that is no longer possible,
+ * by selecting fallback link configurations and notifying userspace to
+ * recover the link via a modeset.
+ *
+ * Recovery sequence and userspace notification:
+ *   After the first link training failure following initialization or a
+ *   previously successful training, recovery is first attempted by the
+ *   driver via automatic retraining, without userspace involvement. During
+ *   this phase, a given link configuration is attempted twice before being
+ *   abandoned: after the initial link training failure, an automatic
+ *   retraining modeset is performed with the same link parameters,
+ *   constituting the second attempt.
+ *
+ *   Once automatic retraining is no longer possible, recovery is delegated
+ *   to userspace, which must select a new modeset configuration, as the
+ *   kernel must not do so. From this point onwards, each link configuration
+ *   may be attempted only once as userspace iterates through alternative
+ *   configurations. A successful link training restores the automatic
+ *   retraining model for subsequent failures.
+ *
+ *   The failure of the last automatic retraining attempt is reported to
+ *   userspace, and from that point onward the driver notifies userspace of
+ *   each subsequent failure. This allows userspace to both initiate
+ *   recovery via modesets and observe the outcome of those recovery
+ *   attempts, even when no further fallback configurations remain.
+ *
+ *   Link training failures are always reported to userspace, even when they
+ *   result from a kernel-internal modeset. Such modesets only re-apply the
+ *   existing userspace-provided state and must not modify it. A failure
+ *   triggered by such a modeset is therefore treated the same as a link
+ *   degradation after a previously successful training, and recovery is
+ *   handled by userspace in place of the kernel caller.
+ *
+ * Contexts:
+ *   The following execution contexts (A/B/C) describe how the different
+ *   recovery states are reached but are not themselves implementation
+ *   states. The actual state machine is defined by &enum
+ *   intel_dp_link_training_recovery_state.
+ *
+ *   A. Modeset-triggered link training:
+ *
+ *     Triggered by:
+ *       - link training during a modeset, or
+ *       - via the "i915_dp_force_link_training_failure" debugfs entry,
+ *         forcing this path by emulating a link training failure.
+ *
+ *     Transitions:
+ *       - A1 Link training succeeds.
+ *
+ *         State -> %INTEL_DP_LINK_RECOVERY_IDLE.
+ *
+ *       - A2 First link training fails after initialization or a previously
+ *         successful training.
+ *
+ *         An automatic retraining attempt is scheduled with the same link
+ *         parameters with which the link training failed.
+ *
+ *         State -> %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING.
+ *
+ *       - A3 Link training fails again after A2, or fails when automatic
+ *         retraining is already disabled.
+ *
+ *         Through fallback selection, the driver attempts to restrict the
+ *         allowed link configurations for subsequent modesets. This may
+ *         be done either by lowering global limits (rate/lane caps), or by
+ *         disabling only the currently failing configuration while leaving
+ *         all other configurations allowed, even if they use higher rate or
+ *         lane count.
+ *
+ *         (The current implementation may still apply parameter capping as
+ *         a coarse fallback selection mechanism. This is transitional and is
+ *         expected to be replaced by a scheme that disables only the failing
+ *         configuration, rather than removing configurations that have not
+ *         been observed to fail and may still train successfully.)
+ *
+ *         This case may repeat in a loop:
+ *             %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED ->
+ *             %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED
+ *
+ *         via repeated A3a -> A3a transitions until the configuration fallback
+ *         space is exhausted, reaching the A3b terminal case.
+ *
+ *         - A3a Fallback selection succeeds.
+ *
+ *           Userspace is notified to retry the modeset.
+ *
+ *           State -> %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED.
+ *
+ *         - A3b Fallback selection fails.
+ *
+ *           Userspace is notified of the failure and may continue recovery
+ *           by retrying the modeset with the remaining allowed link
+ *           configuration.
+ *
+ *           State -> %INTEL_DP_LINK_RECOVERY_NO_FALLBACK.
+ *
+ *   B. Automatic retraining:
+ *
+ *     Triggered by:
+ *       - after a failed link training attempt, or
+ *       - after a successful link training followed by asynchronous link
+ *         degradation, or
+ *       - via the "i915_dp_force_link_retrain" debugfs entry, which may
+ *         bypass normal gating and force this path.
+ *
+ *     Transitions:
+ *       - B1 Autoretrain modeset succeeds and link training succeeds.
+ *
+ *         State -> %INTEL_DP_LINK_RECOVERY_IDLE.
+ *
+ *       - B2 Autoretrain modeset succeeds but link training fails.
+ *
+ *         - B2a The current state is %INTEL_DP_LINK_RECOVERY_IDLE.
+ *
+ *           This corresponds to a first failure in a new failure
+ *           sequence and is handled as in A2: an automatic retraining
+ *           attempt is scheduled with the same link parameters.
+ *
+ *           State -> %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING.
+ *
+ *         - B2b The current state is %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING.
+ *
+ *           In non-regular (debug-forced) scenarios this may also be
+ *           reached from
+ *           %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED or
+ *           %INTEL_DP_LINK_RECOVERY_NO_FALLBACK, effectively behaving
+ *           like a userspace-driven recovery attempt.
+ *
+ *           The failure is handled as in A3, performing fallback
+ *           selection and transitioning according to A3a or A3b.
+ *
+ *       - B3 Link retraining cannot be started because its modeset atomic
+ *         check fails.
+ *
+ *         The modeset may fail, for example, due to external conditions such
+ *         as changed shared link bandwidth, which can make previously valid
+ *         modeset parameters no longer acceptable.
+ *
+ *         In this case, automatic retraining is disabled without selecting
+ *         a fallback configuration. The driver hands recovery over to
+ *         userspace without modifying the allowed configuration set, so a
+ *         subsequent userspace modeset will retry with the current link
+ *         configuration. Userspace is in a better position to select new
+ *         modeset parameters (e.g. video mode or enabled outputs) that
+ *         satisfy the updated constraints, as the driver is only allowed
+ *         to retry the modeset with the existing userspace-provided modeset
+ *         configuration.
+ *
+ *         This policy preserves the normal retry model, where a given link
+ *         configuration is attempted twice in the automatic retraining
+ *         flow before being abandoned: after a first link training failure,
+ *         an automatic retraining modeset is performed with the same link
+ *         parameters, and if its atomic check passes, the link training
+ *         itself may either succeed or fail, constituting the second
+ *         attempt. In this case, however, the retry modeset's atomic check
+ *         failed, so no second link training attempt with those parameters
+ *         was performed, and selecting a fallback would cause that
+ *         configuration to be tried only once rather than twice.
+ *
+ *   C. State reset:
+ *
+ *     Triggered by:
+ *       - sink capability changes,
+ *       - sink disconnect/reconnect,
+ *       - system suspend/resume or power transitions where HPD
+ *         handling may have been suppressed, or
+ *       - successful link training.
+ *
+ *     Transitions:
+ *       - The recovery state is reset from any of the recovery states
+ *
+ *         State -> %INTEL_DP_LINK_RECOVERY_IDLE.
+ *
+ *         After reset, the driver may re-check link status and schedule
+ *         retraining if the link is found to remain degraded.
+ *
+ * State transition summary:
+ *   - From %INTEL_DP_LINK_RECOVERY_IDLE
+ *
+ *     - To %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING
+ *
+ *       - In contexts: A2, B2a
+ *       - Action: queue autoretrain work
+ *
+ *     - To %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED
+ *
+ *       - In context: B3
+ *       - Action: disable automatic retraining, notify userspace
+ *
+ *   - From %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_PENDING
+ *
+ *     - To %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED
+ *
+ *       - In contexts: A3a, B2b
+ *       - Action: disable automatic retraining, select fallback
+ *         configurations, notify userspace
+ *
+ *     - To %INTEL_DP_LINK_RECOVERY_NO_FALLBACK
+ *
+ *       - In contexts: A3b, B2b
+ *       - Action: disable automatic retraining, notify userspace
+ *
+ *   - From %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED
+ *
+ *     - To %INTEL_DP_LINK_RECOVERY_AUTORETRAIN_DISABLED
+ *
+ *       - In contexts: A3a, B2b
+ *       - Action: select fallback configurations, notify userspace
+ *
+ *     - To %INTEL_DP_LINK_RECOVERY_NO_FALLBACK
+ *
+ *       - In contexts: A3b, B2b
+ *       - Action: notify userspace
+ *
+ *   - From %INTEL_DP_LINK_RECOVERY_NO_FALLBACK
+ *
+ *     - To %INTEL_DP_LINK_RECOVERY_NO_FALLBACK
+ *
+ *       - In contexts: A3b
+ *       - Action: notify userspace
+ *
+ *   - From any state
+ *
+ *     - To %INTEL_DP_LINK_RECOVERY_IDLE
+ *
+ *       - In contexts: C
+ *       - Action: no action
+ */
+
 #define LT_MSG_PREFIX			"[CONNECTOR:%d:%s][ENCODER:%d:%s][%s] "
 #define LT_MSG_ARGS(_intel_dp, _dp_phy)	(_intel_dp)->attached_connector->base.base.id, \
 					(_intel_dp)->attached_connector->base.name, \
@@ -95,6 +335,7 @@
  * logic.
  *
  * See also:
+ *   - DOC: DisplayPort link training
  *   - link_recovery_autoretrain_pending()
  *   - link_recovery_autoretrain_allowed()
  *   - link_recovery_has_no_fallback()
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 027/108] drm/i915/dp: Rename intel_dp_link_config to intel_dp_link_config_entry
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (25 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 026/108] drm/i915/dp_link_training: Document DP link recovery logic Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 028/108] drm/i915/dp: Add struct intel_dp_link_config Imre Deak
                   ` (83 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Rename intel_dp_link_config to intel_dp_link_config_entry to prepare
for tracking a link configuration in both an internal packed and a
public unpacked format. A follow-up change will add
struct intel_dp_link_config representing the public unpacked format.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_display_types.h   |  2 +-
 drivers/gpu/drm/i915/display/intel_dp.c          | 16 ++++++++--------
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index dd61d958d5b6c..e591bca15e4eb 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1831,7 +1831,7 @@ struct intel_dp {
 #define INTEL_DP_LINK_RATE_IDX_BITS		(BITS_PER_TYPE(u8) - INTEL_DP_LANE_COUNT_EXP_BITS)
 #define INTEL_DP_MAX_LINK_CONFIGS		(DP_MAX_SUPPORTED_RATES * \
 						 INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS)
-		struct intel_dp_link_config {
+		struct intel_dp_link_config_entry {
 			u8 link_rate_idx:INTEL_DP_LINK_RATE_IDX_BITS;
 			u8 lane_count_exp:INTEL_DP_LANE_COUNT_EXP_BITS;
 		} configs[INTEL_DP_MAX_LINK_CONFIGS];
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 3dc27dbf2bce8..4f016adef93be 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -688,18 +688,18 @@ int intel_dp_rate_index(const int *rates, int len, int rate)
 }
 
 static int intel_dp_link_config_rate(struct intel_dp *intel_dp,
-				     const struct intel_dp_link_config *lc)
+				     const struct intel_dp_link_config_entry *lc)
 {
 	return intel_dp_common_rate(intel_dp, lc->link_rate_idx);
 }
 
-static int intel_dp_link_config_lane_count(const struct intel_dp_link_config *lc)
+static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_entry *lc)
 {
 	return 1 << lc->lane_count_exp;
 }
 
 static int intel_dp_link_config_bw(struct intel_dp *intel_dp,
-				   const struct intel_dp_link_config *lc)
+				   const struct intel_dp_link_config_entry *lc)
 {
 	return drm_dp_max_dprx_data_rate(intel_dp_link_config_rate(intel_dp, lc),
 					 intel_dp_link_config_lane_count(lc));
@@ -708,8 +708,8 @@ static int intel_dp_link_config_bw(struct intel_dp *intel_dp,
 static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 {
 	struct intel_dp *intel_dp = (struct intel_dp *)p;	/* remove const */
-	const struct intel_dp_link_config *lc_a = a;
-	const struct intel_dp_link_config *lc_b = b;
+	const struct intel_dp_link_config_entry *lc_a = a;
+	const struct intel_dp_link_config_entry *lc_b = b;
 	int bw_a = intel_dp_link_config_bw(intel_dp, lc_a);
 	int bw_b = intel_dp_link_config_bw(intel_dp, lc_b);
 
@@ -723,7 +723,7 @@ static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 static void intel_dp_link_config_init(struct intel_dp *intel_dp)
 {
 	struct intel_display *display = to_intel_display(intel_dp);
-	struct intel_dp_link_config *lc;
+	struct intel_dp_link_config_entry *lc;
 	int num_common_lane_configs;
 	int i;
 	int j;
@@ -758,7 +758,7 @@ static void intel_dp_link_config_init(struct intel_dp *intel_dp)
 void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count)
 {
 	struct intel_display *display = to_intel_display(intel_dp);
-	const struct intel_dp_link_config *lc;
+	const struct intel_dp_link_config_entry *lc;
 
 	if (drm_WARN_ON(display->drm, idx < 0 || idx >= intel_dp->link.num_configs))
 		idx = 0;
@@ -777,7 +777,7 @@ int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lan
 	int i;
 
 	for (i = 0; i < intel_dp->link.num_configs; i++) {
-		const struct intel_dp_link_config *lc = &intel_dp->link.configs[i];
+		const struct intel_dp_link_config_entry *lc = &intel_dp->link.configs[i];
 
 		if (lc->lane_count_exp == lane_count_exp &&
 		    lc->link_rate_idx == link_rate_idx)
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 028/108] drm/i915/dp: Add struct intel_dp_link_config
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (26 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 027/108] drm/i915/dp: Rename intel_dp_link_config to intel_dp_link_config_entry Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 029/108] drm/i915/dp_link_caps: Introduce DP link capability module Imre Deak
                   ` (82 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add a struct representing the public unpacked format of a link
configuration. This will be used by the DP link capability API added
as a follow-up, and by DP code in general that needs to track a link
configuration.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_display_types.h | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index e591bca15e4eb..28a8a149157e0 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1792,6 +1792,14 @@ struct intel_psr {
 	const char *no_psr_reason;
 };
 
+struct intel_dp_link_config {
+	int rate;
+	int lane_count;
+};
+
+#define INTEL_DP_LINK_CONFIG_NULL \
+	((struct intel_dp_link_config){})
+
 struct intel_dp {
 	i915_reg_t output_reg;
 	u32 DP;
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 029/108] drm/i915/dp_link_caps: Introduce DP link capability module
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (27 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 028/108] drm/i915/dp: Add struct intel_dp_link_config Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 030/108] drm/i915/dp_link_caps: Move common rate helpers to link caps Imre Deak
                   ` (81 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Start isolating the DP link capability logic from the generic DP code by
adding a separate intel_dp_link_caps module and a corresponding state
object.

Allocate the state so it can remain opaque within its module.

Follow-up changes will move link capability helpers and state from
intel_dp.c and intel_dp_link_training.c to the new module and state.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/Makefile                 |  1 +
 .../drm/i915/display/intel_display_types.h    |  2 +
 drivers/gpu/drm/i915/display/intel_dp.c       |  9 ++++
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 47 +++++++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h | 12 +++++
 drivers/gpu/drm/xe/Makefile                   |  1 +
 6 files changed, 72 insertions(+)
 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

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index fa632f4e505c9..0c04c6d9bb13e 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -355,6 +355,7 @@ i915-y += \
 	display/intel_dp_aux.o \
 	display/intel_dp_aux_backlight.o \
 	display/intel_dp_hdcp.o \
+	display/intel_dp_link_caps.o \
 	display/intel_dp_link_training.o \
 	display/intel_dp_mst.o \
 	display/intel_dp_test.o \
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 28a8a149157e0..d11686ce2963d 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -58,6 +58,7 @@ struct cec_notifier;
 struct drm_printer;
 struct intel_connector;
 struct intel_ddi_buf_trans;
+struct intel_dp_link_caps;
 struct intel_dp_link_training;
 struct intel_fbc;
 struct intel_global_objs_state;
@@ -1858,6 +1859,7 @@ struct intel_dp {
 		int force_lane_count;
 		int force_rate;
 		struct intel_dp_link_training *training;
+		struct intel_dp_link_caps *caps;
 	} link;
 	bool reset_link_params;
 	int mso_link_count;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 4f016adef93be..e63e341aa5c8d 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -71,6 +71,7 @@
 #include "intel_dp.h"
 #include "intel_dp_aux.h"
 #include "intel_dp_hdcp.h"
+#include "intel_dp_link_caps.h"
 #include "intel_dp_link_training.h"
 #include "intel_dp_mst.h"
 #include "intel_dp_test.h"
@@ -7357,6 +7358,13 @@ int intel_dp_link_init(struct intel_dp *intel_dp)
 	if (!intel_dp->link.training)
 		return -ENOMEM;
 
+	intel_dp->link.caps = intel_dp_link_caps_init(intel_dp);
+	if (!intel_dp->link.caps) {
+		intel_dp_link_training_cleanup(intel_dp->link.training);
+
+		return -ENOMEM;
+	}
+
 	return 0;
 }
 
@@ -7368,5 +7376,6 @@ int intel_dp_link_init(struct intel_dp *intel_dp)
  */
 void intel_dp_link_cleanup(struct intel_dp *intel_dp)
 {
+	intel_dp_link_caps_cleanup(intel_dp->link.caps);
 	intel_dp_link_training_cleanup(intel_dp->link.training);
 }
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
new file mode 100644
index 0000000000000..335382d193475
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include <linux/slab.h>
+
+#include "intel_dp_link_caps.h"
+
+struct intel_dp_link_caps {
+	struct intel_dp *dp;
+};
+
+/**
+ * intel_dp_link_caps_init - allocate and initialize link caps state
+ * @intel_dp: DP encoder state
+ *
+ * Allocate and initialize the link capabilities state for @intel_dp and
+ * the connectors attached to it.
+ *
+ * Return:
+ * - Pointer to the newly allocated link capabilities state.
+ * - %NULL if allocation fails.
+ */
+struct intel_dp_link_caps *intel_dp_link_caps_init(struct intel_dp *intel_dp)
+{
+	struct intel_dp_link_caps *link_caps;
+
+	link_caps = kzalloc_obj(*link_caps);
+	if (!link_caps)
+		return NULL;
+
+	link_caps->dp = intel_dp;
+
+	return link_caps;
+}
+
+/**
+ * intel_dp_link_caps_cleanup - free link caps state
+ * @link_caps: link capabilities state to free
+ *
+ * Free @link_caps.
+ */
+void intel_dp_link_caps_cleanup(struct intel_dp_link_caps *link_caps)
+{
+	kfree(link_caps);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
new file mode 100644
index 0000000000000..050b279463d6e
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: MIT */
+/* Copyright © 2026 Intel Corporation */
+
+#ifndef __INTEL_DP_LINK_CAPS_H__
+#define __INTEL_DP_LINK_CAPS_H__
+
+struct intel_dp;
+
+struct intel_dp_link_caps *intel_dp_link_caps_init(struct intel_dp *intel_dp);
+void intel_dp_link_caps_cleanup(struct intel_dp_link_caps *link_caps);
+
+#endif /* __INTEL_DP_LINK_CAPS_H__ */
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 95666f950a6fc..9450d487123a3 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -276,6 +276,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \
 	i915-display/intel_dp_aux.o \
 	i915-display/intel_dp_aux_backlight.o \
 	i915-display/intel_dp_hdcp.o \
+	i915-display/intel_dp_link_caps.o \
 	i915-display/intel_dp_link_training.o \
 	i915-display/intel_dp_mst.o \
 	i915-display/intel_dp_test.o \
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 030/108] drm/i915/dp_link_caps: Move common rate helpers to link caps
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (28 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 029/108] drm/i915/dp_link_caps: Introduce DP link capability module Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 031/108] drm/i915/dp_link_caps: Move forced link param " Imre Deak
                   ` (80 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Move the helpers handling common link rates to intel_dp_link_caps.c.
Their functionality is part of the link capability logic and will be
updated to use the link capability state in follow-up changes.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       | 27 +----------------
 drivers/gpu/drm/i915/display/intel_dp.h       |  3 +-
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 30 +++++++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  5 ++++
 .../drm/i915/display/intel_dp_link_training.c |  1 +
 .../gpu/drm/i915/display/intel_dp_tunnel.c    |  1 +
 6 files changed, 39 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index e63e341aa5c8d..1f903f9acec15 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -314,7 +314,7 @@ static void intel_dp_set_max_sink_lane_count(struct intel_dp *intel_dp)
 }
 
 /* Get length of rates array potentially limited by max_rate. */
-static int intel_dp_rate_limit_len(const int *rates, int len, int max_rate)
+int intel_dp_rate_limit_len(const int *rates, int len, int max_rate)
 {
 	int i;
 
@@ -327,31 +327,6 @@ static int intel_dp_rate_limit_len(const int *rates, int len, int max_rate)
 	return 0;
 }
 
-/* Get length of common rates array potentially limited by max_rate. */
-static int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
-					  int max_rate)
-{
-	return intel_dp_rate_limit_len(intel_dp->common_rates,
-				       intel_dp->num_common_rates, max_rate);
-}
-
-int intel_dp_common_rate(struct intel_dp *intel_dp, int index)
-{
-	struct intel_display *display = to_intel_display(intel_dp);
-
-	if (drm_WARN_ON(display->drm,
-			index < 0 || index >= intel_dp->num_common_rates))
-		return 162000;
-
-	return intel_dp->common_rates[index];
-}
-
-/* Theoretical max between source and sink */
-int intel_dp_max_common_rate(struct intel_dp *intel_dp)
-{
-	return intel_dp_common_rate(intel_dp, intel_dp->num_common_rates - 1);
-}
-
 int intel_dp_max_source_lane_count(struct intel_digital_port *dig_port)
 {
 	int vbt_max_lanes = intel_bios_dp_max_lane_count(dig_port->base.devdata);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 3c0d229eb1f55..8f7607dc412d0 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -97,14 +97,13 @@ void intel_edp_backlight_off(const struct drm_connector_state *conn_state);
 void intel_edp_fixup_vbt_bpp(struct intel_encoder *encoder, int pipe_bpp);
 void intel_dp_mst_suspend(struct intel_display *display);
 void intel_dp_mst_resume(struct intel_display *display);
+int intel_dp_rate_limit_len(const int *rates, int len, int max_rate);
 int intel_dp_max_source_lane_count(struct intel_digital_port *dig_port);
 int intel_dp_max_link_rate(struct intel_dp *intel_dp);
 int intel_dp_max_lane_count(struct intel_dp *intel_dp);
 int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state);
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
-int intel_dp_max_common_rate(struct intel_dp *intel_dp);
 int intel_dp_max_common_lane_count(struct intel_dp *intel_dp);
-int intel_dp_common_rate(struct intel_dp *intel_dp, int index);
 int intel_dp_rate_index(const int *rates, int len, int rate);
 int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count);
 void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 335382d193475..5711dde8d6eed 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -5,12 +5,42 @@
 
 #include <linux/slab.h>
 
+#include <drm/drm_print.h>
+
+#include "intel_display_core.h"
+#include "intel_display_types.h"
+#include "intel_dp.h"
 #include "intel_dp_link_caps.h"
 
 struct intel_dp_link_caps {
 	struct intel_dp *dp;
 };
 
+/* Get length of common rates array potentially limited by max_rate. */
+int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
+				   int max_rate)
+{
+	return intel_dp_rate_limit_len(intel_dp->common_rates,
+				       intel_dp->num_common_rates, max_rate);
+}
+
+int intel_dp_common_rate(struct intel_dp *intel_dp, int index)
+{
+	struct intel_display *display = to_intel_display(intel_dp);
+
+	if (drm_WARN_ON(display->drm,
+			index < 0 || index >= intel_dp->num_common_rates))
+		return 162000;
+
+	return intel_dp->common_rates[index];
+}
+
+/* Theoretical max between source and sink */
+int intel_dp_max_common_rate(struct intel_dp *intel_dp)
+{
+	return intel_dp_common_rate(intel_dp, intel_dp->num_common_rates - 1);
+}
+
 /**
  * intel_dp_link_caps_init - allocate and initialize link caps state
  * @intel_dp: DP encoder state
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 050b279463d6e..3248777d1287f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -6,6 +6,11 @@
 
 struct intel_dp;
 
+int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
+				   int max_rate);
+int intel_dp_common_rate(struct intel_dp *intel_dp, int index);
+int intel_dp_max_common_rate(struct intel_dp *intel_dp);
+
 struct intel_dp_link_caps *intel_dp_link_caps_init(struct intel_dp *intel_dp);
 void intel_dp_link_caps_cleanup(struct intel_dp_link_caps *link_caps);
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 810227328d002..9572ea509a8af 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -33,6 +33,7 @@
 #include "intel_display_types.h"
 #include "intel_display_utils.h"
 #include "intel_dp.h"
+#include "intel_dp_link_caps.h"
 #include "intel_dp_link_training.h"
 #include "intel_dp_mst.h"
 #include "intel_encoder.h"
diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
index 11712a151f729..64fd4f09d1cdd 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
@@ -11,6 +11,7 @@
 #include "intel_display_limits.h"
 #include "intel_display_types.h"
 #include "intel_dp.h"
+#include "intel_dp_link_caps.h"
 #include "intel_dp_link_training.h"
 #include "intel_dp_mst.h"
 #include "intel_dp_tunnel.h"
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 031/108] drm/i915/dp_link_caps: Move forced link param helpers to link caps
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (29 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 030/108] drm/i915/dp_link_caps: Move common rate helpers to link caps Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 032/108] drm/i915/dp: Simplify querying of forced link parameters Imre Deak
                   ` (79 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Move the helpers handling forced link parameters to intel_dp_link_caps.c.
Their functionality is part of the link capability logic and will be
updated to use the link capability state in follow-up changes.

Return the forced link rate and lane count through a
struct intel_dp_link_config, which is the canonical way the rest of the
link capability API will also accept and return link configurations.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       | 40 ++++++++++---------
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 22 ++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  5 +++
 3 files changed, 48 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 1f903f9acec15..0aab37dcce97a 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -353,17 +353,16 @@ int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
 	return min3(source_max, sink_max, lane_max);
 }
 
-static int forced_lane_count(struct intel_dp *intel_dp)
-{
-	return clamp(intel_dp->link.force_lane_count, 1, intel_dp_max_common_lane_count(intel_dp));
-}
-
 int intel_dp_max_lane_count(struct intel_dp *intel_dp)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp_link_config forced_params;
 	int lane_count;
 
+	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
+
 	if (intel_dp->link.force_lane_count)
-		lane_count = forced_lane_count(intel_dp);
+		lane_count = forced_params.lane_count;
 	else
 		lane_count = intel_dp->link.max_lane_count;
 
@@ -380,8 +379,12 @@ int intel_dp_max_lane_count(struct intel_dp *intel_dp)
 
 static int intel_dp_min_lane_count(struct intel_dp *intel_dp)
 {
+	struct intel_dp_link_config forced_params;
+
+	intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params);
+
 	if (intel_dp->link.force_lane_count)
-		return forced_lane_count(intel_dp);
+		return forced_params.lane_count;
 
 	return 1;
 }
@@ -1657,21 +1660,16 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp)
 	drm_dbg_kms(display->drm, "common rates: %s\n", seq_buf_str(&s));
 }
 
-static int forced_link_rate(struct intel_dp *intel_dp)
-{
-	int len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.force_rate);
-
-	if (len == 0)
-		return intel_dp_common_rate(intel_dp, 0);
-
-	return intel_dp_common_rate(intel_dp, len - 1);
-}
-
 int
 intel_dp_max_link_rate(struct intel_dp *intel_dp)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp_link_config forced_params;
+
+	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
+
 	if (intel_dp->link.force_rate)
-		return forced_link_rate(intel_dp);
+		return forced_params.rate;
 
 	return intel_dp->link.max_rate;
 }
@@ -1679,8 +1677,12 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 static int
 intel_dp_min_link_rate(struct intel_dp *intel_dp)
 {
+	struct intel_dp_link_config forced_params;
+
+	intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params);
+
 	if (intel_dp->link.force_rate)
-		return forced_link_rate(intel_dp);
+		return forced_params.rate;
 
 	return intel_dp_common_rate(intel_dp, 0);
 }
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 5711dde8d6eed..0a2db7d65e20d 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -41,6 +41,28 @@ int intel_dp_max_common_rate(struct intel_dp *intel_dp)
 	return intel_dp_common_rate(intel_dp, intel_dp->num_common_rates - 1);
 }
 
+static int forced_lane_count(struct intel_dp *intel_dp)
+{
+	return clamp(intel_dp->link.force_lane_count, 1, intel_dp_max_common_lane_count(intel_dp));
+}
+
+static int forced_link_rate(struct intel_dp *intel_dp)
+{
+	int len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.force_rate);
+
+	if (len == 0)
+		return intel_dp_common_rate(intel_dp, 0);
+
+	return intel_dp_common_rate(intel_dp, len - 1);
+}
+
+void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
+					  struct intel_dp_link_config *forced_params)
+{
+	forced_params->rate = forced_link_rate(link_caps->dp);
+	forced_params->lane_count = forced_lane_count(link_caps->dp);
+}
+
 /**
  * intel_dp_link_caps_init - allocate and initialize link caps state
  * @intel_dp: DP encoder state
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 3248777d1287f..61dbce86ee3d0 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -5,12 +5,17 @@
 #define __INTEL_DP_LINK_CAPS_H__
 
 struct intel_dp;
+struct intel_dp_link_caps;
+struct intel_dp_link_config;
 
 int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
 				   int max_rate);
 int intel_dp_common_rate(struct intel_dp *intel_dp, int index);
 int intel_dp_max_common_rate(struct intel_dp *intel_dp);
 
+void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
+					  struct intel_dp_link_config *forced_params);
+
 struct intel_dp_link_caps *intel_dp_link_caps_init(struct intel_dp *intel_dp);
 void intel_dp_link_caps_cleanup(struct intel_dp_link_caps *link_caps);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 032/108] drm/i915/dp: Simplify querying of forced link parameters
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (30 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 031/108] drm/i915/dp_link_caps: Move forced link param " Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 033/108] drm/i915/dp_link_caps: Move forced and max link debugfs entries to link caps Imre Deak
                   ` (78 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Simplify querying the forced link rate and lane count by
performing the zero checks inside the helpers, allowing callers
to use the returned values directly.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c           | 8 ++++----
 drivers/gpu/drm/i915/display/intel_dp_link_caps.c | 9 ++++++++-
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 0aab37dcce97a..52d843b05c38c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -361,7 +361,7 @@ int intel_dp_max_lane_count(struct intel_dp *intel_dp)
 
 	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
 
-	if (intel_dp->link.force_lane_count)
+	if (forced_params.lane_count)
 		lane_count = forced_params.lane_count;
 	else
 		lane_count = intel_dp->link.max_lane_count;
@@ -383,7 +383,7 @@ static int intel_dp_min_lane_count(struct intel_dp *intel_dp)
 
 	intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params);
 
-	if (intel_dp->link.force_lane_count)
+	if (forced_params.lane_count)
 		return forced_params.lane_count;
 
 	return 1;
@@ -1668,7 +1668,7 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 
 	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
 
-	if (intel_dp->link.force_rate)
+	if (forced_params.rate)
 		return forced_params.rate;
 
 	return intel_dp->link.max_rate;
@@ -1681,7 +1681,7 @@ intel_dp_min_link_rate(struct intel_dp *intel_dp)
 
 	intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params);
 
-	if (intel_dp->link.force_rate)
+	if (forced_params.rate)
 		return forced_params.rate;
 
 	return intel_dp_common_rate(intel_dp, 0);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 0a2db7d65e20d..1892fc0ff46ef 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -43,13 +43,20 @@ int intel_dp_max_common_rate(struct intel_dp *intel_dp)
 
 static int forced_lane_count(struct intel_dp *intel_dp)
 {
+	if (!intel_dp->link.force_lane_count)
+		return 0;
+
 	return clamp(intel_dp->link.force_lane_count, 1, intel_dp_max_common_lane_count(intel_dp));
 }
 
 static int forced_link_rate(struct intel_dp *intel_dp)
 {
-	int len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.force_rate);
+	int len;
 
+	if (!intel_dp->link.force_rate)
+		return 0;
+
+	len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.force_rate);
 	if (len == 0)
 		return intel_dp_common_rate(intel_dp, 0);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 033/108] drm/i915/dp_link_caps: Move forced and max link debugfs entries to link caps
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (31 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 032/108] drm/i915/dp: Simplify querying of forced link parameters Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 034/108] drm/i915/dp_link_training: Use helpers to get forced link params Imre Deak
                   ` (77 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Move the debugfs entries for the forced and max DP link parameters to
intel_dp_link_caps. Their functionality is part of the link capability
logic and will be updated to use the link capability state in follow-up
changes.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_display_debugfs.c  |   2 +
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 273 ++++++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h |   3 +
 .../drm/i915/display/intel_dp_link_training.c | 263 -----------------
 4 files changed, 278 insertions(+), 263 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_debugfs.c b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
index 81bef000a4e3e..448fc985c5b58 100644
--- a/drivers/gpu/drm/i915/display/intel_display_debugfs.c
+++ b/drivers/gpu/drm/i915/display/intel_display_debugfs.c
@@ -32,6 +32,7 @@
 #include "intel_display_types.h"
 #include "intel_dmc.h"
 #include "intel_dp.h"
+#include "intel_dp_link_caps.h"
 #include "intel_dp_link_training.h"
 #include "intel_dp_mst.h"
 #include "intel_dp_test.h"
@@ -1336,6 +1337,7 @@ void intel_connector_debugfs_add(struct intel_connector *connector)
 	intel_psr_connector_debugfs_add(connector);
 	intel_alpm_lobf_debugfs_add(connector);
 	intel_dp_link_training_debugfs_add(connector);
+	intel_dp_link_caps_debugfs_add(connector);
 	intel_link_bw_connector_debugfs_add(connector);
 
 	if (DISPLAY_VER(display) >= 11 &&
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 1892fc0ff46ef..ed05a8597fc01 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -3,6 +3,7 @@
  * Copyright © 2026 Intel Corporation
  */
 
+#include <linux/debugfs.h>
 #include <linux/slab.h>
 
 #include <drm/drm_print.h>
@@ -70,6 +71,278 @@ void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 	forced_params->lane_count = forced_lane_count(link_caps->dp);
 }
 
+static int i915_dp_force_link_rate_show(struct seq_file *m, void *data)
+{
+	struct intel_connector *connector = to_intel_connector(m->private);
+	struct intel_display *display = to_intel_display(connector);
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	int current_rate = -1;
+	int force_rate;
+	int err;
+	int i;
+
+	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
+	if (err)
+		return err;
+
+	intel_dp_flush_connector_commits(connector);
+
+	if (intel_dp->link.active)
+		current_rate = intel_dp->link_rate;
+
+	force_rate = intel_dp->link.force_rate;
+
+	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
+
+	seq_printf(m, "%sauto%s",
+		   force_rate == 0 ? "[" : "",
+		   force_rate == 0 ? "]" : "");
+
+	for (i = 0; i < intel_dp->num_source_rates; i++)
+		seq_printf(m, " %s%d%s%s",
+			   intel_dp->source_rates[i] == force_rate ? "[" : "",
+			   intel_dp->source_rates[i],
+			   intel_dp->source_rates[i] == current_rate ? "*" : "",
+			   intel_dp->source_rates[i] == force_rate ? "]" : "");
+
+	seq_putc(m, '\n');
+
+	return 0;
+}
+
+static int parse_link_rate(struct intel_dp *intel_dp, const char __user *ubuf, size_t len)
+{
+	char *kbuf;
+	const char *p;
+	int rate;
+	int ret = 0;
+
+	kbuf = memdup_user_nul(ubuf, len);
+	if (IS_ERR(kbuf))
+		return PTR_ERR(kbuf);
+
+	p = strim(kbuf);
+
+	if (!strcmp(p, "auto")) {
+		rate = 0;
+	} else {
+		ret = kstrtoint(p, 0, &rate);
+		if (ret < 0)
+			goto out_free;
+
+		if (intel_dp_rate_index(intel_dp->source_rates,
+					intel_dp->num_source_rates,
+					rate) < 0)
+			ret = -EINVAL;
+	}
+
+out_free:
+	kfree(kbuf);
+
+	return ret < 0 ? ret : rate;
+}
+
+static ssize_t i915_dp_force_link_rate_write(struct file *file,
+					     const char __user *ubuf,
+					     size_t len, loff_t *offp)
+{
+	struct seq_file *m = file->private_data;
+	struct intel_connector *connector = to_intel_connector(m->private);
+	struct intel_display *display = to_intel_display(connector);
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	int rate;
+	int err;
+
+	rate = parse_link_rate(intel_dp, ubuf, len);
+	if (rate < 0)
+		return rate;
+
+	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
+	if (err)
+		return err;
+
+	intel_dp_flush_connector_commits(connector);
+
+	intel_dp_reset_link_params(intel_dp);
+	intel_dp->link.force_rate = rate;
+
+	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
+
+	*offp += len;
+
+	return len;
+}
+DEFINE_SHOW_STORE_ATTRIBUTE(i915_dp_force_link_rate);
+
+static int i915_dp_force_lane_count_show(struct seq_file *m, void *data)
+{
+	struct intel_connector *connector = to_intel_connector(m->private);
+	struct intel_display *display = to_intel_display(connector);
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	int current_lane_count = -1;
+	int force_lane_count;
+	int err;
+	int i;
+
+	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
+	if (err)
+		return err;
+
+	intel_dp_flush_connector_commits(connector);
+
+	if (intel_dp->link.active)
+		current_lane_count = intel_dp->lane_count;
+	force_lane_count = intel_dp->link.force_lane_count;
+
+	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
+
+	seq_printf(m, "%sauto%s",
+		   force_lane_count == 0 ? "[" : "",
+		   force_lane_count == 0 ? "]" : "");
+
+	for (i = 1; i <= 4; i <<= 1)
+		seq_printf(m, " %s%d%s%s",
+			   i == force_lane_count ? "[" : "",
+			   i,
+			   i == current_lane_count ? "*" : "",
+			   i == force_lane_count ? "]" : "");
+
+	seq_putc(m, '\n');
+
+	return 0;
+}
+
+static int parse_lane_count(const char __user *ubuf, size_t len)
+{
+	char *kbuf;
+	const char *p;
+	int lane_count;
+	int ret = 0;
+
+	kbuf = memdup_user_nul(ubuf, len);
+	if (IS_ERR(kbuf))
+		return PTR_ERR(kbuf);
+
+	p = strim(kbuf);
+
+	if (!strcmp(p, "auto")) {
+		lane_count = 0;
+	} else {
+		ret = kstrtoint(p, 0, &lane_count);
+		if (ret < 0)
+			goto out_free;
+
+		switch (lane_count) {
+		case 1:
+		case 2:
+		case 4:
+			break;
+		default:
+			ret = -EINVAL;
+		}
+	}
+
+out_free:
+	kfree(kbuf);
+
+	return ret < 0 ? ret : lane_count;
+}
+
+static ssize_t i915_dp_force_lane_count_write(struct file *file,
+					      const char __user *ubuf,
+					      size_t len, loff_t *offp)
+{
+	struct seq_file *m = file->private_data;
+	struct intel_connector *connector = to_intel_connector(m->private);
+	struct intel_display *display = to_intel_display(connector);
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	int lane_count;
+	int err;
+
+	lane_count = parse_lane_count(ubuf, len);
+	if (lane_count < 0)
+		return lane_count;
+
+	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
+	if (err)
+		return err;
+
+	intel_dp_flush_connector_commits(connector);
+
+	intel_dp_reset_link_params(intel_dp);
+	intel_dp->link.force_lane_count = lane_count;
+
+	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
+
+	*offp += len;
+
+	return len;
+}
+DEFINE_SHOW_STORE_ATTRIBUTE(i915_dp_force_lane_count);
+
+static int i915_dp_max_link_rate_show(void *data, u64 *val)
+{
+	struct intel_connector *connector = to_intel_connector(data);
+	struct intel_display *display = to_intel_display(connector);
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	int err;
+
+	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
+	if (err)
+		return err;
+
+	intel_dp_flush_connector_commits(connector);
+
+	*val = intel_dp->link.max_rate;
+
+	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
+
+	return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(i915_dp_max_link_rate_fops, i915_dp_max_link_rate_show, NULL, "%llu\n");
+
+static int i915_dp_max_lane_count_show(void *data, u64 *val)
+{
+	struct intel_connector *connector = to_intel_connector(data);
+	struct intel_display *display = to_intel_display(connector);
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	int err;
+
+	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
+	if (err)
+		return err;
+
+	intel_dp_flush_connector_commits(connector);
+
+	*val = intel_dp->link.max_lane_count;
+
+	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
+
+	return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(i915_dp_max_lane_count_fops, i915_dp_max_lane_count_show, NULL, "%llu\n");
+
+void intel_dp_link_caps_debugfs_add(struct intel_connector *connector)
+{
+	struct dentry *root = connector->base.debugfs_entry;
+
+	if (connector->base.connector_type != DRM_MODE_CONNECTOR_DisplayPort &&
+	    connector->base.connector_type != DRM_MODE_CONNECTOR_eDP)
+		return;
+
+	debugfs_create_file("i915_dp_force_link_rate", 0644, root,
+			    connector, &i915_dp_force_link_rate_fops);
+
+	debugfs_create_file("i915_dp_force_lane_count", 0644, root,
+			    connector, &i915_dp_force_lane_count_fops);
+
+	debugfs_create_file("i915_dp_max_link_rate", 0444, root,
+			    connector, &i915_dp_max_link_rate_fops);
+
+	debugfs_create_file("i915_dp_max_lane_count", 0444, root,
+			    connector, &i915_dp_max_lane_count_fops);
+}
+
 /**
  * intel_dp_link_caps_init - allocate and initialize link caps state
  * @intel_dp: DP encoder state
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 61dbce86ee3d0..c6a84891db464 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -4,6 +4,7 @@
 #ifndef __INTEL_DP_LINK_CAPS_H__
 #define __INTEL_DP_LINK_CAPS_H__
 
+struct intel_connector;
 struct intel_dp;
 struct intel_dp_link_caps;
 struct intel_dp_link_config;
@@ -16,6 +17,8 @@ int intel_dp_max_common_rate(struct intel_dp *intel_dp);
 void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 					  struct intel_dp_link_config *forced_params);
 
+void intel_dp_link_caps_debugfs_add(struct intel_connector *connector);
+
 struct intel_dp_link_caps *intel_dp_link_caps_init(struct intel_dp *intel_dp);
 void intel_dp_link_caps_cleanup(struct intel_dp_link_caps *link_caps);
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 9572ea509a8af..3455e4daf1faf 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -2571,257 +2571,6 @@ void intel_dp_check_link_state(struct intel_dp *intel_dp)
 	intel_encoder_link_check_queue_work(encoder, 0);
 }
 
-static int i915_dp_force_link_rate_show(struct seq_file *m, void *data)
-{
-	struct intel_connector *connector = to_intel_connector(m->private);
-	struct intel_display *display = to_intel_display(connector);
-	struct intel_dp *intel_dp = intel_attached_dp(connector);
-	int current_rate = -1;
-	int force_rate;
-	int err;
-	int i;
-
-	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
-	if (err)
-		return err;
-
-	intel_dp_flush_connector_commits(connector);
-
-	if (intel_dp->link.active)
-		current_rate = intel_dp->link_rate;
-
-	force_rate = intel_dp->link.force_rate;
-
-	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
-
-	seq_printf(m, "%sauto%s",
-		   force_rate == 0 ? "[" : "",
-		   force_rate == 0 ? "]" : "");
-
-	for (i = 0; i < intel_dp->num_source_rates; i++)
-		seq_printf(m, " %s%d%s%s",
-			   intel_dp->source_rates[i] == force_rate ? "[" : "",
-			   intel_dp->source_rates[i],
-			   intel_dp->source_rates[i] == current_rate ? "*" : "",
-			   intel_dp->source_rates[i] == force_rate ? "]" : "");
-
-	seq_putc(m, '\n');
-
-	return 0;
-}
-
-static int parse_link_rate(struct intel_dp *intel_dp, const char __user *ubuf, size_t len)
-{
-	char *kbuf;
-	const char *p;
-	int rate;
-	int ret = 0;
-
-	kbuf = memdup_user_nul(ubuf, len);
-	if (IS_ERR(kbuf))
-		return PTR_ERR(kbuf);
-
-	p = strim(kbuf);
-
-	if (!strcmp(p, "auto")) {
-		rate = 0;
-	} else {
-		ret = kstrtoint(p, 0, &rate);
-		if (ret < 0)
-			goto out_free;
-
-		if (intel_dp_rate_index(intel_dp->source_rates,
-					intel_dp->num_source_rates,
-					rate) < 0)
-			ret = -EINVAL;
-	}
-
-out_free:
-	kfree(kbuf);
-
-	return ret < 0 ? ret : rate;
-}
-
-static ssize_t i915_dp_force_link_rate_write(struct file *file,
-					     const char __user *ubuf,
-					     size_t len, loff_t *offp)
-{
-	struct seq_file *m = file->private_data;
-	struct intel_connector *connector = to_intel_connector(m->private);
-	struct intel_display *display = to_intel_display(connector);
-	struct intel_dp *intel_dp = intel_attached_dp(connector);
-	int rate;
-	int err;
-
-	rate = parse_link_rate(intel_dp, ubuf, len);
-	if (rate < 0)
-		return rate;
-
-	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
-	if (err)
-		return err;
-
-	intel_dp_flush_connector_commits(connector);
-
-	intel_dp_reset_link_params(intel_dp);
-	intel_dp->link.force_rate = rate;
-
-	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
-
-	*offp += len;
-
-	return len;
-}
-DEFINE_SHOW_STORE_ATTRIBUTE(i915_dp_force_link_rate);
-
-static int i915_dp_force_lane_count_show(struct seq_file *m, void *data)
-{
-	struct intel_connector *connector = to_intel_connector(m->private);
-	struct intel_display *display = to_intel_display(connector);
-	struct intel_dp *intel_dp = intel_attached_dp(connector);
-	int current_lane_count = -1;
-	int force_lane_count;
-	int err;
-	int i;
-
-	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
-	if (err)
-		return err;
-
-	intel_dp_flush_connector_commits(connector);
-
-	if (intel_dp->link.active)
-		current_lane_count = intel_dp->lane_count;
-	force_lane_count = intel_dp->link.force_lane_count;
-
-	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
-
-	seq_printf(m, "%sauto%s",
-		   force_lane_count == 0 ? "[" : "",
-		   force_lane_count == 0 ? "]" : "");
-
-	for (i = 1; i <= 4; i <<= 1)
-		seq_printf(m, " %s%d%s%s",
-			   i == force_lane_count ? "[" : "",
-			   i,
-			   i == current_lane_count ? "*" : "",
-			   i == force_lane_count ? "]" : "");
-
-	seq_putc(m, '\n');
-
-	return 0;
-}
-
-static int parse_lane_count(const char __user *ubuf, size_t len)
-{
-	char *kbuf;
-	const char *p;
-	int lane_count;
-	int ret = 0;
-
-	kbuf = memdup_user_nul(ubuf, len);
-	if (IS_ERR(kbuf))
-		return PTR_ERR(kbuf);
-
-	p = strim(kbuf);
-
-	if (!strcmp(p, "auto")) {
-		lane_count = 0;
-	} else {
-		ret = kstrtoint(p, 0, &lane_count);
-		if (ret < 0)
-			goto out_free;
-
-		switch (lane_count) {
-		case 1:
-		case 2:
-		case 4:
-			break;
-		default:
-			ret = -EINVAL;
-		}
-	}
-
-out_free:
-	kfree(kbuf);
-
-	return ret < 0 ? ret : lane_count;
-}
-
-static ssize_t i915_dp_force_lane_count_write(struct file *file,
-					      const char __user *ubuf,
-					      size_t len, loff_t *offp)
-{
-	struct seq_file *m = file->private_data;
-	struct intel_connector *connector = to_intel_connector(m->private);
-	struct intel_display *display = to_intel_display(connector);
-	struct intel_dp *intel_dp = intel_attached_dp(connector);
-	int lane_count;
-	int err;
-
-	lane_count = parse_lane_count(ubuf, len);
-	if (lane_count < 0)
-		return lane_count;
-
-	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
-	if (err)
-		return err;
-
-	intel_dp_flush_connector_commits(connector);
-
-	intel_dp_reset_link_params(intel_dp);
-	intel_dp->link.force_lane_count = lane_count;
-
-	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
-
-	*offp += len;
-
-	return len;
-}
-DEFINE_SHOW_STORE_ATTRIBUTE(i915_dp_force_lane_count);
-
-static int i915_dp_max_link_rate_show(void *data, u64 *val)
-{
-	struct intel_connector *connector = to_intel_connector(data);
-	struct intel_display *display = to_intel_display(connector);
-	struct intel_dp *intel_dp = intel_attached_dp(connector);
-	int err;
-
-	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
-	if (err)
-		return err;
-
-	intel_dp_flush_connector_commits(connector);
-
-	*val = intel_dp->link.max_rate;
-
-	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
-
-	return 0;
-}
-DEFINE_DEBUGFS_ATTRIBUTE(i915_dp_max_link_rate_fops, i915_dp_max_link_rate_show, NULL, "%llu\n");
-
-static int i915_dp_max_lane_count_show(void *data, u64 *val)
-{
-	struct intel_connector *connector = to_intel_connector(data);
-	struct intel_display *display = to_intel_display(connector);
-	struct intel_dp *intel_dp = intel_attached_dp(connector);
-	int err;
-
-	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
-	if (err)
-		return err;
-
-	intel_dp_flush_connector_commits(connector);
-
-	*val = intel_dp->link.max_lane_count;
-
-	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
-
-	return 0;
-}
-DEFINE_DEBUGFS_ATTRIBUTE(i915_dp_max_lane_count_fops, i915_dp_max_lane_count_show, NULL, "%llu\n");
-
 static int i915_dp_force_link_training_failure_show(void *data, u64 *val)
 {
 	struct intel_connector *connector = to_intel_connector(data);
@@ -2949,18 +2698,6 @@ void intel_dp_link_training_debugfs_add(struct intel_connector *connector)
 	    connector->base.connector_type != DRM_MODE_CONNECTOR_eDP)
 		return;
 
-	debugfs_create_file("i915_dp_force_link_rate", 0644, root,
-			    connector, &i915_dp_force_link_rate_fops);
-
-	debugfs_create_file("i915_dp_force_lane_count", 0644, root,
-			    connector, &i915_dp_force_lane_count_fops);
-
-	debugfs_create_file("i915_dp_max_link_rate", 0444, root,
-			    connector, &i915_dp_max_link_rate_fops);
-
-	debugfs_create_file("i915_dp_max_lane_count", 0444, root,
-			    connector, &i915_dp_max_lane_count_fops);
-
 	debugfs_create_file("i915_dp_force_link_training_failure", 0644, root,
 			    connector, &i915_dp_force_link_training_failure_fops);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 034/108] drm/i915/dp_link_training: Use helpers to get forced link params
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (32 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 033/108] drm/i915/dp_link_caps: Move forced and max link debugfs entries to link caps Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 035/108] drm/i915/dp_link_caps: Move forced link params to link_caps Imre Deak
                   ` (76 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Use intel_dp_link_caps_get_forced_params() in the link training fallback
code instead of directly accessing the state. This allows the link caps
module to track changes to forced parameters internally.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c | 26 ++++++++++++++-----
 1 file changed, 20 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 3455e4daf1faf..5218220b82b0b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1760,18 +1760,26 @@ static bool reduce_link_params_in_bw_order(struct intel_dp *intel_dp,
 					   const struct intel_crtc_state *crtc_state,
 					   int *new_link_rate, int *new_lane_count)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp_link_config forced_params;
+	int forced_lane_count;
+	int forced_rate;
 	int link_rate;
 	int lane_count;
 	int i;
 
+	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
+	forced_rate = forced_params.rate;
+	forced_lane_count = forced_params.lane_count;
+
 	i = intel_dp_link_config_index(intel_dp, crtc_state->port_clock, crtc_state->lane_count);
 	for (i--; i >= 0; i--) {
 		intel_dp_link_config_get(intel_dp, i, &link_rate, &lane_count);
 
-		if ((intel_dp->link.force_rate &&
-		     intel_dp->link.force_rate != link_rate) ||
-		    (intel_dp->link.force_lane_count &&
-		     intel_dp->link.force_lane_count != lane_count))
+		if ((forced_rate &&
+		     forced_rate != link_rate) ||
+		    (forced_lane_count &&
+		     forced_lane_count != lane_count))
 			continue;
 
 		break;
@@ -1788,10 +1796,13 @@ static bool reduce_link_params_in_bw_order(struct intel_dp *intel_dp,
 
 static int reduce_link_rate(struct intel_dp *intel_dp, int current_rate)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp_link_config forced_params;
 	int rate_index;
 	int new_rate;
 
-	if (intel_dp->link.force_rate)
+	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
+	if (forced_params.rate)
 		return -1;
 
 	rate_index = intel_dp_rate_index(intel_dp->common_rates,
@@ -1812,7 +1823,10 @@ static int reduce_link_rate(struct intel_dp *intel_dp, int current_rate)
 
 static int reduce_lane_count(struct intel_dp *intel_dp, int current_lane_count)
 {
-	if (intel_dp->link.force_lane_count)
+	struct intel_dp_link_config forced_params;
+
+	intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params);
+	if (forced_params.lane_count)
 		return -1;
 
 	if (current_lane_count == 1)
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 035/108] drm/i915/dp_link_caps: Move forced link params to link_caps
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (33 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 034/108] drm/i915/dp_link_training: Use helpers to get forced link params Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 036/108] drm/i915/dp_link_caps: Move link config helpers to link caps Imre Deak
                   ` (75 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Move tracking of the forced link parameters from struct intel_dp to
struct intel_dp_link_caps.

Previous changes made all users access these parameters through the link
caps helpers, so the state can now be kept internal to the link caps
module.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_display_types.h    |  2 --
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 30 ++++++++++++++-----
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index d11686ce2963d..1fae80c8c241b 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1856,8 +1856,6 @@ struct intel_dp {
 		 */
 		int mst_probed_lane_count;
 		int mst_probed_rate;
-		int force_lane_count;
-		int force_rate;
 		struct intel_dp_link_training *training;
 		struct intel_dp_link_caps *caps;
 	} link;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index ed05a8597fc01..e11a36ea2d178 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -15,6 +15,12 @@
 
 struct intel_dp_link_caps {
 	struct intel_dp *dp;
+
+	/*
+	 * Forced parameters requested via debugfs. Remains set across sink
+	 * disconnects.
+	 */
+	struct intel_dp_link_config forced_params;
 };
 
 /* Get length of common rates array potentially limited by max_rate. */
@@ -44,20 +50,24 @@ int intel_dp_max_common_rate(struct intel_dp *intel_dp)
 
 static int forced_lane_count(struct intel_dp *intel_dp)
 {
-	if (!intel_dp->link.force_lane_count)
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+
+	if (!link_caps->forced_params.lane_count)
 		return 0;
 
-	return clamp(intel_dp->link.force_lane_count, 1, intel_dp_max_common_lane_count(intel_dp));
+	return clamp(link_caps->forced_params.lane_count,
+		     1, intel_dp_max_common_lane_count(intel_dp));
 }
 
 static int forced_link_rate(struct intel_dp *intel_dp)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	int len;
 
-	if (!intel_dp->link.force_rate)
+	if (!link_caps->forced_params.rate)
 		return 0;
 
-	len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.force_rate);
+	len = intel_dp_common_len_rate_limit(intel_dp, link_caps->forced_params.rate);
 	if (len == 0)
 		return intel_dp_common_rate(intel_dp, 0);
 
@@ -76,6 +86,7 @@ static int i915_dp_force_link_rate_show(struct seq_file *m, void *data)
 	struct intel_connector *connector = to_intel_connector(m->private);
 	struct intel_display *display = to_intel_display(connector);
 	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	int current_rate = -1;
 	int force_rate;
 	int err;
@@ -90,7 +101,7 @@ static int i915_dp_force_link_rate_show(struct seq_file *m, void *data)
 	if (intel_dp->link.active)
 		current_rate = intel_dp->link_rate;
 
-	force_rate = intel_dp->link.force_rate;
+	force_rate = link_caps->forced_params.rate;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
@@ -150,6 +161,7 @@ static ssize_t i915_dp_force_link_rate_write(struct file *file,
 	struct intel_connector *connector = to_intel_connector(m->private);
 	struct intel_display *display = to_intel_display(connector);
 	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	int rate;
 	int err;
 
@@ -164,7 +176,7 @@ static ssize_t i915_dp_force_link_rate_write(struct file *file,
 	intel_dp_flush_connector_commits(connector);
 
 	intel_dp_reset_link_params(intel_dp);
-	intel_dp->link.force_rate = rate;
+	link_caps->forced_params.rate = rate;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
@@ -179,6 +191,7 @@ static int i915_dp_force_lane_count_show(struct seq_file *m, void *data)
 	struct intel_connector *connector = to_intel_connector(m->private);
 	struct intel_display *display = to_intel_display(connector);
 	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	int current_lane_count = -1;
 	int force_lane_count;
 	int err;
@@ -192,7 +205,7 @@ static int i915_dp_force_lane_count_show(struct seq_file *m, void *data)
 
 	if (intel_dp->link.active)
 		current_lane_count = intel_dp->lane_count;
-	force_lane_count = intel_dp->link.force_lane_count;
+	force_lane_count = link_caps->forced_params.lane_count;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
@@ -256,6 +269,7 @@ static ssize_t i915_dp_force_lane_count_write(struct file *file,
 	struct intel_connector *connector = to_intel_connector(m->private);
 	struct intel_display *display = to_intel_display(connector);
 	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	int lane_count;
 	int err;
 
@@ -270,7 +284,7 @@ static ssize_t i915_dp_force_lane_count_write(struct file *file,
 	intel_dp_flush_connector_commits(connector);
 
 	intel_dp_reset_link_params(intel_dp);
-	intel_dp->link.force_lane_count = lane_count;
+	link_caps->forced_params.lane_count = lane_count;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 036/108] drm/i915/dp_link_caps: Move link config helpers to link caps
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (34 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 035/108] drm/i915/dp_link_caps: Move forced link params to link_caps Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 037/108] drm/i915/dp_link_caps: Move link config tracking to link_caps Imre Deak
                   ` (74 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Move the helpers handling link configurations to intel_dp_link_caps.c.
Their functionality is part of the link capability logic and will be
updated to use the link capability state in follow-up changes.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       | 101 -----------------
 drivers/gpu/drm/i915/display/intel_dp.h       |   2 -
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 102 ++++++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h |   5 +
 4 files changed, 107 insertions(+), 103 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 52d843b05c38c..25f8ac21ce60c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -33,7 +33,6 @@
 #include <linux/notifier.h>
 #include <linux/seq_buf.h>
 #include <linux/slab.h>
-#include <linux/sort.h>
 #include <linux/string_helpers.h>
 #include <linux/timekeeping.h>
 #include <linux/types.h>
@@ -666,106 +665,6 @@ int intel_dp_rate_index(const int *rates, int len, int rate)
 	return -1;
 }
 
-static int intel_dp_link_config_rate(struct intel_dp *intel_dp,
-				     const struct intel_dp_link_config_entry *lc)
-{
-	return intel_dp_common_rate(intel_dp, lc->link_rate_idx);
-}
-
-static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_entry *lc)
-{
-	return 1 << lc->lane_count_exp;
-}
-
-static int intel_dp_link_config_bw(struct intel_dp *intel_dp,
-				   const struct intel_dp_link_config_entry *lc)
-{
-	return drm_dp_max_dprx_data_rate(intel_dp_link_config_rate(intel_dp, lc),
-					 intel_dp_link_config_lane_count(lc));
-}
-
-static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
-{
-	struct intel_dp *intel_dp = (struct intel_dp *)p;	/* remove const */
-	const struct intel_dp_link_config_entry *lc_a = a;
-	const struct intel_dp_link_config_entry *lc_b = b;
-	int bw_a = intel_dp_link_config_bw(intel_dp, lc_a);
-	int bw_b = intel_dp_link_config_bw(intel_dp, lc_b);
-
-	if (bw_a != bw_b)
-		return bw_a - bw_b;
-
-	return intel_dp_link_config_rate(intel_dp, lc_a) -
-	       intel_dp_link_config_rate(intel_dp, lc_b);
-}
-
-static void intel_dp_link_config_init(struct intel_dp *intel_dp)
-{
-	struct intel_display *display = to_intel_display(intel_dp);
-	struct intel_dp_link_config_entry *lc;
-	int num_common_lane_configs;
-	int i;
-	int j;
-
-	if (drm_WARN_ON(display->drm, !is_power_of_2(intel_dp_max_common_lane_count(intel_dp))))
-		return;
-
-	num_common_lane_configs = ilog2(intel_dp_max_common_lane_count(intel_dp)) + 1;
-
-	if (drm_WARN_ON(display->drm, intel_dp->num_common_rates * num_common_lane_configs >
-				    ARRAY_SIZE(intel_dp->link.configs)))
-		return;
-
-	intel_dp->link.num_configs = intel_dp->num_common_rates * num_common_lane_configs;
-
-	lc = &intel_dp->link.configs[0];
-	for (i = 0; i < intel_dp->num_common_rates; i++) {
-		for (j = 0; j < num_common_lane_configs; j++) {
-			lc->lane_count_exp = j;
-			lc->link_rate_idx = i;
-
-			lc++;
-		}
-	}
-
-	sort_r(intel_dp->link.configs, intel_dp->link.num_configs,
-	       sizeof(intel_dp->link.configs[0]),
-	       link_config_cmp_by_bw, NULL,
-	       intel_dp);
-}
-
-void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count)
-{
-	struct intel_display *display = to_intel_display(intel_dp);
-	const struct intel_dp_link_config_entry *lc;
-
-	if (drm_WARN_ON(display->drm, idx < 0 || idx >= intel_dp->link.num_configs))
-		idx = 0;
-
-	lc = &intel_dp->link.configs[idx];
-
-	*link_rate = intel_dp_link_config_rate(intel_dp, lc);
-	*lane_count = intel_dp_link_config_lane_count(lc);
-}
-
-int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count)
-{
-	int link_rate_idx = intel_dp_rate_index(intel_dp->common_rates, intel_dp->num_common_rates,
-						link_rate);
-	int lane_count_exp = ilog2(lane_count);
-	int i;
-
-	for (i = 0; i < intel_dp->link.num_configs; i++) {
-		const struct intel_dp_link_config_entry *lc = &intel_dp->link.configs[i];
-
-		if (lc->lane_count_exp == lane_count_exp &&
-		    lc->link_rate_idx == link_rate_idx)
-			return i;
-	}
-
-	return -1;
-}
-
 static bool current_common_caps_match(struct intel_dp *intel_dp,
 				      const int *rates, int num_rates)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 8f7607dc412d0..363907d463486 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -105,8 +105,6 @@ int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state);
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
 int intel_dp_max_common_lane_count(struct intel_dp *intel_dp);
 int intel_dp_rate_index(const int *rates, int len, int rate);
-int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count);
-void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count);
 void intel_dp_update_sink_caps(struct intel_dp *intel_dp);
 void intel_dp_reset_link_params(struct intel_dp *intel_dp);
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index e11a36ea2d178..9fadab008e8ee 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -4,7 +4,9 @@
  */
 
 #include <linux/debugfs.h>
+#include <linux/log2.h>
 #include <linux/slab.h>
+#include <linux/sort.h>
 
 #include <drm/drm_print.h>
 
@@ -81,6 +83,106 @@ void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 	forced_params->lane_count = forced_lane_count(link_caps->dp);
 }
 
+static int intel_dp_link_config_rate(struct intel_dp *intel_dp,
+				     const struct intel_dp_link_config_entry *lc)
+{
+	return intel_dp_common_rate(intel_dp, lc->link_rate_idx);
+}
+
+static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_entry *lc)
+{
+	return 1 << lc->lane_count_exp;
+}
+
+static int intel_dp_link_config_bw(struct intel_dp *intel_dp,
+				   const struct intel_dp_link_config_entry *lc)
+{
+	return drm_dp_max_dprx_data_rate(intel_dp_link_config_rate(intel_dp, lc),
+					 intel_dp_link_config_lane_count(lc));
+}
+
+static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
+{
+	struct intel_dp *intel_dp = (struct intel_dp *)p;	/* remove const */
+	const struct intel_dp_link_config_entry *lc_a = a;
+	const struct intel_dp_link_config_entry *lc_b = b;
+	int bw_a = intel_dp_link_config_bw(intel_dp, lc_a);
+	int bw_b = intel_dp_link_config_bw(intel_dp, lc_b);
+
+	if (bw_a != bw_b)
+		return bw_a - bw_b;
+
+	return intel_dp_link_config_rate(intel_dp, lc_a) -
+	       intel_dp_link_config_rate(intel_dp, lc_b);
+}
+
+void intel_dp_link_config_init(struct intel_dp *intel_dp)
+{
+	struct intel_display *display = to_intel_display(intel_dp);
+	struct intel_dp_link_config_entry *lc;
+	int num_common_lane_configs;
+	int i;
+	int j;
+
+	if (drm_WARN_ON(display->drm, !is_power_of_2(intel_dp_max_common_lane_count(intel_dp))))
+		return;
+
+	num_common_lane_configs = ilog2(intel_dp_max_common_lane_count(intel_dp)) + 1;
+
+	if (drm_WARN_ON(display->drm, intel_dp->num_common_rates * num_common_lane_configs >
+				    ARRAY_SIZE(intel_dp->link.configs)))
+		return;
+
+	intel_dp->link.num_configs = intel_dp->num_common_rates * num_common_lane_configs;
+
+	lc = &intel_dp->link.configs[0];
+	for (i = 0; i < intel_dp->num_common_rates; i++) {
+		for (j = 0; j < num_common_lane_configs; j++) {
+			lc->lane_count_exp = j;
+			lc->link_rate_idx = i;
+
+			lc++;
+		}
+	}
+
+	sort_r(intel_dp->link.configs, intel_dp->link.num_configs,
+	       sizeof(intel_dp->link.configs[0]),
+	       link_config_cmp_by_bw, NULL,
+	       intel_dp);
+}
+
+void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count)
+{
+	struct intel_display *display = to_intel_display(intel_dp);
+	const struct intel_dp_link_config_entry *lc;
+
+	if (drm_WARN_ON(display->drm, idx < 0 || idx >= intel_dp->link.num_configs))
+		idx = 0;
+
+	lc = &intel_dp->link.configs[idx];
+
+	*link_rate = intel_dp_link_config_rate(intel_dp, lc);
+	*lane_count = intel_dp_link_config_lane_count(lc);
+}
+
+int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count)
+{
+	int link_rate_idx = intel_dp_rate_index(intel_dp->common_rates, intel_dp->num_common_rates,
+						link_rate);
+	int lane_count_exp = ilog2(lane_count);
+	int i;
+
+	for (i = 0; i < intel_dp->link.num_configs; i++) {
+		const struct intel_dp_link_config_entry *lc = &intel_dp->link.configs[i];
+
+		if (lc->lane_count_exp == lane_count_exp &&
+		    lc->link_rate_idx == link_rate_idx)
+			return i;
+	}
+
+	return -1;
+}
+
 static int i915_dp_force_link_rate_show(struct seq_file *m, void *data)
 {
 	struct intel_connector *connector = to_intel_connector(m->private);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index c6a84891db464..dab956e804b95 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -17,6 +17,11 @@ int intel_dp_max_common_rate(struct intel_dp *intel_dp);
 void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 					  struct intel_dp_link_config *forced_params);
 
+int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count);
+void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count);
+
+void intel_dp_link_config_init(struct intel_dp *intel_dp);
+
 void intel_dp_link_caps_debugfs_add(struct intel_connector *connector);
 
 struct intel_dp_link_caps *intel_dp_link_caps_init(struct intel_dp *intel_dp);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 037/108] drm/i915/dp_link_caps: Move link config tracking to link_caps
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (35 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 036/108] drm/i915/dp_link_caps: Move link config helpers to link caps Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 038/108] drm/i915/dp_link_caps: Rename helper updating the link configurations Imre Deak
                   ` (73 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Move tracking of the link configurations from struct intel_dp to struct
intel_dp_link_caps.

Previous changes moved the helpers operating on configurations to the
link caps module, so the state can now be kept internal to that module.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_display_types.h    | 12 -------
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 36 ++++++++++++++-----
 2 files changed, 27 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 1fae80c8c241b..97d2836d0e159 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1832,18 +1832,6 @@ struct intel_dp {
 	struct {
 		/* TODO: move the rest of link specific fields to here */
 		bool active;
-		/* common rate,lane_count configs in bw order */
-		int num_configs;
-#define INTEL_DP_MAX_LANE_COUNT			4
-#define INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS	(ilog2(INTEL_DP_MAX_LANE_COUNT) + 1)
-#define INTEL_DP_LANE_COUNT_EXP_BITS		order_base_2(INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS)
-#define INTEL_DP_LINK_RATE_IDX_BITS		(BITS_PER_TYPE(u8) - INTEL_DP_LANE_COUNT_EXP_BITS)
-#define INTEL_DP_MAX_LINK_CONFIGS		(DP_MAX_SUPPORTED_RATES * \
-						 INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS)
-		struct intel_dp_link_config_entry {
-			u8 link_rate_idx:INTEL_DP_LINK_RATE_IDX_BITS;
-			u8 lane_count_exp:INTEL_DP_LANE_COUNT_EXP_BITS;
-		} configs[INTEL_DP_MAX_LINK_CONFIGS];
 		/* Max lane count for the current link */
 		int max_lane_count;
 		/* Max rate for the current link */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 9fadab008e8ee..0034dd439e59d 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -3,10 +3,12 @@
  * Copyright © 2026 Intel Corporation
  */
 
+#include <linux/bitops.h>
 #include <linux/debugfs.h>
 #include <linux/log2.h>
 #include <linux/slab.h>
 #include <linux/sort.h>
+#include <linux/types.h>
 
 #include <drm/drm_print.h>
 
@@ -18,6 +20,19 @@
 struct intel_dp_link_caps {
 	struct intel_dp *dp;
 
+	/* common rate,lane_count configs in bw order */
+	int num_configs;
+#define INTEL_DP_MAX_LANE_COUNT			4
+#define INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS	(ilog2(INTEL_DP_MAX_LANE_COUNT) + 1)
+#define INTEL_DP_LANE_COUNT_EXP_BITS		order_base_2(INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS)
+#define INTEL_DP_LINK_RATE_IDX_BITS		(BITS_PER_TYPE(u8) - INTEL_DP_LANE_COUNT_EXP_BITS)
+#define INTEL_DP_MAX_LINK_CONFIGS		(DP_MAX_SUPPORTED_RATES * \
+						 INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS)
+	struct intel_dp_link_config_entry {
+		u8 link_rate_idx:INTEL_DP_LINK_RATE_IDX_BITS;
+		u8 lane_count_exp:INTEL_DP_LANE_COUNT_EXP_BITS;
+	} configs[INTEL_DP_MAX_LINK_CONFIGS];
+
 	/*
 	 * Forced parameters requested via debugfs. Remains set across sink
 	 * disconnects.
@@ -118,6 +133,7 @@ static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 
 void intel_dp_link_config_init(struct intel_dp *intel_dp)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_display *display = to_intel_display(intel_dp);
 	struct intel_dp_link_config_entry *lc;
 	int num_common_lane_configs;
@@ -130,12 +146,12 @@ void intel_dp_link_config_init(struct intel_dp *intel_dp)
 	num_common_lane_configs = ilog2(intel_dp_max_common_lane_count(intel_dp)) + 1;
 
 	if (drm_WARN_ON(display->drm, intel_dp->num_common_rates * num_common_lane_configs >
-				    ARRAY_SIZE(intel_dp->link.configs)))
+				    ARRAY_SIZE(link_caps->configs)))
 		return;
 
-	intel_dp->link.num_configs = intel_dp->num_common_rates * num_common_lane_configs;
+	link_caps->num_configs = intel_dp->num_common_rates * num_common_lane_configs;
 
-	lc = &intel_dp->link.configs[0];
+	lc = &link_caps->configs[0];
 	for (i = 0; i < intel_dp->num_common_rates; i++) {
 		for (j = 0; j < num_common_lane_configs; j++) {
 			lc->lane_count_exp = j;
@@ -145,21 +161,22 @@ void intel_dp_link_config_init(struct intel_dp *intel_dp)
 		}
 	}
 
-	sort_r(intel_dp->link.configs, intel_dp->link.num_configs,
-	       sizeof(intel_dp->link.configs[0]),
+	sort_r(link_caps->configs, link_caps->num_configs,
+	       sizeof(link_caps->configs[0]),
 	       link_config_cmp_by_bw, NULL,
 	       intel_dp);
 }
 
 void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_display *display = to_intel_display(intel_dp);
 	const struct intel_dp_link_config_entry *lc;
 
-	if (drm_WARN_ON(display->drm, idx < 0 || idx >= intel_dp->link.num_configs))
+	if (drm_WARN_ON(display->drm, idx < 0 || idx >= link_caps->num_configs))
 		idx = 0;
 
-	lc = &intel_dp->link.configs[idx];
+	lc = &link_caps->configs[idx];
 
 	*link_rate = intel_dp_link_config_rate(intel_dp, lc);
 	*lane_count = intel_dp_link_config_lane_count(lc);
@@ -167,13 +184,14 @@ void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate
 
 int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	int link_rate_idx = intel_dp_rate_index(intel_dp->common_rates, intel_dp->num_common_rates,
 						link_rate);
 	int lane_count_exp = ilog2(lane_count);
 	int i;
 
-	for (i = 0; i < intel_dp->link.num_configs; i++) {
-		const struct intel_dp_link_config_entry *lc = &intel_dp->link.configs[i];
+	for (i = 0; i < link_caps->num_configs; i++) {
+		const struct intel_dp_link_config_entry *lc = &link_caps->configs[i];
 
 		if (lc->lane_count_exp == lane_count_exp &&
 		    lc->link_rate_idx == link_rate_idx)
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 038/108] drm/i915/dp_link_caps: Rename helper updating the link configurations
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (36 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 037/108] drm/i915/dp_link_caps: Move link config tracking to link_caps Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 039/108] drm/i915/dp: Factor out helper to get link rate capabilities Imre Deak
                   ` (72 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Rename the helper updating link configurations to
intel_dp_link_caps_update() to better reflect its functionality.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c           | 2 +-
 drivers/gpu/drm/i915/display/intel_dp_link_caps.c | 2 +-
 drivers/gpu/drm/i915/display/intel_dp_link_caps.h | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 25f8ac21ce60c..e0f8dc35574f3 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -711,7 +711,7 @@ static bool intel_dp_set_common_rates(struct intel_dp *intel_dp)
 	if (!current_common_caps_match(intel_dp, old_common_rates, num_old_common_rates))
 		link_params_changed = true;
 
-	intel_dp_link_config_init(intel_dp);
+	intel_dp_link_caps_update(intel_dp);
 
 	len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.max_rate);
 	if (len > 0)
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 0034dd439e59d..6e021b616934e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -131,7 +131,7 @@ static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 	       intel_dp_link_config_rate(intel_dp, lc_b);
 }
 
-void intel_dp_link_config_init(struct intel_dp *intel_dp)
+void intel_dp_link_caps_update(struct intel_dp *intel_dp)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_display *display = to_intel_display(intel_dp);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index dab956e804b95..aed2122a05d24 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -20,7 +20,7 @@ void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count);
 void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count);
 
-void intel_dp_link_config_init(struct intel_dp *intel_dp);
+void intel_dp_link_caps_update(struct intel_dp *intel_dp);
 
 void intel_dp_link_caps_debugfs_add(struct intel_connector *connector);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 039/108] drm/i915/dp: Factor out helper to get link rate capabilities
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (37 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 038/108] drm/i915/dp_link_caps: Rename helper updating the link configurations Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 040/108] drm/i915/dp_link_caps: Pass supported link rates to link caps update Imre Deak
                   ` (71 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Factor out a helper to get the supported link rates. This allows to
gather all the link capabilities and pass these to the link capability
module from a single place. A follow-up change will extend this to
gather and pass the maximum lane count capability in the same way.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 44 +++++++++++++++----------
 1 file changed, 26 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index e0f8dc35574f3..347ea9bbe1ef2 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -680,33 +680,41 @@ static bool current_common_caps_match(struct intel_dp *intel_dp,
 	return true;
 }
 
-/* Return %true if any supported or maximum link param changed. */
-static bool intel_dp_set_common_rates(struct intel_dp *intel_dp)
+static void intel_dp_get_common_rates(struct intel_dp *intel_dp,
+				      int common_rates[DP_MAX_SUPPORTED_RATES],
+				      int *num_common_rates)
 {
 	struct intel_display *display = to_intel_display(intel_dp);
+
+	drm_WARN_ON(display->drm,
+		    !intel_dp->num_source_rates || !intel_dp->num_sink_rates);
+
+	*num_common_rates = intersect_rates(intel_dp->source_rates,
+					    intel_dp->num_source_rates,
+					    intel_dp->sink_rates,
+					    intel_dp->num_sink_rates,
+					    common_rates);
+
+	/* Paranoia, there should always be something in common. */
+	if (drm_WARN_ON(display->drm, *num_common_rates == 0)) {
+		common_rates[0] = 162000;
+		*num_common_rates = 1;
+	}
+}
+
+/* Return %true if any supported or maximum link param changed. */
+static bool intel_dp_set_common_link_params(struct intel_dp *intel_dp)
+{
 	int num_old_common_rates = intel_dp->num_common_rates;
 	int old_max_rate_limit = intel_dp->link.max_rate;
 	int old_common_rates[DP_MAX_SUPPORTED_RATES];
 	bool link_params_changed = false;
 	int len;
 
-	drm_WARN_ON(display->drm,
-		    !intel_dp->num_source_rates || !intel_dp->num_sink_rates);
-
 	static_assert(sizeof(old_common_rates) == sizeof(intel_dp->common_rates));
 	memcpy(old_common_rates, intel_dp->common_rates, sizeof(old_common_rates));
 
-	intel_dp->num_common_rates = intersect_rates(intel_dp->source_rates,
-						     intel_dp->num_source_rates,
-						     intel_dp->sink_rates,
-						     intel_dp->num_sink_rates,
-						     intel_dp->common_rates);
-
-	/* Paranoia, there should always be something in common. */
-	if (drm_WARN_ON(display->drm, intel_dp->num_common_rates == 0)) {
-		intel_dp->common_rates[0] = 162000;
-		intel_dp->num_common_rates = 1;
-	}
+	intel_dp_get_common_rates(intel_dp, intel_dp->common_rates, &intel_dp->num_common_rates);
 
 	if (!current_common_caps_match(intel_dp, old_common_rates, num_old_common_rates))
 		link_params_changed = true;
@@ -4752,7 +4760,7 @@ void intel_dp_update_sink_caps(struct intel_dp *intel_dp)
 
 	intel_dp_set_sink_rates(intel_dp);
 	intel_dp_set_max_sink_lane_count(intel_dp);
-	if (intel_dp_set_common_rates(intel_dp))
+	if (intel_dp_set_common_link_params(intel_dp))
 		link_params_changed = true;
 
 	current_max_common_lane_count = intel_dp_max_common_lane_count(intel_dp);
@@ -7039,7 +7047,7 @@ intel_dp_init_connector(struct intel_digital_port *dig_port,
 	}
 
 	intel_dp_set_source_rates(intel_dp);
-	intel_dp_set_common_rates(intel_dp);
+	intel_dp_set_common_link_params(intel_dp);
 	intel_dp_reset_link_params(intel_dp);
 
 	/* init MST on ports that can support it */
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 040/108] drm/i915/dp_link_caps: Pass supported link rates to link caps update
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (38 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 039/108] drm/i915/dp: Factor out helper to get link rate capabilities Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 041/108] drm/i915/dp_link_caps: Add helper to get all supported link rates Imre Deak
                   ` (70 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Pass the supported link rates explicitly to intel_dp_link_caps_update().
This prepares for tracking these capabilities internally within the
link caps module.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       | 30 ++----------
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 47 ++++++++++++++++---
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  5 +-
 3 files changed, 50 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 347ea9bbe1ef2..febcf413bb63b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -665,21 +665,6 @@ int intel_dp_rate_index(const int *rates, int len, int rate)
 	return -1;
 }
 
-static bool current_common_caps_match(struct intel_dp *intel_dp,
-				      const int *rates, int num_rates)
-{
-	const int *current_rates = intel_dp->common_rates;
-	int num_current_rates = intel_dp->num_common_rates;
-
-	if (num_current_rates != num_rates)
-		return false;
-
-	if (memcmp(current_rates, rates, num_rates * sizeof(rates[0])))
-		return false;
-
-	return true;
-}
-
 static void intel_dp_get_common_rates(struct intel_dp *intel_dp,
 				      int common_rates[DP_MAX_SUPPORTED_RATES],
 				      int *num_common_rates)
@@ -705,22 +690,17 @@ static void intel_dp_get_common_rates(struct intel_dp *intel_dp,
 /* Return %true if any supported or maximum link param changed. */
 static bool intel_dp_set_common_link_params(struct intel_dp *intel_dp)
 {
-	int num_old_common_rates = intel_dp->num_common_rates;
 	int old_max_rate_limit = intel_dp->link.max_rate;
-	int old_common_rates[DP_MAX_SUPPORTED_RATES];
+	int num_common_rates;
+	int common_rates[DP_MAX_SUPPORTED_RATES];
 	bool link_params_changed = false;
 	int len;
 
-	static_assert(sizeof(old_common_rates) == sizeof(intel_dp->common_rates));
-	memcpy(old_common_rates, intel_dp->common_rates, sizeof(old_common_rates));
-
-	intel_dp_get_common_rates(intel_dp, intel_dp->common_rates, &intel_dp->num_common_rates);
-
-	if (!current_common_caps_match(intel_dp, old_common_rates, num_old_common_rates))
+	intel_dp_get_common_rates(intel_dp, common_rates, &num_common_rates);
+	if (intel_dp_link_caps_update(intel_dp,
+				      common_rates, num_common_rates))
 		link_params_changed = true;
 
-	intel_dp_link_caps_update(intel_dp);
-
 	len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.max_rate);
 	if (len > 0)
 		intel_dp->link.max_rate = intel_dp_common_rate(intel_dp, len - 1);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 6e021b616934e..9f8b7da98305f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -8,6 +8,7 @@
 #include <linux/log2.h>
 #include <linux/slab.h>
 #include <linux/sort.h>
+#include <linux/string.h>
 #include <linux/types.h>
 
 #include <drm/drm_print.h>
@@ -131,28 +132,56 @@ static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 	       intel_dp_link_config_rate(intel_dp, lc_b);
 }
 
-void intel_dp_link_caps_update(struct intel_dp *intel_dp)
+static bool current_common_caps_match(struct intel_dp *intel_dp,
+				      const int *rates, int num_rates)
+{
+	const int *current_rates = intel_dp->common_rates;
+	int num_current_rates = intel_dp->num_common_rates;
+
+	if (num_current_rates != num_rates)
+		return false;
+
+	if (memcmp(current_rates, rates, num_rates * sizeof(rates[0])))
+		return false;
+
+	return true;
+}
+
+/* Return %true if the supported link parameters have changed. */
+bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
+			       const int *rates, int num_rates)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_display *display = to_intel_display(intel_dp);
+	int old_rates[DP_MAX_SUPPORTED_RATES];
 	struct intel_dp_link_config_entry *lc;
+	bool link_params_changed = false;
 	int num_common_lane_configs;
+	int num_old_rates;
 	int i;
 	int j;
 
 	if (drm_WARN_ON(display->drm, !is_power_of_2(intel_dp_max_common_lane_count(intel_dp))))
-		return;
+		return false;
+
+	if (drm_WARN_ON(display->drm, num_rates > ARRAY_SIZE(intel_dp->common_rates)))
+		return false;
 
 	num_common_lane_configs = ilog2(intel_dp_max_common_lane_count(intel_dp)) + 1;
 
-	if (drm_WARN_ON(display->drm, intel_dp->num_common_rates * num_common_lane_configs >
+	if (drm_WARN_ON(display->drm, num_rates * num_common_lane_configs >
 				    ARRAY_SIZE(link_caps->configs)))
-		return;
+		return false;
 
-	link_caps->num_configs = intel_dp->num_common_rates * num_common_lane_configs;
+	num_old_rates = intel_dp->num_common_rates;
+	memcpy(old_rates, intel_dp->common_rates, num_old_rates * sizeof(old_rates[0]));
+
+	memcpy(intel_dp->common_rates, rates, num_rates * sizeof(rates[0]));
+	intel_dp->num_common_rates = num_rates;
+	link_caps->num_configs = num_rates * num_common_lane_configs;
 
 	lc = &link_caps->configs[0];
-	for (i = 0; i < intel_dp->num_common_rates; i++) {
+	for (i = 0; i < num_rates; i++) {
 		for (j = 0; j < num_common_lane_configs; j++) {
 			lc->lane_count_exp = j;
 			lc->link_rate_idx = i;
@@ -165,6 +194,12 @@ void intel_dp_link_caps_update(struct intel_dp *intel_dp)
 	       sizeof(link_caps->configs[0]),
 	       link_config_cmp_by_bw, NULL,
 	       intel_dp);
+
+	if (!current_common_caps_match(intel_dp, old_rates, num_old_rates))
+		link_params_changed = true;
+
+	/* TODO: Also detect a change in the max lane count and max link limits. */
+	return link_params_changed;
 }
 
 void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count)
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index aed2122a05d24..09e580bc5c9b3 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -4,6 +4,8 @@
 #ifndef __INTEL_DP_LINK_CAPS_H__
 #define __INTEL_DP_LINK_CAPS_H__
 
+#include <linux/types.h>
+
 struct intel_connector;
 struct intel_dp;
 struct intel_dp_link_caps;
@@ -20,7 +22,8 @@ void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count);
 void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count);
 
-void intel_dp_link_caps_update(struct intel_dp *intel_dp);
+bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
+			       const int *rates, int num_rates);
 
 void intel_dp_link_caps_debugfs_add(struct intel_connector *connector);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 041/108] drm/i915/dp_link_caps: Add helper to get all supported link rates
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (39 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 040/108] drm/i915/dp_link_caps: Pass supported link rates to link caps update Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 042/108] drm/i915/dp_link_caps: Add helper to get the number of " Imre Deak
                   ` (69 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add intel_dp_link_caps_all_common_rates() to return all supported link
rates tracked by the link_caps module. This prepares for tracking
these capabilities internally within the link caps module.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       |  6 ++++-
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 23 +++++++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  2 ++
 3 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index febcf413bb63b..d92160c522f93 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -1531,6 +1531,8 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp)
 {
 	struct intel_display *display = to_intel_display(intel_dp);
 	DECLARE_SEQ_BUF(s, 128); /* FIXME: too big for stack? */
+	const int *common_rates;
+	int num_common_rates;
 
 	if (!drm_debug_enabled(DRM_UT_KMS))
 		return;
@@ -1543,7 +1545,9 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp)
 	drm_dbg_kms(display->drm, "sink rates: %s\n", seq_buf_str(&s));
 
 	seq_buf_clear(&s);
-	seq_buf_print_array(&s, intel_dp->common_rates, intel_dp->num_common_rates);
+	intel_dp_link_caps_all_common_rates(intel_dp->link.caps,
+					    &common_rates, &num_common_rates);
+	seq_buf_print_array(&s, common_rates, num_common_rates);
 	drm_dbg_kms(display->drm, "common rates: %s\n", seq_buf_str(&s));
 }
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 9f8b7da98305f..94a643b6e68b6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -66,6 +66,29 @@ int intel_dp_max_common_rate(struct intel_dp *intel_dp)
 	return intel_dp_common_rate(intel_dp, intel_dp->num_common_rates - 1);
 }
 
+/**
+ * intel_dp_link_caps_all_common_rates - get all common link rates
+ * @link_caps: link capabilities state
+ * @rates: returned pointer to the common rate array
+ * @num_rates: returned number of entries in @rates
+ *
+ * Return all link rates through @rates and @num_rates that are currently
+ * supported by @link_caps, common to both the source and the sink. The
+ * returned array is owned by @link_caps.
+ *
+ * Besides the usual locking requirement for API access, the caller must
+ * also serialize any dereference of the returned array against concurrent
+ * updates to @link_caps.
+ */
+void intel_dp_link_caps_all_common_rates(struct intel_dp_link_caps *link_caps,
+					 const int **rates, int *num_rates)
+{
+	struct intel_dp *intel_dp = link_caps->dp;
+
+	*rates = intel_dp->common_rates;
+	*num_rates = intel_dp->num_common_rates;
+}
+
 static int forced_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 09e580bc5c9b3..636a1d16dbb47 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -15,6 +15,8 @@ int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
 				   int max_rate);
 int intel_dp_common_rate(struct intel_dp *intel_dp, int index);
 int intel_dp_max_common_rate(struct intel_dp *intel_dp);
+void intel_dp_link_caps_all_common_rates(struct intel_dp_link_caps *link_caps,
+					 const int **rates, int *num_rates);
 
 void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 					  struct intel_dp_link_config *forced_params);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 042/108] drm/i915/dp_link_caps: Add helper to get the number of supported link rates
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (40 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 041/108] drm/i915/dp_link_caps: Add helper to get all supported link rates Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 043/108] drm/i915/dp_link_caps: Add helper to get common rate index Imre Deak
                   ` (68 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add intel_dp_link_caps_num_common_rates() to return the number of
supported link rates tracked by the link_caps module. This prepares for
tracking these capabilities internally within the link caps module.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c           | 4 ++--
 drivers/gpu/drm/i915/display/intel_dp_link_caps.c | 5 +++++
 drivers/gpu/drm/i915/display/intel_dp_link_caps.h | 1 +
 3 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index d92160c522f93..666bb8e51f59e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -1768,7 +1768,7 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
 		int link_bpp_x16 =
 			intel_dp_output_format_link_bpp_x16(pipe_config->output_format, bpp);
 
-		for (i = 0; i < intel_dp->num_common_rates; i++) {
+		for (i = 0; i < intel_dp_link_caps_num_common_rates(intel_dp->link.caps); i++) {
 			link_rate = intel_dp_common_rate(intel_dp, i);
 			if (link_rate < limits->min_rate ||
 			    link_rate > limits->max_rate)
@@ -1997,7 +1997,7 @@ static int dsc_compute_link_config(struct intel_dp *intel_dp,
 	int link_rate, lane_count;
 	int i;
 
-	for (i = 0; i < intel_dp->num_common_rates; i++) {
+	for (i = 0; i < intel_dp_link_caps_num_common_rates(intel_dp->link.caps); i++) {
 		link_rate = intel_dp_common_rate(intel_dp, i);
 		if (link_rate < limits->min_rate || link_rate > limits->max_rate)
 			continue;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 94a643b6e68b6..b1b78e7cda897 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -66,6 +66,11 @@ int intel_dp_max_common_rate(struct intel_dp *intel_dp)
 	return intel_dp_common_rate(intel_dp, intel_dp->num_common_rates - 1);
 }
 
+int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps)
+{
+	return link_caps->dp->num_common_rates;
+}
+
 /**
  * intel_dp_link_caps_all_common_rates - get all common link rates
  * @link_caps: link capabilities state
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 636a1d16dbb47..b2eb61272652e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -15,6 +15,7 @@ int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
 				   int max_rate);
 int intel_dp_common_rate(struct intel_dp *intel_dp, int index);
 int intel_dp_max_common_rate(struct intel_dp *intel_dp);
+int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps);
 void intel_dp_link_caps_all_common_rates(struct intel_dp_link_caps *link_caps,
 					 const int **rates, int *num_rates);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 043/108] drm/i915/dp_link_caps: Add helper to get common rate index
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (41 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 042/108] drm/i915/dp_link_caps: Add helper to get the number of " Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 044/108] drm/i915/dp_link_caps: Move tracking of common rates to link_caps struct Imre Deak
                   ` (67 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add intel_dp_link_caps_common_rate_idx() to look up supported link rates
tracked by the link_caps module by rate. This prepares for tracking these
capabilities internally within the link caps module.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 25 +++++++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  1 +
 .../drm/i915/display/intel_dp_link_training.c |  5 ++--
 drivers/gpu/drm/i915/display/intel_dp_test.c  |  7 +++---
 4 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index b1b78e7cda897..c99fc7704b3e8 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -60,6 +60,31 @@ int intel_dp_common_rate(struct intel_dp *intel_dp, int index)
 	return intel_dp->common_rates[index];
 }
 
+/**
+ * intel_dp_link_caps_common_rate_idx - get index of a common link rate
+ * @link_caps: link capabilities state
+ * @rate: common link rate to look up
+ *
+ * Look up @rate in the rate list currently supported by @link_caps, common to
+ * both the source and the sink.
+ *
+ * The returned value is an index into the common rate list returned by
+ * intel_dp_link_caps_all_common_rates() and accepted by
+ * intel_dp_link_caps_common_rate().
+ *
+ * Return:
+ * - Index of @rate in the current common rate list.
+ * - %-1 if @rate is not present.
+ */
+int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate)
+{
+	struct intel_dp *intel_dp = link_caps->dp;
+
+	return intel_dp_rate_index(intel_dp->common_rates,
+				   intel_dp->num_common_rates,
+				   rate);
+}
+
 /* Theoretical max between source and sink */
 int intel_dp_max_common_rate(struct intel_dp *intel_dp)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index b2eb61272652e..7ec1612a044ed 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -14,6 +14,7 @@ struct intel_dp_link_config;
 int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
 				   int max_rate);
 int intel_dp_common_rate(struct intel_dp *intel_dp, int index);
+int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate);
 int intel_dp_max_common_rate(struct intel_dp *intel_dp);
 int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps);
 void intel_dp_link_caps_all_common_rates(struct intel_dp_link_caps *link_caps,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 5218220b82b0b..456540925db55 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1805,9 +1805,8 @@ static int reduce_link_rate(struct intel_dp *intel_dp, int current_rate)
 	if (forced_params.rate)
 		return -1;
 
-	rate_index = intel_dp_rate_index(intel_dp->common_rates,
-					 intel_dp->num_common_rates,
-					 current_rate);
+	rate_index = intel_dp_link_caps_common_rate_idx(link_caps,
+							current_rate);
 
 	if (rate_index <= 0)
 		return -1;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_test.c b/drivers/gpu/drm/i915/display/intel_dp_test.c
index 5cfa1dd411dab..0b791eee3b910 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_test.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_test.c
@@ -14,6 +14,7 @@
 #include "intel_display_regs.h"
 #include "intel_display_types.h"
 #include "intel_dp.h"
+#include "intel_dp_link_caps.h"
 #include "intel_dp_link_training.h"
 #include "intel_dp_mst.h"
 #include "intel_dp_test.h"
@@ -32,6 +33,7 @@ void intel_dp_test_compute_config(struct intel_dp *intel_dp,
 				  struct intel_crtc_state *pipe_config,
 				  struct link_config_limits *limits)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_display *display = to_intel_display(intel_dp);
 
 	/* For DP Compliance we override the computed bpp for the pipe */
@@ -54,9 +56,8 @@ void intel_dp_test_compute_config(struct intel_dp *intel_dp,
 		 */
 		if (intel_dp_link_params_valid(intel_dp, intel_dp->compliance.test_link_rate,
 					       intel_dp->compliance.test_lane_count)) {
-			index = intel_dp_rate_index(intel_dp->common_rates,
-						    intel_dp->num_common_rates,
-						    intel_dp->compliance.test_link_rate);
+			index = intel_dp_link_caps_common_rate_idx(link_caps,
+								   intel_dp->compliance.test_link_rate);
 			if (index >= 0) {
 				limits->min_rate = intel_dp->compliance.test_link_rate;
 				limits->max_rate = intel_dp->compliance.test_link_rate;
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 044/108] drm/i915/dp_link_caps: Move tracking of common rates to link_caps struct
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (42 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 043/108] drm/i915/dp_link_caps: Add helper to get common rate index Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 045/108] drm/i915/dp_link_caps: Track max common lane count in link_caps Imre Deak
                   ` (66 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Now that all users access the supported link rates via helpers, move
tracking of these rates from struct intel_dp to the link_caps state.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_display_types.h    |  3 --
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 54 ++++++++++---------
 2 files changed, 30 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 97d2836d0e159..71cb45a2374b0 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1826,9 +1826,6 @@ struct intel_dp {
 	bool use_rate_select;
 	/* Max sink lane count as reported by DP_MAX_LANE_COUNT */
 	int max_sink_lane_count;
-	/* intersection of source and sink rates */
-	int num_common_rates;
-	int common_rates[DP_MAX_SUPPORTED_RATES];
 	struct {
 		/* TODO: move the rest of link specific fields to here */
 		bool active;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index c99fc7704b3e8..fc0c100835595 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -21,6 +21,10 @@
 struct intel_dp_link_caps {
 	struct intel_dp *dp;
 
+	/* Rate, lane count caps common to source and sink. */
+	int num_rates;
+	int rates[DP_MAX_SUPPORTED_RATES];
+
 	/* common rate,lane_count configs in bw order */
 	int num_configs;
 #define INTEL_DP_MAX_LANE_COUNT			4
@@ -30,6 +34,7 @@ struct intel_dp_link_caps {
 #define INTEL_DP_MAX_LINK_CONFIGS		(DP_MAX_SUPPORTED_RATES * \
 						 INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS)
 	struct intel_dp_link_config_entry {
+		/* index into rates[] */
 		u8 link_rate_idx:INTEL_DP_LINK_RATE_IDX_BITS;
 		u8 lane_count_exp:INTEL_DP_LANE_COUNT_EXP_BITS;
 	} configs[INTEL_DP_MAX_LINK_CONFIGS];
@@ -45,19 +50,22 @@ struct intel_dp_link_caps {
 int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
 				   int max_rate)
 {
-	return intel_dp_rate_limit_len(intel_dp->common_rates,
-				       intel_dp->num_common_rates, max_rate);
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+
+	return intel_dp_rate_limit_len(link_caps->rates,
+				       link_caps->num_rates, max_rate);
 }
 
 int intel_dp_common_rate(struct intel_dp *intel_dp, int index)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_display *display = to_intel_display(intel_dp);
 
 	if (drm_WARN_ON(display->drm,
-			index < 0 || index >= intel_dp->num_common_rates))
+			index < 0 || index >= link_caps->num_rates))
 		return 162000;
 
-	return intel_dp->common_rates[index];
+	return link_caps->rates[index];
 }
 
 /**
@@ -78,22 +86,22 @@ int intel_dp_common_rate(struct intel_dp *intel_dp, int index)
  */
 int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate)
 {
-	struct intel_dp *intel_dp = link_caps->dp;
-
-	return intel_dp_rate_index(intel_dp->common_rates,
-				   intel_dp->num_common_rates,
+	return intel_dp_rate_index(link_caps->rates,
+				   link_caps->num_rates,
 				   rate);
 }
 
 /* Theoretical max between source and sink */
 int intel_dp_max_common_rate(struct intel_dp *intel_dp)
 {
-	return intel_dp_common_rate(intel_dp, intel_dp->num_common_rates - 1);
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+
+	return intel_dp_common_rate(intel_dp, link_caps->num_rates - 1);
 }
 
 int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps)
 {
-	return link_caps->dp->num_common_rates;
+	return link_caps->num_rates;
 }
 
 /**
@@ -113,10 +121,8 @@ int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps)
 void intel_dp_link_caps_all_common_rates(struct intel_dp_link_caps *link_caps,
 					 const int **rates, int *num_rates)
 {
-	struct intel_dp *intel_dp = link_caps->dp;
-
-	*rates = intel_dp->common_rates;
-	*num_rates = intel_dp->num_common_rates;
+	*rates = link_caps->rates;
+	*num_rates = link_caps->num_rates;
 }
 
 static int forced_lane_count(struct intel_dp *intel_dp)
@@ -185,11 +191,11 @@ static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 	       intel_dp_link_config_rate(intel_dp, lc_b);
 }
 
-static bool current_common_caps_match(struct intel_dp *intel_dp,
+static bool current_common_caps_match(struct intel_dp_link_caps *link_caps,
 				      const int *rates, int num_rates)
 {
-	const int *current_rates = intel_dp->common_rates;
-	int num_current_rates = intel_dp->num_common_rates;
+	const int *current_rates = link_caps->rates;
+	int num_current_rates = link_caps->num_rates;
 
 	if (num_current_rates != num_rates)
 		return false;
@@ -217,7 +223,7 @@ bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 	if (drm_WARN_ON(display->drm, !is_power_of_2(intel_dp_max_common_lane_count(intel_dp))))
 		return false;
 
-	if (drm_WARN_ON(display->drm, num_rates > ARRAY_SIZE(intel_dp->common_rates)))
+	if (drm_WARN_ON(display->drm, num_rates > ARRAY_SIZE(link_caps->rates)))
 		return false;
 
 	num_common_lane_configs = ilog2(intel_dp_max_common_lane_count(intel_dp)) + 1;
@@ -226,11 +232,11 @@ bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 				    ARRAY_SIZE(link_caps->configs)))
 		return false;
 
-	num_old_rates = intel_dp->num_common_rates;
-	memcpy(old_rates, intel_dp->common_rates, num_old_rates * sizeof(old_rates[0]));
+	num_old_rates = link_caps->num_rates;
+	memcpy(old_rates, link_caps->rates, num_old_rates * sizeof(old_rates[0]));
 
-	memcpy(intel_dp->common_rates, rates, num_rates * sizeof(rates[0]));
-	intel_dp->num_common_rates = num_rates;
+	memcpy(link_caps->rates, rates, num_rates * sizeof(rates[0]));
+	link_caps->num_rates = num_rates;
 	link_caps->num_configs = num_rates * num_common_lane_configs;
 
 	lc = &link_caps->configs[0];
@@ -248,7 +254,7 @@ bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 	       link_config_cmp_by_bw, NULL,
 	       intel_dp);
 
-	if (!current_common_caps_match(intel_dp, old_rates, num_old_rates))
+	if (!current_common_caps_match(link_caps, old_rates, num_old_rates))
 		link_params_changed = true;
 
 	/* TODO: Also detect a change in the max lane count and max link limits. */
@@ -273,7 +279,7 @@ void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate
 int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
-	int link_rate_idx = intel_dp_rate_index(intel_dp->common_rates, intel_dp->num_common_rates,
+	int link_rate_idx = intel_dp_rate_index(link_caps->rates, link_caps->num_rates,
 						link_rate);
 	int lane_count_exp = ilog2(lane_count);
 	int i;
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 045/108] drm/i915/dp_link_caps: Track max common lane count in link_caps
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (43 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 044/108] drm/i915/dp_link_caps: Move tracking of common rates to link_caps struct Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 046/108] drm/i915/dp_link_caps: Move max lane count change detection to link_caps Imre Deak
                   ` (65 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Pass the maximum common lane count to intel_dp_link_caps_update() and
track it together with the supported link rates. This prepares for
converting all users of intel_dp_max_common_lane_count() to query the
value from the link caps module instead.

This will make these queries use a cached value, similar to the
supported link rates. The cached max lane count value - along with the
rate list - is recomputed on sink capability changes, via RX_CAP_CHANGED
HPD IRQ or long HPD pulse, through intel_dp_detect() and
intel_dp_reset_link_params() respectively, so using a cached value is
ok.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c           | 3 ++-
 drivers/gpu/drm/i915/display/intel_dp_link_caps.c | 9 ++++++---
 drivers/gpu/drm/i915/display/intel_dp_link_caps.h | 2 +-
 3 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 666bb8e51f59e..ef980ab274e34 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -698,7 +698,8 @@ static bool intel_dp_set_common_link_params(struct intel_dp *intel_dp)
 
 	intel_dp_get_common_rates(intel_dp, common_rates, &num_common_rates);
 	if (intel_dp_link_caps_update(intel_dp,
-				      common_rates, num_common_rates))
+				      common_rates, num_common_rates,
+				      intel_dp_max_common_lane_count(intel_dp)))
 		link_params_changed = true;
 
 	len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.max_rate);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index fc0c100835595..214974658b343 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -24,6 +24,7 @@ struct intel_dp_link_caps {
 	/* Rate, lane count caps common to source and sink. */
 	int num_rates;
 	int rates[DP_MAX_SUPPORTED_RATES];
+	int max_lane_count;
 
 	/* common rate,lane_count configs in bw order */
 	int num_configs;
@@ -208,7 +209,7 @@ static bool current_common_caps_match(struct intel_dp_link_caps *link_caps,
 
 /* Return %true if the supported link parameters have changed. */
 bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
-			       const int *rates, int num_rates)
+			       const int *rates, int num_rates, int max_lane_count)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_display *display = to_intel_display(intel_dp);
@@ -220,13 +221,13 @@ bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 	int i;
 	int j;
 
-	if (drm_WARN_ON(display->drm, !is_power_of_2(intel_dp_max_common_lane_count(intel_dp))))
+	if (drm_WARN_ON(display->drm, !is_power_of_2(max_lane_count)))
 		return false;
 
 	if (drm_WARN_ON(display->drm, num_rates > ARRAY_SIZE(link_caps->rates)))
 		return false;
 
-	num_common_lane_configs = ilog2(intel_dp_max_common_lane_count(intel_dp)) + 1;
+	num_common_lane_configs = ilog2(max_lane_count) + 1;
 
 	if (drm_WARN_ON(display->drm, num_rates * num_common_lane_configs >
 				    ARRAY_SIZE(link_caps->configs)))
@@ -237,6 +238,8 @@ bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 
 	memcpy(link_caps->rates, rates, num_rates * sizeof(rates[0]));
 	link_caps->num_rates = num_rates;
+	link_caps->max_lane_count = max_lane_count;
+
 	link_caps->num_configs = num_rates * num_common_lane_configs;
 
 	lc = &link_caps->configs[0];
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 7ec1612a044ed..7a2e383caeef4 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -27,7 +27,7 @@ int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lan
 void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count);
 
 bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
-			       const int *rates, int num_rates);
+			       const int *rates, int num_rates, int max_lane_count);
 
 void intel_dp_link_caps_debugfs_add(struct intel_connector *connector);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 046/108] drm/i915/dp_link_caps: Move max lane count change detection to link_caps
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (44 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 045/108] drm/i915/dp_link_caps: Track max common lane count in link_caps Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 047/108] drm/i915/dp_link_caps: Use max common lane count from link_caps Imre Deak
                   ` (64 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Move detection of changes to the maximum common lane count to
intel_dp_link_caps_update(), alongside detection of changes to the
supported link rates.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c           |  4 ----
 drivers/gpu/drm/i915/display/intel_dp_link_caps.c | 14 +++++++++++---
 2 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index ef980ab274e34..4e20e1fb20512 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -4738,7 +4738,6 @@ intel_dp_has_sink_count(struct intel_dp *intel_dp)
 void intel_dp_update_sink_caps(struct intel_dp *intel_dp)
 {
 	struct intel_connector *connector = intel_dp->attached_connector;
-	int old_max_common_lane_count = intel_dp_max_common_lane_count(intel_dp);
 	int old_max_lane_count_limit = intel_dp->link.max_lane_count;
 	int current_max_common_lane_count;
 	bool link_params_changed = false;
@@ -4749,9 +4748,6 @@ void intel_dp_update_sink_caps(struct intel_dp *intel_dp)
 		link_params_changed = true;
 
 	current_max_common_lane_count = intel_dp_max_common_lane_count(intel_dp);
-	if (current_max_common_lane_count != old_max_common_lane_count)
-		link_params_changed = true;
-
 	intel_dp->link.max_lane_count = min(intel_dp->link.max_lane_count,
 					    current_max_common_lane_count);
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 214974658b343..a250d7ee06ebb 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -193,14 +193,19 @@ static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 }
 
 static bool current_common_caps_match(struct intel_dp_link_caps *link_caps,
-				      const int *rates, int num_rates)
+				      const int *rates, int num_rates,
+				      int old_max_lane_count)
 {
+	int current_max_lane_count = link_caps->max_lane_count;
 	const int *current_rates = link_caps->rates;
 	int num_current_rates = link_caps->num_rates;
 
 	if (num_current_rates != num_rates)
 		return false;
 
+	if (current_max_lane_count != old_max_lane_count)
+		return false;
+
 	if (memcmp(current_rates, rates, num_rates * sizeof(rates[0])))
 		return false;
 
@@ -217,6 +222,7 @@ bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 	struct intel_dp_link_config_entry *lc;
 	bool link_params_changed = false;
 	int num_common_lane_configs;
+	int old_max_lane_count;
 	int num_old_rates;
 	int i;
 	int j;
@@ -235,6 +241,7 @@ bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 
 	num_old_rates = link_caps->num_rates;
 	memcpy(old_rates, link_caps->rates, num_old_rates * sizeof(old_rates[0]));
+	old_max_lane_count = link_caps->max_lane_count;
 
 	memcpy(link_caps->rates, rates, num_rates * sizeof(rates[0]));
 	link_caps->num_rates = num_rates;
@@ -257,10 +264,11 @@ bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 	       link_config_cmp_by_bw, NULL,
 	       intel_dp);
 
-	if (!current_common_caps_match(link_caps, old_rates, num_old_rates))
+	if (!current_common_caps_match(link_caps, old_rates, num_old_rates,
+				       old_max_lane_count))
 		link_params_changed = true;
 
-	/* TODO: Also detect a change in the max lane count and max link limits. */
+	/* TODO: Also detect a change in the max link limits. */
 	return link_params_changed;
 }
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 047/108] drm/i915/dp_link_caps: Use max common lane count from link_caps
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (45 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 046/108] drm/i915/dp_link_caps: Move max lane count change detection to link_caps Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 048/108] drm/i915/dp_link_caps: Move updating max link limits to link_caps update Imre Deak
                   ` (63 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Convert all users of intel_dp_max_common_lane_count() to query the
maximum common lane count via the link capability API, in common with
the link rate queries.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c           | 4 ++--
 drivers/gpu/drm/i915/display/intel_dp.h           | 1 -
 drivers/gpu/drm/i915/display/intel_dp_link_caps.c | 7 ++++++-
 drivers/gpu/drm/i915/display/intel_dp_link_caps.h | 1 +
 drivers/gpu/drm/i915/display/intel_dp_tunnel.c    | 3 ++-
 5 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 4e20e1fb20512..18b06e5402611 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -338,7 +338,7 @@ int intel_dp_max_source_lane_count(struct intel_digital_port *dig_port)
 }
 
 /* Theoretical max between source and sink */
-int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
+static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
 	int source_max = intel_dp_max_source_lane_count(dig_port);
@@ -3575,7 +3575,7 @@ void intel_dp_set_link_params(struct intel_dp *intel_dp,
 
 void intel_dp_reset_link_params(struct intel_dp *intel_dp)
 {
-	intel_dp->link.max_lane_count = intel_dp_max_common_lane_count(intel_dp);
+	intel_dp->link.max_lane_count = intel_dp_link_caps_max_common_lane_count(intel_dp->link.caps);
 	intel_dp->link.max_rate = intel_dp_max_common_rate(intel_dp);
 	intel_dp->link.mst_probed_lane_count = 0;
 	intel_dp->link.mst_probed_rate = 0;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 363907d463486..6abce846b8e7e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -103,7 +103,6 @@ int intel_dp_max_link_rate(struct intel_dp *intel_dp);
 int intel_dp_max_lane_count(struct intel_dp *intel_dp);
 int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state);
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
-int intel_dp_max_common_lane_count(struct intel_dp *intel_dp);
 int intel_dp_rate_index(const int *rates, int len, int rate);
 void intel_dp_update_sink_caps(struct intel_dp *intel_dp);
 void intel_dp_reset_link_params(struct intel_dp *intel_dp);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index a250d7ee06ebb..5d41e6d9b07df 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -126,6 +126,11 @@ void intel_dp_link_caps_all_common_rates(struct intel_dp_link_caps *link_caps,
 	*num_rates = link_caps->num_rates;
 }
 
+int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_caps)
+{
+	return link_caps->max_lane_count;
+}
+
 static int forced_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
@@ -134,7 +139,7 @@ static int forced_lane_count(struct intel_dp *intel_dp)
 		return 0;
 
 	return clamp(link_caps->forced_params.lane_count,
-		     1, intel_dp_max_common_lane_count(intel_dp));
+		     1, intel_dp_link_caps_max_common_lane_count(link_caps));
 }
 
 static int forced_link_rate(struct intel_dp *intel_dp)
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 7a2e383caeef4..0283c27b71a8c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -19,6 +19,7 @@ int intel_dp_max_common_rate(struct intel_dp *intel_dp);
 int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps);
 void intel_dp_link_caps_all_common_rates(struct intel_dp_link_caps *link_caps,
 					 const int **rates, int *num_rates);
+int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_caps);
 
 void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 					  struct intel_dp_link_config *forced_params);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
index 64fd4f09d1cdd..0f1a6f9d47ec5 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
@@ -57,8 +57,9 @@ static int kbytes_to_mbits(int kbytes)
 
 static int get_current_link_bw(struct intel_dp *intel_dp)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	int rate = intel_dp_max_common_rate(intel_dp);
-	int lane_count = intel_dp_max_common_lane_count(intel_dp);
+	int lane_count = intel_dp_link_caps_max_common_lane_count(link_caps);
 
 	return intel_dp_max_link_data_rate(intel_dp, rate, lane_count);
 }
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 048/108] drm/i915/dp_link_caps: Move updating max link limits to link_caps update
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (46 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 047/108] drm/i915/dp_link_caps: Use max common lane count from link_caps Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 049/108] drm/i915/dp_link_caps: Add helpers to get max link limits Imre Deak
                   ` (62 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Move updating the maximum link rate limit to intel_dp_link_caps_update(),
together with the supported link rates and maximum lane count.

This allows updating the max rate and lane count limit - the maximum
bounds over the currently allowed link configurations - alongside both
sink capability changes and link training fallback reductions of the
allowed configuration set.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       | 18 ---------------
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 22 ++++++++++++++++---
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  2 --
 3 files changed, 19 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 18b06e5402611..7326f6d09f186 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -690,11 +690,9 @@ static void intel_dp_get_common_rates(struct intel_dp *intel_dp,
 /* Return %true if any supported or maximum link param changed. */
 static bool intel_dp_set_common_link_params(struct intel_dp *intel_dp)
 {
-	int old_max_rate_limit = intel_dp->link.max_rate;
 	int num_common_rates;
 	int common_rates[DP_MAX_SUPPORTED_RATES];
 	bool link_params_changed = false;
-	int len;
 
 	intel_dp_get_common_rates(intel_dp, common_rates, &num_common_rates);
 	if (intel_dp_link_caps_update(intel_dp,
@@ -702,13 +700,6 @@ static bool intel_dp_set_common_link_params(struct intel_dp *intel_dp)
 				      intel_dp_max_common_lane_count(intel_dp)))
 		link_params_changed = true;
 
-	len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.max_rate);
-	if (len > 0)
-		intel_dp->link.max_rate = intel_dp_common_rate(intel_dp, len - 1);
-
-	if (intel_dp->link.max_rate != old_max_rate_limit)
-		link_params_changed = true;
-
 	return link_params_changed;
 }
 
@@ -4738,8 +4729,6 @@ intel_dp_has_sink_count(struct intel_dp *intel_dp)
 void intel_dp_update_sink_caps(struct intel_dp *intel_dp)
 {
 	struct intel_connector *connector = intel_dp->attached_connector;
-	int old_max_lane_count_limit = intel_dp->link.max_lane_count;
-	int current_max_common_lane_count;
 	bool link_params_changed = false;
 
 	intel_dp_set_sink_rates(intel_dp);
@@ -4747,13 +4736,6 @@ void intel_dp_update_sink_caps(struct intel_dp *intel_dp)
 	if (intel_dp_set_common_link_params(intel_dp))
 		link_params_changed = true;
 
-	current_max_common_lane_count = intel_dp_max_common_lane_count(intel_dp);
-	intel_dp->link.max_lane_count = min(intel_dp->link.max_lane_count,
-					    current_max_common_lane_count);
-
-	if (intel_dp->link.max_lane_count != old_max_lane_count_limit)
-		link_params_changed = true;
-
 	if (link_params_changed)
 		connector->base.epoch_counter++;
 }
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 5d41e6d9b07df..e514103654fde 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -48,8 +48,8 @@ struct intel_dp_link_caps {
 };
 
 /* Get length of common rates array potentially limited by max_rate. */
-int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
-				   int max_rate)
+static int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
+					  int max_rate)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 
@@ -223,12 +223,15 @@ bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_display *display = to_intel_display(intel_dp);
+	int old_max_lane_count_limit = intel_dp->link.max_lane_count;
+	int old_max_rate_limit = intel_dp->link.max_rate;
 	int old_rates[DP_MAX_SUPPORTED_RATES];
 	struct intel_dp_link_config_entry *lc;
 	bool link_params_changed = false;
 	int num_common_lane_configs;
 	int old_max_lane_count;
 	int num_old_rates;
+	int len;
 	int i;
 	int j;
 
@@ -273,7 +276,20 @@ bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 				       old_max_lane_count))
 		link_params_changed = true;
 
-	/* TODO: Also detect a change in the max link limits. */
+	/* TODO: Update these as part of the rest of max param updates. */
+	len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.max_rate);
+	if (len > 0)
+		intel_dp->link.max_rate = intel_dp_common_rate(intel_dp, len - 1);
+
+	if (intel_dp->link.max_rate != old_max_rate_limit)
+		link_params_changed = true;
+
+	intel_dp->link.max_lane_count = min(intel_dp->link.max_lane_count,
+					    max_lane_count);
+
+	if (intel_dp->link.max_lane_count != old_max_lane_count_limit)
+		link_params_changed = true;
+
 	return link_params_changed;
 }
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 0283c27b71a8c..9f5bc9b7715fb 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -11,8 +11,6 @@ struct intel_dp;
 struct intel_dp_link_caps;
 struct intel_dp_link_config;
 
-int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
-				   int max_rate);
 int intel_dp_common_rate(struct intel_dp *intel_dp, int index);
 int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate);
 int intel_dp_max_common_rate(struct intel_dp *intel_dp);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 049/108] drm/i915/dp_link_caps: Add helpers to get max link limits
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (47 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 048/108] drm/i915/dp_link_caps: Move updating max link limits to link_caps update Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 050/108] drm/i915/dp_link_caps: Add helpers to set " Imre Deak
                   ` (61 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add intel_dp_link_caps_get_max_limits() to query the current maximum
link limits (max bound over all allowed configurations) through the
link caps API instead of direct accesses.

This allows tracking the state internally within the link caps module.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       |  9 ++++-
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 38 ++++++++++++++++++-
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  3 ++
 .../drm/i915/display/intel_dp_link_training.c |  8 +++-
 4 files changed, 52 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 7326f6d09f186..1e26f6000b711 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -355,15 +355,17 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
 int intel_dp_max_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp_link_config max_link_limits;
 	struct intel_dp_link_config forced_params;
 	int lane_count;
 
+	intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits);
 	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
 
 	if (forced_params.lane_count)
 		lane_count = forced_params.lane_count;
 	else
-		lane_count = intel_dp->link.max_lane_count;
+		lane_count = max_link_limits.lane_count;
 
 	switch (lane_count) {
 	case 1:
@@ -1547,6 +1549,7 @@ int
 intel_dp_max_link_rate(struct intel_dp *intel_dp)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp_link_config max_link_limits;
 	struct intel_dp_link_config forced_params;
 
 	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
@@ -1554,7 +1557,9 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 	if (forced_params.rate)
 		return forced_params.rate;
 
-	return intel_dp->link.max_rate;
+	intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits);
+
+	return max_link_limits.rate;
 }
 
 static int
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index e514103654fde..f645c0a9dba69 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -175,6 +175,36 @@ static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_ent
 	return 1 << lc->lane_count_exp;
 }
 
+/**
+ * intel_dp_link_caps_get_max_limits - get the current maximum link limits
+ * @link_caps: link capabilities state
+ * @max_link_limits: returned maximum link limits
+ *
+ * Return the current maximum rate and lane count limits in
+ * @max_link_limits.
+ *
+ * These limits constrain the set of allowed configurations.
+ *
+ * The limits are set to the maximum common supported values after
+ * intel_dp_link_caps_reset() is called, and can later be modified by
+ * intel_dp_link_caps_set_max_limits(). The max rate and lane count
+ * parameters are independent limits, so the pair does not necessarily
+ * define a valid configuration.
+ *
+ * This function may be called without serializing against updates to
+ * @link_caps. However, without such serialization the returned value may be
+ * an out-of-sync (link rate, lane count) tuple, i.e. the parameters may
+ * belong to different update snapshots in time.
+ */
+void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
+				       struct intel_dp_link_config *max_link_limits)
+{
+	struct intel_dp *intel_dp = link_caps->dp;
+
+	max_link_limits->rate = intel_dp->link.max_rate;
+	max_link_limits->lane_count = intel_dp->link.max_lane_count;
+}
+
 static int intel_dp_link_config_bw(struct intel_dp *intel_dp,
 				   const struct intel_dp_link_config_entry *lc)
 {
@@ -545,6 +575,7 @@ static int i915_dp_max_link_rate_show(void *data, u64 *val)
 	struct intel_connector *connector = to_intel_connector(data);
 	struct intel_display *display = to_intel_display(connector);
 	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_config max_link_limits;
 	int err;
 
 	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
@@ -553,7 +584,8 @@ static int i915_dp_max_link_rate_show(void *data, u64 *val)
 
 	intel_dp_flush_connector_commits(connector);
 
-	*val = intel_dp->link.max_rate;
+	intel_dp_link_caps_get_max_limits(intel_dp->link.caps, &max_link_limits);
+	*val = max_link_limits.rate;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
@@ -566,6 +598,7 @@ static int i915_dp_max_lane_count_show(void *data, u64 *val)
 	struct intel_connector *connector = to_intel_connector(data);
 	struct intel_display *display = to_intel_display(connector);
 	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_config max_link_limits;
 	int err;
 
 	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
@@ -574,7 +607,8 @@ static int i915_dp_max_lane_count_show(void *data, u64 *val)
 
 	intel_dp_flush_connector_commits(connector);
 
-	*val = intel_dp->link.max_lane_count;
+	intel_dp_link_caps_get_max_limits(intel_dp->link.caps, &max_link_limits);
+	*val = max_link_limits.lane_count;
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 9f5bc9b7715fb..35bbe340955a6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -25,6 +25,9 @@ void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count);
 void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count);
 
+void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
+				       struct intel_dp_link_config *max_link_limits);
+
 bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 			       const int *rates, int num_rates, int max_lane_count);
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 456540925db55..ff146027baa3c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -2303,6 +2303,8 @@ void intel_dp_128b132b_sdp_crc16(struct intel_dp *intel_dp,
 bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
 				u8 lane_count)
 {
+	struct intel_dp_link_config max_link_limits;
+
 	/*
 	 * FIXME: we need to synchronize the current link parameters with
 	 * hardware readout. Currently fast link training doesn't work on
@@ -2325,12 +2327,14 @@ bool intel_dp_link_params_valid(struct intel_dp *intel_dp, int link_rate,
 	 * configuration. Although that happens to be true for now, it will
 	 * stop being guaranteed once fallback depends only on disabled configs.
 	 */
+	intel_dp_link_caps_get_max_limits(intel_dp->link.caps, &max_link_limits);
+
 	if (link_rate == 0 ||
-	    link_rate > intel_dp->link.max_rate)
+	    link_rate > max_link_limits.rate)
 		return false;
 
 	if (lane_count == 0 ||
-	    lane_count > intel_dp_max_lane_count(intel_dp))
+	    lane_count > max_link_limits.lane_count)
 		return false;
 
 	return true;
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 050/108] drm/i915/dp_link_caps: Add helpers to set max link limits
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (48 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 049/108] drm/i915/dp_link_caps: Add helpers to get max link limits Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 051/108] drm/i915/dp_link_caps: Validate " Imre Deak
                   ` (60 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add intel_dp_link_caps_set_max_limits() to set the current maximum link
limits (max bound over all allowed configurations) through the link caps
API instead of direct accesses.

This allows tracking the state internally within the link caps module.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 35 +++++++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  2 ++
 .../drm/i915/display/intel_dp_link_training.c |  9 +++--
 3 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index f645c0a9dba69..fa8d3a140414f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -175,6 +175,15 @@ static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_ent
 	return 1 << lc->lane_count_exp;
 }
 
+static void set_max_link_limits_no_update(struct intel_dp_link_caps *link_caps,
+					  const struct intel_dp_link_config *max_link_limits)
+{
+	struct intel_dp *intel_dp = link_caps->dp;
+
+	intel_dp->link.max_rate = max_link_limits->rate;
+	intel_dp->link.max_lane_count = max_link_limits->lane_count;
+}
+
 /**
  * intel_dp_link_caps_get_max_limits - get the current maximum link limits
  * @link_caps: link capabilities state
@@ -205,6 +214,32 @@ void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
 	max_link_limits->lane_count = intel_dp->link.max_lane_count;
 }
 
+/**
+ * intel_dp_link_caps_set_max_limits - set the current maximum link limits
+ * @link_caps: link capabilities state
+ * @max_link_limits: new maximum link limits
+ *
+ * Set the current maximum rate and lane count limits to @max_link_limits,
+ * constraining the set of allowed configurations.
+ *
+ * Unlike intel_dp_link_caps_get_max_limits(), the caller must serialize
+ * this call against concurrent queries and updates to @link_caps, in line
+ * with the rest of the API.
+ *
+ * Return:
+ * - %true  if the @link_caps cached max limits value got updated with
+ *          @max_link_limits.
+ * - %false if @max_link_limits is invalid.
+ */
+bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
+				       const struct intel_dp_link_config *max_link_limits)
+{
+	set_max_link_limits_no_update(link_caps, max_link_limits);
+
+	/* TODO: validate max_link_limits */
+	return true;
+}
+
 static int intel_dp_link_config_bw(struct intel_dp *intel_dp,
 				   const struct intel_dp_link_config_entry *lc)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 35bbe340955a6..ed053d9c81380 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -27,6 +27,8 @@ void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate
 
 void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
 				       struct intel_dp_link_config *max_link_limits);
+bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
+				       const struct intel_dp_link_config *max_link_limits);
 
 bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 			       const int *rates, int num_rates, int max_lane_count);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index ff146027baa3c..5e60621f4442e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1872,6 +1872,8 @@ static bool reduce_link_params(struct intel_dp *intel_dp, const struct intel_crt
 static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
 						   const struct intel_crtc_state *crtc_state)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp_link_config max_link_limits;
 	int new_link_rate;
 	int new_lane_count;
 
@@ -1897,8 +1899,11 @@ static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
 	       crtc_state->lane_count, crtc_state->port_clock,
 	       new_lane_count, new_link_rate);
 
-	intel_dp->link.max_rate = new_link_rate;
-	intel_dp->link.max_lane_count = new_lane_count;
+	max_link_limits.rate = new_link_rate;
+	max_link_limits.lane_count = new_lane_count;
+
+	/* TODO: handle an update failure */
+	intel_dp_link_caps_set_max_limits(link_caps, &max_link_limits);
 
 	return 0;
 }
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 051/108] drm/i915/dp_link_caps: Validate max link limits
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (49 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 050/108] drm/i915/dp_link_caps: Add helpers to set " Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 052/108] drm/i915/dp_link_caps: Add helper to reset " Imre Deak
                   ` (59 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add validation in intel_dp_link_caps_set_max_limits() to ensure that
the new maximum rate and lane count leave at least one allowed
configuration.

The validation takes disabled configurations, active forced parameters
and previously set max limits into account. Disabled configurations are
not supported yet, so that part has no effect for now.

At the moment this validation is also performed by the link training
fallback code, but that will be removed later, leaving only the link
caps module to perform the validation added in this patch.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 70 ++++++++++++++++++-
 1 file changed, 69 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index fa8d3a140414f..90cbbe32f180b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -175,6 +175,54 @@ static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_ent
 	return 1 << lc->lane_count_exp;
 }
 
+static void
+to_intel_dp_link_config(struct intel_dp_link_caps *link_caps,
+			const struct intel_dp_link_config_entry *lc,
+			struct intel_dp_link_config *config)
+{
+	struct intel_dp *intel_dp = link_caps->dp;
+
+	config->rate = intel_dp_link_config_rate(intel_dp, lc);
+	config->lane_count = intel_dp_link_config_lane_count(lc);
+}
+
+static u32 calc_allowed_config_mask(struct intel_dp_link_caps *link_caps,
+				    u32 disabled_config_mask,
+				    const struct intel_dp_link_config *max_limits,
+				    const struct intel_dp_link_config *forced_params)
+{
+	struct intel_dp_link_config config;
+	u32 allowed_mask = 0;
+	int config_idx;
+
+	for (config_idx = 0; config_idx < link_caps->num_configs; config_idx++) {
+		const struct intel_dp_link_config_entry *lc = &link_caps->configs[config_idx];
+
+		if (BIT(config_idx) & disabled_config_mask)
+			continue;
+
+		to_intel_dp_link_config(link_caps, lc, &config);
+
+		if (forced_params->rate &&
+		    forced_params->rate != config.rate)
+			continue;
+
+		if (forced_params->lane_count &&
+		    forced_params->lane_count != config.lane_count)
+			continue;
+
+		if (config.rate > max_limits->rate)
+			continue;
+
+		if (config.lane_count > max_limits->lane_count)
+			continue;
+
+		allowed_mask |= BIT(config_idx);
+	}
+
+	return allowed_mask;
+}
+
 static void set_max_link_limits_no_update(struct intel_dp_link_caps *link_caps,
 					  const struct intel_dp_link_config *max_link_limits)
 {
@@ -214,6 +262,20 @@ void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
 	max_link_limits->lane_count = intel_dp->link.max_lane_count;
 }
 
+static bool max_link_limits_valid(struct intel_dp_link_caps *link_caps,
+				  const struct intel_dp_link_config *max_link_limits)
+{
+	struct intel_dp_link_config forced_params;
+	u32 disabled_mask = 0;	/* get the mask from link_caps. */
+	u32 allowed_mask;
+
+	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
+	allowed_mask = calc_allowed_config_mask(link_caps, disabled_mask,
+						max_link_limits, &forced_params);
+
+	return allowed_mask != 0;
+}
+
 /**
  * intel_dp_link_caps_set_max_limits - set the current maximum link limits
  * @link_caps: link capabilities state
@@ -222,6 +284,10 @@ void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
  * Set the current maximum rate and lane count limits to @max_link_limits,
  * constraining the set of allowed configurations.
  *
+ * The new limits must leave at least one configuration allowed: the limits
+ * must not be below the currently active forced parameters or below all the
+ * configurations that remain after disabled configurations are excluded.
+ *
  * Unlike intel_dp_link_caps_get_max_limits(), the caller must serialize
  * this call against concurrent queries and updates to @link_caps, in line
  * with the rest of the API.
@@ -234,9 +300,11 @@ void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
 bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
 				       const struct intel_dp_link_config *max_link_limits)
 {
+	if (!max_link_limits_valid(link_caps, max_link_limits))
+		return false;
+
 	set_max_link_limits_no_update(link_caps, max_link_limits);
 
-	/* TODO: validate max_link_limits */
 	return true;
 }
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 052/108] drm/i915/dp_link_caps: Add helper to reset max link limits
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (50 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 051/108] drm/i915/dp_link_caps: Validate " Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 053/108] drm/i915/dp_link_caps: Add helper to reset link_caps state Imre Deak
                   ` (58 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add a helper to reset the link_caps::max_limits max link limits to the
maximum common supported rate and lane count.

This is needed by a follow-up change in the link training fallback code,
which temporarily resets max_limits before searching for a fallback
configuration.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 22 +++++++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  1 +
 2 files changed, 23 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 90cbbe32f180b..e23793ffde58c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -232,6 +232,16 @@ static void set_max_link_limits_no_update(struct intel_dp_link_caps *link_caps,
 	intel_dp->link.max_lane_count = max_link_limits->lane_count;
 }
 
+static void reset_max_link_limits_no_update(struct intel_dp_link_caps *link_caps)
+{
+	struct intel_dp_link_config max_link_limits = {
+		.rate = intel_dp_max_common_rate(link_caps->dp),
+		.lane_count = intel_dp_link_caps_max_common_lane_count(link_caps),
+	};
+
+	set_max_link_limits_no_update(link_caps, &max_link_limits);
+}
+
 /**
  * intel_dp_link_caps_get_max_limits - get the current maximum link limits
  * @link_caps: link capabilities state
@@ -308,6 +318,18 @@ bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
 	return true;
 }
 
+/**
+ * intel_dp_link_caps_reset_max_limits - reset the current maximum link limits
+ * @link_caps: link capabilities state
+ *
+ * Reset the current maximum link limits to the maximum supported common link
+ * rate and lane count.
+ */
+void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps)
+{
+	reset_max_link_limits_no_update(link_caps);
+}
+
 static int intel_dp_link_config_bw(struct intel_dp *intel_dp,
 				   const struct intel_dp_link_config_entry *lc)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index ed053d9c81380..c7ea40b1714d1 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -29,6 +29,7 @@ void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
 				       struct intel_dp_link_config *max_link_limits);
 bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
 				       const struct intel_dp_link_config *max_link_limits);
+void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps);
 
 bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 			       const int *rates, int num_rates, int max_lane_count);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 053/108] drm/i915/dp_link_caps: Add helper to reset link_caps state
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (51 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 052/108] drm/i915/dp_link_caps: Add helper to reset " Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 054/108] drm/i915/dp_link_caps: Move max link limits to link_caps Imre Deak
                   ` (57 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add a helper to reset the link_caps state, removing all restrictions
except user-forced parameters, re-allowing all supported
configurations. Currently this only resets the maximum link limits,
but follow-up changes will also re-enable configurations previously
disabled on a per-configuration basis by fallback or other logic.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c        |  3 +--
 .../gpu/drm/i915/display/intel_dp_link_caps.c  | 18 ++++++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h  |  1 +
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 1e26f6000b711..dd4c03893a69f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -3571,8 +3571,7 @@ void intel_dp_set_link_params(struct intel_dp *intel_dp,
 
 void intel_dp_reset_link_params(struct intel_dp *intel_dp)
 {
-	intel_dp->link.max_lane_count = intel_dp_link_caps_max_common_lane_count(intel_dp->link.caps);
-	intel_dp->link.max_rate = intel_dp_max_common_rate(intel_dp);
+	intel_dp_link_caps_reset(intel_dp->link.caps);
 	intel_dp->link.mst_probed_lane_count = 0;
 	intel_dp->link.mst_probed_rate = 0;
 	intel_dp_link_training_reset(intel_dp->link.training);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index e23793ffde58c..bdb0d31b0cf03 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -482,6 +482,24 @@ int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lan
 	return -1;
 }
 
+/**
+ * intel_dp_link_caps_reset - reset link capability restrictions
+ * @link_caps: link capabilities state
+ *
+ * Reset all current restrictions except for the user requested forced
+ * parameters, thus updating the set of allowed configurations and the
+ * derived maximum link information accordingly.
+ *
+ * This function is regularly called after a sink is connected, either
+ * for the first time to the connector or after a previous sink was
+ * disconnected from it, and intel_dp_link_caps_update() was called.
+ */
+void intel_dp_link_caps_reset(struct intel_dp_link_caps *link_caps)
+{
+	/* TODO: Update the limits to account for forced params. */
+	reset_max_link_limits_no_update(link_caps);
+}
+
 static int i915_dp_force_link_rate_show(struct seq_file *m, void *data)
 {
 	struct intel_connector *connector = to_intel_connector(m->private);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index c7ea40b1714d1..fed8b0ca72ff2 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -33,6 +33,7 @@ void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps);
 
 bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 			       const int *rates, int num_rates, int max_lane_count);
+void intel_dp_link_caps_reset(struct intel_dp_link_caps *link_caps);
 
 void intel_dp_link_caps_debugfs_add(struct intel_connector *connector);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 054/108] drm/i915/dp_link_caps: Move max link limits to link_caps
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (52 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 053/108] drm/i915/dp_link_caps: Add helper to reset link_caps state Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 055/108] drm/i915/dp_link_caps: Pass link_caps to static functions Imre Deak
                   ` (56 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Now that all users access the max link limits via helpers, move tracking
of these limits from struct intel_dp to the link_caps state.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_display_types.h    |  4 --
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 56 +++++++++++++------
 2 files changed, 40 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h
index 71cb45a2374b0..b01f4d07ba862 100644
--- a/drivers/gpu/drm/i915/display/intel_display_types.h
+++ b/drivers/gpu/drm/i915/display/intel_display_types.h
@@ -1829,10 +1829,6 @@ struct intel_dp {
 	struct {
 		/* TODO: move the rest of link specific fields to here */
 		bool active;
-		/* Max lane count for the current link */
-		int max_lane_count;
-		/* Max rate for the current link */
-		int max_rate;
 		/*
 		 * Link parameters for which the MST topology was probed.
 		 * Tracking these ensures that the MST path resources are
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index bdb0d31b0cf03..6d0ce343e7b04 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -45,6 +45,36 @@ struct intel_dp_link_caps {
 	 * disconnects.
 	 */
 	struct intel_dp_link_config forced_params;
+
+	/*
+	 * Cached / settable upper bounds of the allowed configurations.
+	 *
+	 * max_limits is set via the link caps API and kept updated to the
+	 * actual maximal parameter bounds of the allowed configurations.
+	 * Such updates do not increase max_limits above the value set via the
+	 * API, except when max_limits is reset, see below. The limits (set
+	 * via the API) will constrain the allowed configurations.
+	 *
+	 * max_limits is reset in the same cases as the disabled configuration
+	 * mask (see config_table.disabled_config_mask). This restores
+	 * max_limits to the maximum parameters of the allowed configurations
+	 * as defined above, with the previous max_limits constraint removed
+	 * and the disabled configuration mask cleared, i.e. constrained only
+	 * by forced_params.
+	 *
+	 * max_limits.rate and max_limits.lane_count may come from different
+	 * allowed configurations, i.e. the (max_limits.rate,
+	 * max_limits.lane_count) tuple itself may not be an allowed
+	 * configuration.
+	 *
+	 * TODO: List the events that reset max_limits, after the
+	 * introduction of disabled_config_mask.
+	 *
+	 * TODO: Make max_limits reflect the maximum of the allowed
+	 * configurations at all times and stop making it settable via the
+	 * API, removing it as a constraint on the allowed configurations.
+	 */
+	struct intel_dp_link_config max_limits;
 };
 
 /* Get length of common rates array potentially limited by max_rate. */
@@ -226,10 +256,7 @@ static u32 calc_allowed_config_mask(struct intel_dp_link_caps *link_caps,
 static void set_max_link_limits_no_update(struct intel_dp_link_caps *link_caps,
 					  const struct intel_dp_link_config *max_link_limits)
 {
-	struct intel_dp *intel_dp = link_caps->dp;
-
-	intel_dp->link.max_rate = max_link_limits->rate;
-	intel_dp->link.max_lane_count = max_link_limits->lane_count;
+	link_caps->max_limits = *max_link_limits;
 }
 
 static void reset_max_link_limits_no_update(struct intel_dp_link_caps *link_caps)
@@ -266,10 +293,7 @@ static void reset_max_link_limits_no_update(struct intel_dp_link_caps *link_caps
 void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
 				       struct intel_dp_link_config *max_link_limits)
 {
-	struct intel_dp *intel_dp = link_caps->dp;
-
-	max_link_limits->rate = intel_dp->link.max_rate;
-	max_link_limits->lane_count = intel_dp->link.max_lane_count;
+	*max_link_limits = link_caps->max_limits;
 }
 
 static bool max_link_limits_valid(struct intel_dp_link_caps *link_caps,
@@ -378,8 +402,8 @@ bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_display *display = to_intel_display(intel_dp);
-	int old_max_lane_count_limit = intel_dp->link.max_lane_count;
-	int old_max_rate_limit = intel_dp->link.max_rate;
+	struct intel_dp_link_config old_max_limits =
+		link_caps->max_limits;
 	int old_rates[DP_MAX_SUPPORTED_RATES];
 	struct intel_dp_link_config_entry *lc;
 	bool link_params_changed = false;
@@ -432,17 +456,17 @@ bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 		link_params_changed = true;
 
 	/* TODO: Update these as part of the rest of max param updates. */
-	len = intel_dp_common_len_rate_limit(intel_dp, intel_dp->link.max_rate);
+	len = intel_dp_common_len_rate_limit(intel_dp, link_caps->max_limits.rate);
 	if (len > 0)
-		intel_dp->link.max_rate = intel_dp_common_rate(intel_dp, len - 1);
+		link_caps->max_limits.rate = intel_dp_common_rate(intel_dp, len - 1);
 
-	if (intel_dp->link.max_rate != old_max_rate_limit)
+	if (link_caps->max_limits.rate != old_max_limits.rate)
 		link_params_changed = true;
 
-	intel_dp->link.max_lane_count = min(intel_dp->link.max_lane_count,
-					    max_lane_count);
+	link_caps->max_limits.lane_count = min(link_caps->max_limits.lane_count,
+					       max_lane_count);
 
-	if (intel_dp->link.max_lane_count != old_max_lane_count_limit)
+	if (link_caps->max_limits.lane_count != old_max_limits.lane_count)
 		link_params_changed = true;
 
 	return link_params_changed;
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 055/108] drm/i915/dp_link_caps: Pass link_caps to static functions
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (53 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 054/108] drm/i915/dp_link_caps: Move max link limits to link_caps Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 056/108] drm/i915/dp_link_caps: Pass link_caps to config update/lookup helpers Imre Deak
                   ` (55 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Pass the link_caps pointer to static functions in intel_dp_link_caps.c,
as it holds the state with the relevant information.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 41 +++++++++----------
 1 file changed, 20 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 6d0ce343e7b04..1f6e391838894 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -161,10 +161,8 @@ int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_cap
 	return link_caps->max_lane_count;
 }
 
-static int forced_lane_count(struct intel_dp *intel_dp)
+static int forced_lane_count(struct intel_dp_link_caps *link_caps)
 {
-	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
-
 	if (!link_caps->forced_params.lane_count)
 		return 0;
 
@@ -172,9 +170,9 @@ static int forced_lane_count(struct intel_dp *intel_dp)
 		     1, intel_dp_link_caps_max_common_lane_count(link_caps));
 }
 
-static int forced_link_rate(struct intel_dp *intel_dp)
+static int forced_link_rate(struct intel_dp_link_caps *link_caps)
 {
-	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp *intel_dp = link_caps->dp;
 	int len;
 
 	if (!link_caps->forced_params.rate)
@@ -190,14 +188,14 @@ static int forced_link_rate(struct intel_dp *intel_dp)
 void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 					  struct intel_dp_link_config *forced_params)
 {
-	forced_params->rate = forced_link_rate(link_caps->dp);
-	forced_params->lane_count = forced_lane_count(link_caps->dp);
+	forced_params->rate = forced_link_rate(link_caps);
+	forced_params->lane_count = forced_lane_count(link_caps);
 }
 
-static int intel_dp_link_config_rate(struct intel_dp *intel_dp,
+static int intel_dp_link_config_rate(struct intel_dp_link_caps *link_caps,
 				     const struct intel_dp_link_config_entry *lc)
 {
-	return intel_dp_common_rate(intel_dp, lc->link_rate_idx);
+	return intel_dp_common_rate(link_caps->dp, lc->link_rate_idx);
 }
 
 static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_entry *lc)
@@ -210,9 +208,7 @@ to_intel_dp_link_config(struct intel_dp_link_caps *link_caps,
 			const struct intel_dp_link_config_entry *lc,
 			struct intel_dp_link_config *config)
 {
-	struct intel_dp *intel_dp = link_caps->dp;
-
-	config->rate = intel_dp_link_config_rate(intel_dp, lc);
+	config->rate = intel_dp_link_config_rate(link_caps, lc);
 	config->lane_count = intel_dp_link_config_lane_count(lc);
 }
 
@@ -354,26 +350,28 @@ void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps)
 	reset_max_link_limits_no_update(link_caps);
 }
 
-static int intel_dp_link_config_bw(struct intel_dp *intel_dp,
+static int intel_dp_link_config_bw(struct intel_dp_link_caps *link_caps,
 				   const struct intel_dp_link_config_entry *lc)
 {
-	return drm_dp_max_dprx_data_rate(intel_dp_link_config_rate(intel_dp, lc),
+	return drm_dp_max_dprx_data_rate(intel_dp_link_config_rate(link_caps, lc),
 					 intel_dp_link_config_lane_count(lc));
 }
 
 static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 {
 	struct intel_dp *intel_dp = (struct intel_dp *)p;	/* remove const */
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+
 	const struct intel_dp_link_config_entry *lc_a = a;
 	const struct intel_dp_link_config_entry *lc_b = b;
-	int bw_a = intel_dp_link_config_bw(intel_dp, lc_a);
-	int bw_b = intel_dp_link_config_bw(intel_dp, lc_b);
+	int bw_a = intel_dp_link_config_bw(link_caps, lc_a);
+	int bw_b = intel_dp_link_config_bw(link_caps, lc_b);
 
 	if (bw_a != bw_b)
 		return bw_a - bw_b;
 
-	return intel_dp_link_config_rate(intel_dp, lc_a) -
-	       intel_dp_link_config_rate(intel_dp, lc_b);
+	return intel_dp_link_config_rate(link_caps, lc_a) -
+	       intel_dp_link_config_rate(link_caps, lc_b);
 }
 
 static bool current_common_caps_match(struct intel_dp_link_caps *link_caps,
@@ -483,7 +481,7 @@ void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate
 
 	lc = &link_caps->configs[idx];
 
-	*link_rate = intel_dp_link_config_rate(intel_dp, lc);
+	*link_rate = intel_dp_link_config_rate(link_caps, lc);
 	*lane_count = intel_dp_link_config_lane_count(lc);
 }
 
@@ -564,8 +562,9 @@ static int i915_dp_force_link_rate_show(struct seq_file *m, void *data)
 	return 0;
 }
 
-static int parse_link_rate(struct intel_dp *intel_dp, const char __user *ubuf, size_t len)
+static int parse_link_rate(struct intel_dp_link_caps *link_caps, const char __user *ubuf, size_t len)
 {
+	struct intel_dp *intel_dp = link_caps->dp;
 	char *kbuf;
 	const char *p;
 	int rate;
@@ -608,7 +607,7 @@ static ssize_t i915_dp_force_link_rate_write(struct file *file,
 	int rate;
 	int err;
 
-	rate = parse_link_rate(intel_dp, ubuf, len);
+	rate = parse_link_rate(link_caps, ubuf, len);
 	if (rate < 0)
 		return rate;
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 056/108] drm/i915/dp_link_caps: Pass link_caps to config update/lookup helpers
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (54 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 055/108] drm/i915/dp_link_caps: Pass link_caps to static functions Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 057/108] drm/i915/dp_link_caps: Pass link_caps to common rate helpers Imre Deak
                   ` (54 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Pass the link_caps pointer to the update/lookup helpers in
intel_dp_link_caps.c, as it holds the state with the relevant
information.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c            |  2 +-
 drivers/gpu/drm/i915/display/intel_dp_link_caps.c  | 14 +++++++-------
 drivers/gpu/drm/i915/display/intel_dp_link_caps.h  |  8 +++++---
 .../gpu/drm/i915/display/intel_dp_link_training.c  |  5 +++--
 4 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index dd4c03893a69f..a3f293af5dbfb 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -697,7 +697,7 @@ static bool intel_dp_set_common_link_params(struct intel_dp *intel_dp)
 	bool link_params_changed = false;
 
 	intel_dp_get_common_rates(intel_dp, common_rates, &num_common_rates);
-	if (intel_dp_link_caps_update(intel_dp,
+	if (intel_dp_link_caps_update(intel_dp->link.caps,
 				      common_rates, num_common_rates,
 				      intel_dp_max_common_lane_count(intel_dp)))
 		link_params_changed = true;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 1f6e391838894..fc569092a4dd6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -395,10 +395,10 @@ static bool current_common_caps_match(struct intel_dp_link_caps *link_caps,
 }
 
 /* Return %true if the supported link parameters have changed. */
-bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
+bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 			       const int *rates, int num_rates, int max_lane_count)
 {
-	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp *intel_dp = link_caps->dp;
 	struct intel_display *display = to_intel_display(intel_dp);
 	struct intel_dp_link_config old_max_limits =
 		link_caps->max_limits;
@@ -470,10 +470,10 @@ bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
 	return link_params_changed;
 }
 
-void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count)
+void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps,
+			      int idx, int *link_rate, int *lane_count)
 {
-	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
-	struct intel_display *display = to_intel_display(intel_dp);
+	struct intel_display *display = to_intel_display(link_caps->dp);
 	const struct intel_dp_link_config_entry *lc;
 
 	if (drm_WARN_ON(display->drm, idx < 0 || idx >= link_caps->num_configs))
@@ -485,9 +485,9 @@ void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate
 	*lane_count = intel_dp_link_config_lane_count(lc);
 }
 
-int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count)
+int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps,
+			       int link_rate, int lane_count)
 {
-	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	int link_rate_idx = intel_dp_rate_index(link_caps->rates, link_caps->num_rates,
 						link_rate);
 	int lane_count_exp = ilog2(lane_count);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index fed8b0ca72ff2..992917505b0d1 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -22,8 +22,10 @@ int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_cap
 void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 					  struct intel_dp_link_config *forced_params);
 
-int intel_dp_link_config_index(struct intel_dp *intel_dp, int link_rate, int lane_count);
-void intel_dp_link_config_get(struct intel_dp *intel_dp, int idx, int *link_rate, int *lane_count);
+int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps,
+			       int link_rate, int lane_count);
+void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps,
+			      int idx, int *link_rate, int *lane_count);
 
 void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
 				       struct intel_dp_link_config *max_link_limits);
@@ -31,7 +33,7 @@ bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
 				       const struct intel_dp_link_config *max_link_limits);
 void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps);
 
-bool intel_dp_link_caps_update(struct intel_dp *intel_dp,
+bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 			       const int *rates, int num_rates, int max_lane_count);
 void intel_dp_link_caps_reset(struct intel_dp_link_caps *link_caps);
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 5e60621f4442e..9da8892a80df0 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1772,9 +1772,10 @@ static bool reduce_link_params_in_bw_order(struct intel_dp *intel_dp,
 	forced_rate = forced_params.rate;
 	forced_lane_count = forced_params.lane_count;
 
-	i = intel_dp_link_config_index(intel_dp, crtc_state->port_clock, crtc_state->lane_count);
+	i = intel_dp_link_config_index(intel_dp->link.caps,
+				       crtc_state->port_clock, crtc_state->lane_count);
 	for (i--; i >= 0; i--) {
-		intel_dp_link_config_get(intel_dp, i, &link_rate, &lane_count);
+		intel_dp_link_config_get(intel_dp->link.caps, i, &link_rate, &lane_count);
 
 		if ((forced_rate &&
 		     forced_rate != link_rate) ||
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 057/108] drm/i915/dp_link_caps: Pass link_caps to common rate helpers
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (55 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 056/108] drm/i915/dp_link_caps: Pass link_caps to config update/lookup helpers Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 058/108] drm/i915/dp_link_caps: Add link_caps prefix " Imre Deak
                   ` (53 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Pass the link_caps pointer to the common rate helpers in
intel_dp_link_caps.c, as it holds the state with the relevant
information.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       |  9 ++++--
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 29 ++++++++-----------
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  4 +--
 .../drm/i915/display/intel_dp_link_training.c |  5 ++--
 .../gpu/drm/i915/display/intel_dp_tunnel.c    |  2 +-
 5 files changed, 24 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index a3f293af5dbfb..57f5c73f4c249 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -1565,6 +1565,7 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 static int
 intel_dp_min_link_rate(struct intel_dp *intel_dp)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_dp_link_config forced_params;
 
 	intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params);
@@ -1572,7 +1573,7 @@ intel_dp_min_link_rate(struct intel_dp *intel_dp)
 	if (forced_params.rate)
 		return forced_params.rate;
 
-	return intel_dp_common_rate(intel_dp, 0);
+	return intel_dp_common_rate(link_caps, 0);
 }
 
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
@@ -1756,6 +1757,7 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
 				  const struct drm_connector_state *conn_state,
 				  const struct link_config_limits *limits)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	int bpp, i, lane_count, clock = intel_dp_mode_clock(pipe_config, conn_state);
 	int link_rate, link_avail;
 
@@ -1766,7 +1768,7 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
 			intel_dp_output_format_link_bpp_x16(pipe_config->output_format, bpp);
 
 		for (i = 0; i < intel_dp_link_caps_num_common_rates(intel_dp->link.caps); i++) {
-			link_rate = intel_dp_common_rate(intel_dp, i);
+			link_rate = intel_dp_common_rate(link_caps, i);
 			if (link_rate < limits->min_rate ||
 			    link_rate > limits->max_rate)
 				continue;
@@ -1990,12 +1992,13 @@ static int dsc_compute_link_config(struct intel_dp *intel_dp,
 				   const struct link_config_limits *limits,
 				   int dsc_bpp_x16)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
 	int link_rate, lane_count;
 	int i;
 
 	for (i = 0; i < intel_dp_link_caps_num_common_rates(intel_dp->link.caps); i++) {
-		link_rate = intel_dp_common_rate(intel_dp, i);
+		link_rate = intel_dp_common_rate(link_caps, i);
 		if (link_rate < limits->min_rate || link_rate > limits->max_rate)
 			continue;
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index fc569092a4dd6..4250cdc7af702 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -78,18 +78,16 @@ struct intel_dp_link_caps {
 };
 
 /* Get length of common rates array potentially limited by max_rate. */
-static int intel_dp_common_len_rate_limit(const struct intel_dp *intel_dp,
+static int intel_dp_common_len_rate_limit(struct intel_dp_link_caps *link_caps,
 					  int max_rate)
 {
-	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
-
 	return intel_dp_rate_limit_len(link_caps->rates,
 				       link_caps->num_rates, max_rate);
 }
 
-int intel_dp_common_rate(struct intel_dp *intel_dp, int index)
+int intel_dp_common_rate(struct intel_dp_link_caps *link_caps, int index)
 {
-	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp *intel_dp = link_caps->dp;
 	struct intel_display *display = to_intel_display(intel_dp);
 
 	if (drm_WARN_ON(display->drm,
@@ -123,11 +121,9 @@ int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int
 }
 
 /* Theoretical max between source and sink */
-int intel_dp_max_common_rate(struct intel_dp *intel_dp)
+int intel_dp_max_common_rate(struct intel_dp_link_caps *link_caps)
 {
-	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
-
-	return intel_dp_common_rate(intel_dp, link_caps->num_rates - 1);
+	return intel_dp_common_rate(link_caps, link_caps->num_rates - 1);
 }
 
 int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps)
@@ -172,17 +168,16 @@ static int forced_lane_count(struct intel_dp_link_caps *link_caps)
 
 static int forced_link_rate(struct intel_dp_link_caps *link_caps)
 {
-	struct intel_dp *intel_dp = link_caps->dp;
 	int len;
 
 	if (!link_caps->forced_params.rate)
 		return 0;
 
-	len = intel_dp_common_len_rate_limit(intel_dp, link_caps->forced_params.rate);
+	len = intel_dp_common_len_rate_limit(link_caps, link_caps->forced_params.rate);
 	if (len == 0)
-		return intel_dp_common_rate(intel_dp, 0);
+		return intel_dp_common_rate(link_caps, 0);
 
-	return intel_dp_common_rate(intel_dp, len - 1);
+	return intel_dp_common_rate(link_caps, len - 1);
 }
 
 void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
@@ -195,7 +190,7 @@ void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 static int intel_dp_link_config_rate(struct intel_dp_link_caps *link_caps,
 				     const struct intel_dp_link_config_entry *lc)
 {
-	return intel_dp_common_rate(link_caps->dp, lc->link_rate_idx);
+	return intel_dp_common_rate(link_caps, lc->link_rate_idx);
 }
 
 static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_entry *lc)
@@ -258,7 +253,7 @@ static void set_max_link_limits_no_update(struct intel_dp_link_caps *link_caps,
 static void reset_max_link_limits_no_update(struct intel_dp_link_caps *link_caps)
 {
 	struct intel_dp_link_config max_link_limits = {
-		.rate = intel_dp_max_common_rate(link_caps->dp),
+		.rate = intel_dp_max_common_rate(link_caps),
 		.lane_count = intel_dp_link_caps_max_common_lane_count(link_caps),
 	};
 
@@ -454,9 +449,9 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 		link_params_changed = true;
 
 	/* TODO: Update these as part of the rest of max param updates. */
-	len = intel_dp_common_len_rate_limit(intel_dp, link_caps->max_limits.rate);
+	len = intel_dp_common_len_rate_limit(link_caps, link_caps->max_limits.rate);
 	if (len > 0)
-		link_caps->max_limits.rate = intel_dp_common_rate(intel_dp, len - 1);
+		link_caps->max_limits.rate = intel_dp_common_rate(link_caps, len - 1);
 
 	if (link_caps->max_limits.rate != old_max_limits.rate)
 		link_params_changed = true;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 992917505b0d1..db17f7ba19954 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -11,9 +11,9 @@ struct intel_dp;
 struct intel_dp_link_caps;
 struct intel_dp_link_config;
 
-int intel_dp_common_rate(struct intel_dp *intel_dp, int index);
+int intel_dp_common_rate(struct intel_dp_link_caps *link_caps, int index);
 int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate);
-int intel_dp_max_common_rate(struct intel_dp *intel_dp);
+int intel_dp_max_common_rate(struct intel_dp_link_caps *link_caps);
 int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps);
 void intel_dp_link_caps_all_common_rates(struct intel_dp_link_caps *link_caps,
 					 const int **rates, int *num_rates);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 9da8892a80df0..a89f9161b8329 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1812,7 +1812,7 @@ static int reduce_link_rate(struct intel_dp *intel_dp, int current_rate)
 	if (rate_index <= 0)
 		return -1;
 
-	new_rate = intel_dp_common_rate(intel_dp, rate_index - 1);
+	new_rate = intel_dp_common_rate(link_caps, rate_index - 1);
 
 	/* TODO: Make switching from UHBR to non-UHBR rates work. */
 	if (drm_dp_is_uhbr_rate(current_rate) != drm_dp_is_uhbr_rate(new_rate))
@@ -1839,6 +1839,7 @@ static bool reduce_link_params_in_rate_lane_order(struct intel_dp *intel_dp,
 						  const struct intel_crtc_state *crtc_state,
 						  int *new_link_rate, int *new_lane_count)
 {
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	int link_rate;
 	int lane_count;
 
@@ -1846,7 +1847,7 @@ static bool reduce_link_params_in_rate_lane_order(struct intel_dp *intel_dp,
 	link_rate = reduce_link_rate(intel_dp, crtc_state->port_clock);
 	if (link_rate < 0) {
 		lane_count = reduce_lane_count(intel_dp, crtc_state->lane_count);
-		link_rate = intel_dp_max_common_rate(intel_dp);
+		link_rate = intel_dp_max_common_rate(link_caps);
 	}
 
 	if (lane_count < 0)
diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
index 0f1a6f9d47ec5..bccd3bfe32a2c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
@@ -58,7 +58,7 @@ static int kbytes_to_mbits(int kbytes)
 static int get_current_link_bw(struct intel_dp *intel_dp)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
-	int rate = intel_dp_max_common_rate(intel_dp);
+	int rate = intel_dp_max_common_rate(link_caps);
 	int lane_count = intel_dp_link_caps_max_common_lane_count(link_caps);
 
 	return intel_dp_max_link_data_rate(intel_dp, rate, lane_count);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 058/108] drm/i915/dp_link_caps: Add link_caps prefix to common rate helpers
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (56 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 057/108] drm/i915/dp_link_caps: Pass link_caps to common rate helpers Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 059/108] drm/i915/dp_link_caps: Add missing documentation to exported functions Imre Deak
                   ` (52 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Rename the common rate helpers in intel_dp_link_caps.c to use the
intel_dp_link_caps_ prefix, matching the other exported functions in
the file.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       |  6 ++---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 24 +++++++++----------
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  4 ++--
 .../drm/i915/display/intel_dp_link_training.c |  4 ++--
 .../gpu/drm/i915/display/intel_dp_tunnel.c    |  2 +-
 5 files changed, 20 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 57f5c73f4c249..88154352e1faa 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -1573,7 +1573,7 @@ intel_dp_min_link_rate(struct intel_dp *intel_dp)
 	if (forced_params.rate)
 		return forced_params.rate;
 
-	return intel_dp_common_rate(link_caps, 0);
+	return intel_dp_link_caps_common_rate(link_caps, 0);
 }
 
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
@@ -1768,7 +1768,7 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
 			intel_dp_output_format_link_bpp_x16(pipe_config->output_format, bpp);
 
 		for (i = 0; i < intel_dp_link_caps_num_common_rates(intel_dp->link.caps); i++) {
-			link_rate = intel_dp_common_rate(link_caps, i);
+			link_rate = intel_dp_link_caps_common_rate(link_caps, i);
 			if (link_rate < limits->min_rate ||
 			    link_rate > limits->max_rate)
 				continue;
@@ -1998,7 +1998,7 @@ static int dsc_compute_link_config(struct intel_dp *intel_dp,
 	int i;
 
 	for (i = 0; i < intel_dp_link_caps_num_common_rates(intel_dp->link.caps); i++) {
-		link_rate = intel_dp_common_rate(link_caps, i);
+		link_rate = intel_dp_link_caps_common_rate(link_caps, i);
 		if (link_rate < limits->min_rate || link_rate > limits->max_rate)
 			continue;
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 4250cdc7af702..529cb702c99eb 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -78,14 +78,14 @@ struct intel_dp_link_caps {
 };
 
 /* Get length of common rates array potentially limited by max_rate. */
-static int intel_dp_common_len_rate_limit(struct intel_dp_link_caps *link_caps,
-					  int max_rate)
+static int intel_dp_link_caps_common_len_rate_limit(struct intel_dp_link_caps *link_caps,
+						    int max_rate)
 {
 	return intel_dp_rate_limit_len(link_caps->rates,
 				       link_caps->num_rates, max_rate);
 }
 
-int intel_dp_common_rate(struct intel_dp_link_caps *link_caps, int index)
+int intel_dp_link_caps_common_rate(struct intel_dp_link_caps *link_caps, int index)
 {
 	struct intel_dp *intel_dp = link_caps->dp;
 	struct intel_display *display = to_intel_display(intel_dp);
@@ -121,9 +121,9 @@ int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int
 }
 
 /* Theoretical max between source and sink */
-int intel_dp_max_common_rate(struct intel_dp_link_caps *link_caps)
+int intel_dp_link_caps_max_common_rate(struct intel_dp_link_caps *link_caps)
 {
-	return intel_dp_common_rate(link_caps, link_caps->num_rates - 1);
+	return intel_dp_link_caps_common_rate(link_caps, link_caps->num_rates - 1);
 }
 
 int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps)
@@ -173,11 +173,11 @@ static int forced_link_rate(struct intel_dp_link_caps *link_caps)
 	if (!link_caps->forced_params.rate)
 		return 0;
 
-	len = intel_dp_common_len_rate_limit(link_caps, link_caps->forced_params.rate);
+	len = intel_dp_link_caps_common_len_rate_limit(link_caps, link_caps->forced_params.rate);
 	if (len == 0)
-		return intel_dp_common_rate(link_caps, 0);
+		return intel_dp_link_caps_common_rate(link_caps, 0);
 
-	return intel_dp_common_rate(link_caps, len - 1);
+	return intel_dp_link_caps_common_rate(link_caps, len - 1);
 }
 
 void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
@@ -190,7 +190,7 @@ void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 static int intel_dp_link_config_rate(struct intel_dp_link_caps *link_caps,
 				     const struct intel_dp_link_config_entry *lc)
 {
-	return intel_dp_common_rate(link_caps, lc->link_rate_idx);
+	return intel_dp_link_caps_common_rate(link_caps, lc->link_rate_idx);
 }
 
 static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_entry *lc)
@@ -253,7 +253,7 @@ static void set_max_link_limits_no_update(struct intel_dp_link_caps *link_caps,
 static void reset_max_link_limits_no_update(struct intel_dp_link_caps *link_caps)
 {
 	struct intel_dp_link_config max_link_limits = {
-		.rate = intel_dp_max_common_rate(link_caps),
+		.rate = intel_dp_link_caps_max_common_rate(link_caps),
 		.lane_count = intel_dp_link_caps_max_common_lane_count(link_caps),
 	};
 
@@ -449,9 +449,9 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 		link_params_changed = true;
 
 	/* TODO: Update these as part of the rest of max param updates. */
-	len = intel_dp_common_len_rate_limit(link_caps, link_caps->max_limits.rate);
+	len = intel_dp_link_caps_common_len_rate_limit(link_caps, link_caps->max_limits.rate);
 	if (len > 0)
-		link_caps->max_limits.rate = intel_dp_common_rate(link_caps, len - 1);
+		link_caps->max_limits.rate = intel_dp_link_caps_common_rate(link_caps, len - 1);
 
 	if (link_caps->max_limits.rate != old_max_limits.rate)
 		link_params_changed = true;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index db17f7ba19954..2afc47c6b7e68 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -11,9 +11,9 @@ struct intel_dp;
 struct intel_dp_link_caps;
 struct intel_dp_link_config;
 
-int intel_dp_common_rate(struct intel_dp_link_caps *link_caps, int index);
+int intel_dp_link_caps_common_rate(struct intel_dp_link_caps *link_caps, int index);
 int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate);
-int intel_dp_max_common_rate(struct intel_dp_link_caps *link_caps);
+int intel_dp_link_caps_max_common_rate(struct intel_dp_link_caps *link_caps);
 int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps);
 void intel_dp_link_caps_all_common_rates(struct intel_dp_link_caps *link_caps,
 					 const int **rates, int *num_rates);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index a89f9161b8329..b7645bcbe0c2b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1812,7 +1812,7 @@ static int reduce_link_rate(struct intel_dp *intel_dp, int current_rate)
 	if (rate_index <= 0)
 		return -1;
 
-	new_rate = intel_dp_common_rate(link_caps, rate_index - 1);
+	new_rate = intel_dp_link_caps_common_rate(link_caps, rate_index - 1);
 
 	/* TODO: Make switching from UHBR to non-UHBR rates work. */
 	if (drm_dp_is_uhbr_rate(current_rate) != drm_dp_is_uhbr_rate(new_rate))
@@ -1847,7 +1847,7 @@ static bool reduce_link_params_in_rate_lane_order(struct intel_dp *intel_dp,
 	link_rate = reduce_link_rate(intel_dp, crtc_state->port_clock);
 	if (link_rate < 0) {
 		lane_count = reduce_lane_count(intel_dp, crtc_state->lane_count);
-		link_rate = intel_dp_max_common_rate(link_caps);
+		link_rate = intel_dp_link_caps_max_common_rate(link_caps);
 	}
 
 	if (lane_count < 0)
diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
index bccd3bfe32a2c..52f5c88f7e09c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
@@ -58,7 +58,7 @@ static int kbytes_to_mbits(int kbytes)
 static int get_current_link_bw(struct intel_dp *intel_dp)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
-	int rate = intel_dp_max_common_rate(link_caps);
+	int rate = intel_dp_link_caps_max_common_rate(link_caps);
 	int lane_count = intel_dp_link_caps_max_common_lane_count(link_caps);
 
 	return intel_dp_max_link_data_rate(intel_dp, rate, lane_count);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 059/108] drm/i915/dp_link_caps: Add missing documentation to exported functions
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (57 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 058/108] drm/i915/dp_link_caps: Add link_caps prefix " Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 060/108] drm/i915/dp_link_caps: Set forced link params before resetting link params Imre Deak
                   ` (51 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add missing documentation to common rate helpers and the config updater.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 50 ++++++++++++++++++-
 1 file changed, 48 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 529cb702c99eb..5d6d5441b54a4 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -85,6 +85,18 @@ static int intel_dp_link_caps_common_len_rate_limit(struct intel_dp_link_caps *l
 				       link_caps->num_rates, max_rate);
 }
 
+/**
+ * intel_dp_link_caps_common_rate - get common link rate at a given index
+ * @link_caps: link capabilities state
+ * @index: index into the common rate list
+ *
+ * Return the link rate identified by @idx currently supported by @link_caps,
+ * common to both the source and the sink.
+ *
+ * Return:
+ * - Common link rate at @idx.
+ * - 162000 if @idx is out of range.
+ */
 int intel_dp_link_caps_common_rate(struct intel_dp_link_caps *link_caps, int index)
 {
 	struct intel_dp *intel_dp = link_caps->dp;
@@ -120,7 +132,14 @@ int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int
 				   rate);
 }
 
-/* Theoretical max between source and sink */
+/**
+ * intel_dp_link_caps_max_common_rate - get the maximum common link rate
+ * @link_caps: link capabilities state
+ *
+ * Return:
+ * Maximum link rate currently supported by @link_caps, common to both the
+ * source and the sink.
+ */
 int intel_dp_link_caps_max_common_rate(struct intel_dp_link_caps *link_caps)
 {
 	return intel_dp_link_caps_common_rate(link_caps, link_caps->num_rates - 1);
@@ -389,7 +408,34 @@ static bool current_common_caps_match(struct intel_dp_link_caps *link_caps,
 	return true;
 }
 
-/* Return %true if the supported link parameters have changed. */
+/**
+ * intel_dp_link_caps_update - rebuild the supported link configuration state
+ * @link_caps: link capabilities state
+ * @rates: supported common link rates
+ * @num_rates: number of entries in @rates
+ * @max_lane_count: supported maximum lane count
+ *
+ * Rebuild the supported link configuration state from @rates and
+ * @max_lane_count.
+ *
+ * Configuration indices are not stable across calls to this function, so
+ * callers should not cache such indices and masks built from them across
+ * updates via this function.
+ *
+ * This function is called regularly, at least after a sink is connected,
+ * but it may also be called later whenever the sink capabilities may have
+ * changed, for example in response to HPD IRQ / RX_CAP_CHANGED signaling.
+ *
+ * In the Intel driver this function is currently called whenever the
+ * connector detect handler runs, after reading the sink capabilities. This
+ * may change if those capabilities are cached until the sink is
+ * disconnected, or until RX_CAP_CHANGED is signaled. In any case, this
+ * function should be called whenever the sink capabilities were read out
+ * and may have changed.
+ *
+ * Returns:
+ * - %true if the supported link parameters have changed, %false otherwise.
+ */
 bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 			       const int *rates, int num_rates, int max_lane_count)
 {
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 060/108] drm/i915/dp_link_caps: Set forced link params before resetting link params
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (58 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 059/108] drm/i915/dp_link_caps: Add missing documentation to exported functions Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 061/108] drm/i915/dp_link_caps: Adjust max_limits during link config update Imre Deak
                   ` (50 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Set the debugfs forced link parameters before calling
intel_dp_reset_link_params(), so the reset can take them into account.

A follow-up change will update the maximum link parameters as part of
the reset, where the forced parameters also influence the result.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp_link_caps.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 5d6d5441b54a4..4905d68b13269 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -658,8 +658,8 @@ static ssize_t i915_dp_force_link_rate_write(struct file *file,
 
 	intel_dp_flush_connector_commits(connector);
 
-	intel_dp_reset_link_params(intel_dp);
 	link_caps->forced_params.rate = rate;
+	intel_dp_reset_link_params(intel_dp);
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
@@ -766,8 +766,8 @@ static ssize_t i915_dp_force_lane_count_write(struct file *file,
 
 	intel_dp_flush_connector_commits(connector);
 
-	intel_dp_reset_link_params(intel_dp);
 	link_caps->forced_params.lane_count = lane_count;
+	intel_dp_reset_link_params(intel_dp);
 
 	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 061/108] drm/i915/dp_link_caps: Adjust max_limits during link config update
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (59 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 060/108] drm/i915/dp_link_caps: Set forced link params before resetting link params Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 062/108] drm/i915/dp_link_caps: Adjust max_limits when setting or resetting it Imre Deak
                   ` (49 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Adjust the cached max_limits to match the currently allowed
configurations when updating link parameters to new sink capabilities.

The adjustment takes disabled configurations, active forced parameters
and the currently set max limits into account. Disabled configurations
are not supported yet, so that part has no effect for now.

As a safeguard, this restores a state with at least one link
configuration enabled if needed.

Various sites query max_limits, including modeset state computation,
connector probing, MST link probing, TBT bandwidth calculation, and link
status checks. This change provides a way for all queries to see the
effective max_limits consistently - taken this into use at those places
in follow-up changes. For unserialized contexts (link status check),
this is enabled by caching the precomputed value.

A follow-up change will perform the same adjustment during setting and
resetting max_limits.

Also export the allowed config mask helper used here for validation,
used by follow-up changes to iterate allowed configurations.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 132 ++++++++++++++++--
 .../gpu/drm/i915/display/intel_dp_link_caps.h |   1 +
 2 files changed, 125 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 4905d68b13269..112d343c6d9d6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -263,6 +263,31 @@ static u32 calc_allowed_config_mask(struct intel_dp_link_caps *link_caps,
 	return allowed_mask;
 }
 
+/**
+ * intel_dp_link_caps_get_allowed_config_mask - get the currently allowed config mask
+ * @link_caps: link capabilities state
+ *
+ * Return:
+ * Mask of link configuration indices allowed after applying the current
+ * maximum link limits, and further narrowing them by any forced link
+ * parameters. The caller may further filter the returned mask before passing
+ * it to the for_each_dp_link_config() iterators.
+ *
+ * See also:
+ * - intel_dp_link_caps_set_max_limits()
+ * - intel_dp_link_caps_get_forced_params()
+ */
+u32 intel_dp_link_caps_get_allowed_config_mask(struct intel_dp_link_caps *link_caps)
+{
+	struct intel_dp_link_config forced_params;
+	u32 disabled_mask = 0;	/* get the mask from link_caps. */
+
+	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
+
+	return calc_allowed_config_mask(link_caps, disabled_mask,
+					&link_caps->max_limits, &forced_params);
+}
+
 static void set_max_link_limits_no_update(struct intel_dp_link_caps *link_caps,
 					  const struct intel_dp_link_config *max_link_limits)
 {
@@ -279,6 +304,99 @@ static void reset_max_link_limits_no_update(struct intel_dp_link_caps *link_caps
 	set_max_link_limits_no_update(link_caps, &max_link_limits);
 }
 
+static void reset_all_restrictions_no_update(struct intel_dp_link_caps *link_caps)
+{
+	reset_max_link_limits_no_update(link_caps);
+	link_caps->forced_params = INTEL_DP_LINK_CONFIG_NULL;
+}
+
+/*
+ * Compute the maximum link limits from the allowed configurations.
+ *
+ * The result reflects the maximum rate and lane count among the
+ * configurations currently allowed by link_caps, i.e. constrained by
+ * the currently stored max_limits, forced parameters. Since the
+ * allowed set depends on max_limits, the result can only be less
+ * than or equal to the current max_limits.
+ */
+static void compute_max_link_limits(struct intel_dp_link_caps *link_caps,
+				    struct intel_dp_link_config *max_link_limits)
+{
+	u32 allowed_mask = intel_dp_link_caps_get_allowed_config_mask(link_caps);
+	struct intel_dp_link_config max_config = {};
+	struct intel_dp_link_config link_config;
+	int config_idx;
+
+	for (config_idx = 0; config_idx < link_caps->num_configs; config_idx++) {
+		const struct intel_dp_link_config_entry *lc = &link_caps->configs[config_idx];
+
+		if (!(BIT(config_idx) & allowed_mask))
+			continue;
+
+		to_intel_dp_link_config(link_caps, lc, &link_config);
+
+		max_config.rate = max(max_config.rate,
+				      link_config.rate);
+		max_config.lane_count = max(max_config.lane_count,
+					    link_config.lane_count);
+	}
+
+	*max_link_limits = max_config;
+}
+
+/**
+ * update_max_link_limits - update max_limits to match the allowed configs
+ * @link_caps: link capabilities state
+ *
+ * Adjust the stored max_limits to the actual parameter bounds of the
+ * currently allowed configurations.
+ *
+ * The allowed configurations are already constrained by the stored
+ * max_limits and forced parameters. The recomputed max_limits is
+ * derived from that same set, so it can only be less than or equal to
+ * the stored max_limits.
+ *
+ * A %false return indicates an internal error (either the stored
+ * max_limits was below all allowed configurations, or
+ * compute_max_link_limits() returned a larger value). The caller must
+ * recover by removing all restrictions.
+ *
+ * Return:
+ * - %true  if max_limits was updated successfully.
+ * - %false if an internal error was detected.
+ */
+static bool update_max_link_limits(struct intel_dp_link_caps *link_caps)
+{
+	struct intel_display *display = to_intel_display(link_caps->dp);
+	struct intel_dp_link_config new_limits;
+
+	compute_max_link_limits(link_caps, &new_limits);
+
+	if (drm_WARN_ON(display->drm,
+			new_limits.rate == 0 ||
+			new_limits.lane_count == 0 ||
+			new_limits.rate > link_caps->max_limits.rate ||
+			new_limits.lane_count > link_caps->max_limits.lane_count))
+		return false;
+
+	link_caps->max_limits = new_limits;
+
+	return true;
+}
+
+static bool update_max_link_info(struct intel_dp_link_caps *link_caps)
+{
+	struct intel_display *display = to_intel_display(link_caps->dp);
+	bool limit_update_ok;
+
+	limit_update_ok = update_max_link_limits(link_caps);
+
+	if (drm_WARN_ON(display->drm, !limit_update_ok))
+		reset_all_restrictions_no_update(link_caps);
+
+	return limit_update_ok;
+}
+
 /**
  * intel_dp_link_caps_get_max_limits - get the current maximum link limits
  * @link_caps: link capabilities state
@@ -449,7 +567,6 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 	int num_common_lane_configs;
 	int old_max_lane_count;
 	int num_old_rates;
-	int len;
 	int i;
 	int j;
 
@@ -494,17 +611,16 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 				       old_max_lane_count))
 		link_params_changed = true;
 
-	/* TODO: Update these as part of the rest of max param updates. */
-	len = intel_dp_link_caps_common_len_rate_limit(link_caps, link_caps->max_limits.rate);
-	if (len > 0)
-		link_caps->max_limits.rate = intel_dp_link_caps_common_rate(link_caps, len - 1);
+	/*
+	 * A failure could be only due to a bug, the update function handles
+	 * that case by removing all restriction and resetting the max limit
+	 * to the sink's maximum bounds.
+	 */
+	update_max_link_info(link_caps);
 
 	if (link_caps->max_limits.rate != old_max_limits.rate)
 		link_params_changed = true;
 
-	link_caps->max_limits.lane_count = min(link_caps->max_limits.lane_count,
-					       max_lane_count);
-
 	if (link_caps->max_limits.lane_count != old_max_limits.lane_count)
 		link_params_changed = true;
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 2afc47c6b7e68..110c1d1e604dd 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -21,6 +21,7 @@ int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_cap
 
 void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 					  struct intel_dp_link_config *forced_params);
+u32 intel_dp_link_caps_get_allowed_config_mask(struct intel_dp_link_caps *link_caps);
 
 int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps,
 			       int link_rate, int lane_count);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 062/108] drm/i915/dp_link_caps: Adjust max_limits when setting or resetting it
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (60 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 061/108] drm/i915/dp_link_caps: Adjust max_limits during link config update Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 063/108] drm/i915/dp: Simplify the modeset max link rate limit computation Imre Deak
                   ` (48 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Adjust max_limits when setting or resetting it, accounting for all other
constraints that limit the allowed configurations, similar to how it is
adjusted during a link configuration update. On detecting
inconsistencies, all restrictions are removed, ensuring at least one
allowed link configuration.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 20 +++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 112d343c6d9d6..7c6259c95d388 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -444,7 +444,9 @@ static bool max_link_limits_valid(struct intel_dp_link_caps *link_caps,
  * @max_link_limits: new maximum link limits
  *
  * Set the current maximum rate and lane count limits to @max_link_limits,
- * constraining the set of allowed configurations.
+ * after adjusting @max_link_limits to the currently allowed configuration
+ * set. Since the old @max_link_limits also constrains this allowed set, the
+ * new adjusted value of @max_link_limits will be at or below the old one.
  *
  * The new limits must leave at least one configuration allowed: the limits
  * must not be below the currently active forced parameters or below all the
@@ -456,8 +458,10 @@ static bool max_link_limits_valid(struct intel_dp_link_caps *link_caps,
  *
  * Return:
  * - %true  if the @link_caps cached max limits value got updated with
- *          @max_link_limits.
- * - %false if @max_link_limits is invalid.
+ *          @max_link_limits along with all the max link information.
+ * - %false if @max_link_limits is invalid, or if max link info update
+ *          fails due to an internal consistency issue. In the latter
+ *          case return after resetting all limits and restrictions.
  */
 bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
 				       const struct intel_dp_link_config *max_link_limits)
@@ -467,7 +471,7 @@ bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
 
 	set_max_link_limits_no_update(link_caps, max_link_limits);
 
-	return true;
+	return update_max_link_info(link_caps);
 }
 
 /**
@@ -475,11 +479,14 @@ bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
  * @link_caps: link capabilities state
  *
  * Reset the current maximum link limits to the maximum supported common link
- * rate and lane count.
+ * rate and lane count, then update the derived maximum-link information
+ * accordingly.
  */
 void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps)
 {
 	reset_max_link_limits_no_update(link_caps);
+	/* On failure the following removes all restrictions. */
+	update_max_link_info(link_caps);
 }
 
 static int intel_dp_link_config_bw(struct intel_dp_link_caps *link_caps,
@@ -675,8 +682,9 @@ int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps,
  */
 void intel_dp_link_caps_reset(struct intel_dp_link_caps *link_caps)
 {
-	/* TODO: Update the limits to account for forced params. */
 	reset_max_link_limits_no_update(link_caps);
+	/* On failure the following removes all restrictions. */
+	update_max_link_info(link_caps);
 }
 
 static int i915_dp_force_link_rate_show(struct seq_file *m, void *data)
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 063/108] drm/i915/dp: Simplify the modeset max link rate limit computation
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (61 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 062/108] drm/i915/dp_link_caps: Adjust max_limits when setting or resetting it Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 064/108] drm/i915/dp: Query max limits via link_caps during mode validation Imre Deak
                   ` (47 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

intel_dp_link_caps_get_max_limits() already accounts for forced
parameters, so no separate adjustment is needed during modeset link
configuration.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 14 +-------------
 1 file changed, 1 insertion(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 88154352e1faa..9be3b767fb54c 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -356,16 +356,10 @@ int intel_dp_max_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_dp_link_config max_link_limits;
-	struct intel_dp_link_config forced_params;
 	int lane_count;
 
 	intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits);
-	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
-
-	if (forced_params.lane_count)
-		lane_count = forced_params.lane_count;
-	else
-		lane_count = max_link_limits.lane_count;
+	lane_count = max_link_limits.lane_count;
 
 	switch (lane_count) {
 	case 1:
@@ -1550,12 +1544,6 @@ intel_dp_max_link_rate(struct intel_dp *intel_dp)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_dp_link_config max_link_limits;
-	struct intel_dp_link_config forced_params;
-
-	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
-
-	if (forced_params.rate)
-		return forced_params.rate;
 
 	intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 064/108] drm/i915/dp: Query max limits via link_caps during mode validation
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (62 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 063/108] drm/i915/dp: Simplify the modeset max link rate limit computation Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 065/108] drm/i915/dp_tunnel: Query max link limits via link_caps for BW computation Imre Deak
                   ` (46 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Query the maximum link parameters during mode validation and MST link
probing directly from intel_dp_link_caps_get_max_limits(), instead of
using the intel_dp_max_link_rate() and intel_dp_max_lane_count()
helpers, which internally also call the link_caps query.

This removes an unnecessary indirection, makes the max_limits query
uniform across modeset, mode validation, TBT BW calculation and link
state checking, and allows unexporting the
intel_dp_max_link_rate()/intel_dp_max_lane_count() helpers.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c     | 14 ++++++++++----
 drivers/gpu/drm/i915/display/intel_dp.h     |  2 --
 drivers/gpu/drm/i915/display/intel_dp_mst.c | 20 ++++++++++++++++----
 3 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 9be3b767fb54c..875e835848c39 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -352,7 +352,7 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
 	return min3(source_max, sink_max, lane_max);
 }
 
-int intel_dp_max_lane_count(struct intel_dp *intel_dp)
+static int intel_dp_max_lane_count(struct intel_dp *intel_dp)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_dp_link_config max_link_limits;
@@ -1322,6 +1322,7 @@ intel_dp_mode_valid_format(struct intel_connector *connector,
 	struct intel_dp *intel_dp = intel_attached_dp(connector);
 	enum intel_output_format output_format;
 	int max_rate, mode_rate, max_lanes, max_link_clock;
+	struct intel_dp_link_config max_link_limits;
 	u16 dsc_max_compressed_bpp = 0;
 	enum drm_mode_status status;
 	bool dsc = false;
@@ -1334,8 +1335,13 @@ intel_dp_mode_valid_format(struct intel_connector *connector,
 
 	output_format = intel_dp_output_format(connector, sink_format);
 
-	max_link_clock = intel_dp_max_link_rate(intel_dp);
-	max_lanes = intel_dp_max_lane_count(intel_dp);
+	/*
+	 * TODO: Compute BW from the maximum-BW configuration; max limits are
+	 * independent bounds over all configs and may not form a valid config.
+	 */
+	intel_dp_link_caps_get_max_limits(intel_dp->link.caps, &max_link_limits);
+	max_link_clock = max_link_limits.rate;
+	max_lanes = max_link_limits.lane_count;
 
 	max_rate = intel_dp_max_link_data_rate(intel_dp, max_link_clock, max_lanes);
 
@@ -1539,7 +1545,7 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp)
 	drm_dbg_kms(display->drm, "common rates: %s\n", seq_buf_str(&s));
 }
 
-int
+static int
 intel_dp_max_link_rate(struct intel_dp *intel_dp)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 6abce846b8e7e..6d6bb9e23ff26 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -99,8 +99,6 @@ void intel_dp_mst_suspend(struct intel_display *display);
 void intel_dp_mst_resume(struct intel_display *display);
 int intel_dp_rate_limit_len(const int *rates, int len, int max_rate);
 int intel_dp_max_source_lane_count(struct intel_digital_port *dig_port);
-int intel_dp_max_link_rate(struct intel_dp *intel_dp);
-int intel_dp_max_lane_count(struct intel_dp *intel_dp);
 int intel_dp_config_required_rate(const struct intel_crtc_state *crtc_state);
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate);
 int intel_dp_rate_index(const int *rates, int len, int rate);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 832a43ebe00f7..4736bfeb25e06 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -47,6 +47,7 @@
 #include "intel_display_wa.h"
 #include "intel_dp.h"
 #include "intel_dp_hdcp.h"
+#include "intel_dp_link_caps.h"
 #include "intel_dp_link_training.h"
 #include "intel_dp_mst.h"
 #include "intel_dp_test.h"
@@ -1473,6 +1474,7 @@ mst_connector_mode_valid_ctx(struct drm_connector *_connector,
 	unsigned long bw_overhead_flags =
 		DRM_DP_BW_OVERHEAD_MST | DRM_DP_BW_OVERHEAD_SSC_REF_CLK;
 	int min_link_bpp_x16 = fxp_q4_from_int(18);
+	struct intel_dp_link_config max_link_limits;
 	static bool supports_dsc;
 	int ret;
 	bool dsc = false;
@@ -1505,8 +1507,13 @@ mst_connector_mode_valid_ctx(struct drm_connector *_connector,
 		min_link_bpp_x16 = intel_dp_compute_min_compressed_bpp_x16(connector,
 									   INTEL_OUTPUT_FORMAT_RGB);
 
-	max_link_clock = intel_dp_max_link_rate(intel_dp);
-	max_lanes = intel_dp_max_lane_count(intel_dp);
+	/*
+	 * TODO: Compute BW from the maximum-BW configuration; max limits are
+	 * independent bounds over all configs and may not form a valid config.
+	 */
+	intel_dp_link_caps_get_max_limits(intel_dp->link.caps, &max_link_limits);
+	max_link_clock = max_link_limits.rate;
+	max_lanes = max_link_limits.lane_count;
 
 	max_rate = intel_dp_max_link_data_rate(intel_dp,
 					       max_link_clock, max_lanes);
@@ -2132,14 +2139,19 @@ bool intel_dp_mst_crtc_needs_modeset(struct intel_atomic_state *state,
  */
 void intel_dp_mst_prepare_probe(struct intel_dp *intel_dp)
 {
-	int link_rate = intel_dp_max_link_rate(intel_dp);
-	int lane_count = intel_dp_max_lane_count(intel_dp);
+	struct intel_dp_link_config max_link_limits;
+	int link_rate;
+	int lane_count;
 	u8 rate_select;
 	u8 link_bw;
 
 	if (intel_dp->link.active)
 		return;
 
+	intel_dp_link_caps_get_max_limits(intel_dp->link.caps, &max_link_limits);
+	link_rate = max_link_limits.rate;
+	lane_count = max_link_limits.lane_count;
+
 	if (intel_mst_probed_link_params_valid(intel_dp, link_rate, lane_count))
 		return;
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 065/108] drm/i915/dp_tunnel: Query max link limits via link_caps for BW computation
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (63 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 064/108] drm/i915/dp: Query max limits via link_caps during mode validation Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 066/108] drm/i915/doc: Document DP link capabilities Imre Deak
                   ` (45 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Query the maximum link limits via the link caps interface to compute the
available TBT bandwidth. Unlike the max common link params used so far
for this, the max link limits also accounts for any forced link
parameters.

This makes the max_limits query uniform across modeset, mode validation,
link state checking, and TBT bandwidth computation. It also allows
intel_dp_link_caps_max_common_lane_count() to be unexported.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp_link_caps.c |  2 +-
 drivers/gpu/drm/i915/display/intel_dp_link_caps.h |  1 -
 drivers/gpu/drm/i915/display/intel_dp_tunnel.c    | 12 +++++++++---
 3 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 7c6259c95d388..e8d1fd86b327f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -171,7 +171,7 @@ void intel_dp_link_caps_all_common_rates(struct intel_dp_link_caps *link_caps,
 	*num_rates = link_caps->num_rates;
 }
 
-int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_caps)
+static int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_caps)
 {
 	return link_caps->max_lane_count;
 }
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 110c1d1e604dd..7fe0e4a028f26 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -17,7 +17,6 @@ int intel_dp_link_caps_max_common_rate(struct intel_dp_link_caps *link_caps);
 int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps);
 void intel_dp_link_caps_all_common_rates(struct intel_dp_link_caps *link_caps,
 					 const int **rates, int *num_rates);
-int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_caps);
 
 void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 					  struct intel_dp_link_config *forced_params);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
index 52f5c88f7e09c..07817f5251c81 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
@@ -58,10 +58,16 @@ static int kbytes_to_mbits(int kbytes)
 static int get_current_link_bw(struct intel_dp *intel_dp)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
-	int rate = intel_dp_link_caps_max_common_rate(link_caps);
-	int lane_count = intel_dp_link_caps_max_common_lane_count(link_caps);
+	struct intel_dp_link_config max_link_limits;
 
-	return intel_dp_max_link_data_rate(intel_dp, rate, lane_count);
+	/*
+	 * TODO: Compute BW from the maximum-BW configuration; max limits are
+	 * independent bounds over all configs and may not form a valid config.
+	 */
+	intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits);
+
+	return intel_dp_max_link_data_rate(intel_dp, max_link_limits.rate,
+						     max_link_limits.lane_count);
 }
 
 static int __update_tunnel_state(struct intel_dp *intel_dp, bool force_sink_update)
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 066/108] drm/i915/doc: Document DP link capabilities
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (64 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 065/108] drm/i915/dp_tunnel: Query max link limits via link_caps for BW computation Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 067/108] drm/i915/dp_link_caps: Move config table members to a substruct Imre Deak
                   ` (44 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add documentation for the DP link capabilities interface.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 Documentation/gpu/i915.rst                    | 12 ++++
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 60 +++++++++++++++++++
 2 files changed, 72 insertions(+)

diff --git a/Documentation/gpu/i915.rst b/Documentation/gpu/i915.rst
index 34556b2104aa5..38680f277328d 100644
--- a/Documentation/gpu/i915.rst
+++ b/Documentation/gpu/i915.rst
@@ -150,6 +150,18 @@ DisplayPort Link Training
 .. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp_link_training.c
    :internal:
 
+DisplayPort Link Capabilities
+-----------------------------
+
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+   :doc: DisplayPort link capabilities
+
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+   :internal:
+
+.. kernel-doc:: drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+   :internal:
+
 High Definition Audio
 ---------------------
 
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index e8d1fd86b327f..01eba9fb0b887 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -18,6 +18,66 @@
 #include "intel_dp.h"
 #include "intel_dp_link_caps.h"
 
+/**
+ * DOC: DisplayPort link capabilities
+ *
+ * The Intel DP link caps API tracks the supported and allowed DP link
+ * configurations for a DP encoder and its attached connectors, and
+ * provides helpers to iterate, filter, disable, and constrain them.
+ *
+ * Locking:
+ *   All accesses to this API must be serialized. The only exception
+ *   is intel_dp_link_caps_get_max_limits(), which allow lockless
+ *   lookup. Such lookups may observe an out-of-sync &struct
+ *   intel_dp_link_config tuple, i.e. a rate from one state and a lane
+ *   count from another.
+ *
+ *   The Intel i915/xe drivers ensure the above serialization by holding
+ *   &drm_mode_config.connection_mutex and, while holding the lock,
+ *   flushing pending asynchronous atomic commits. This also allows use
+ *   of the API from the tails of asynchronous atomic commits, which
+ *   cannot hold the lock.
+ *
+ * Configuration indexing and iteration position:
+ *   A configuration index or mask always refers to the same
+ *   configuration or set of configurations across all API calls.
+ *
+ *   In contrast, an iteration position depends on the selected
+ *   configuration ordering (key and direction). Any mapping between
+ *   iteration positions and configuration indices is
+ *   ordering-dependent and not part of the API, and must not be relied
+ *   upon.
+ *
+ *   Configuration indices are not stable across
+ *   intel_dp_link_caps_update() calls. API users must not cache
+ *   configuration indices or masks across such updates.
+ *
+ *   The API also supports iterating configurations in ascending and
+ *   descending BW order, and in ascending and descending rate/lane order.
+ *   The for_each_dp_link_config*() helpers iterate configurations in
+ *   these orders.
+ *
+ * Terminology:
+ *   "Common link capabilities" (or "common caps") refer to the link
+ *   rates and maximum lane count supported by both the source and the
+ *   sink, i.e. the intersection of their respective capabilities.
+ *
+ *   "Supported configurations" are all configurations defined by the
+ *   common link capabilities' link rates and maximum lane count.
+ *
+ *   "Disabled configurations" are supported configurations disabled via
+ *   this API.
+ *
+ *   "Enabled configurations" are supported configurations that are not
+ *   disabled.
+ *
+ *   "Forced configurations" are enabled configurations forced via
+ *   debugfs.
+ *
+ *   "Allowed configurations" are the enabled configurations, or if
+ *   forcing is in effect the forced configurations, constrained by a
+ *   maximum rate and lane count set via the API.
+ */
 struct intel_dp_link_caps {
 	struct intel_dp *dp;
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 067/108] drm/i915/dp_link_caps: Move config table members to a substruct
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (65 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 066/108] drm/i915/doc: Document DP link capabilities Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 068/108] drm/i915/dp_link_caps: Factor out a helper to look up a config table rate Imre Deak
                   ` (43 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Group the rate/lane configuration members (rates array, max lane count,
and config entries) into a substruct within intel_dp_link_caps. This
provides a clearer view of the related information and prepares for a
follow-up change that will precompute the table before committing it to
link_caps.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 112 ++++++++++--------
 1 file changed, 63 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 01eba9fb0b887..81c36e3326bb9 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -81,24 +81,26 @@
 struct intel_dp_link_caps {
 	struct intel_dp *dp;
 
-	/* Rate, lane count caps common to source and sink. */
-	int num_rates;
-	int rates[DP_MAX_SUPPORTED_RATES];
-	int max_lane_count;
+	struct intel_dp_link_caps_config_table {
+		/* Rate, lane count caps common to source and sink. */
+		int num_rates;
+		int rates[DP_MAX_SUPPORTED_RATES];
+		int max_lane_count;
 
-	/* common rate,lane_count configs in bw order */
-	int num_configs;
+		/* common rate,lane_count configs in bw order */
+		int num_configs;
 #define INTEL_DP_MAX_LANE_COUNT			4
 #define INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS	(ilog2(INTEL_DP_MAX_LANE_COUNT) + 1)
 #define INTEL_DP_LANE_COUNT_EXP_BITS		order_base_2(INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS)
 #define INTEL_DP_LINK_RATE_IDX_BITS		(BITS_PER_TYPE(u8) - INTEL_DP_LANE_COUNT_EXP_BITS)
 #define INTEL_DP_MAX_LINK_CONFIGS		(DP_MAX_SUPPORTED_RATES * \
 						 INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS)
-	struct intel_dp_link_config_entry {
-		/* index into rates[] */
-		u8 link_rate_idx:INTEL_DP_LINK_RATE_IDX_BITS;
-		u8 lane_count_exp:INTEL_DP_LANE_COUNT_EXP_BITS;
-	} configs[INTEL_DP_MAX_LINK_CONFIGS];
+		struct intel_dp_link_config_entry {
+			/* index into rates[] */
+			u8 link_rate_idx:INTEL_DP_LINK_RATE_IDX_BITS;
+			u8 lane_count_exp:INTEL_DP_LANE_COUNT_EXP_BITS;
+		} configs[INTEL_DP_MAX_LINK_CONFIGS];
+	} config_table;
 
 	/*
 	 * Forced parameters requested via debugfs. Remains set across sink
@@ -141,8 +143,9 @@ struct intel_dp_link_caps {
 static int intel_dp_link_caps_common_len_rate_limit(struct intel_dp_link_caps *link_caps,
 						    int max_rate)
 {
-	return intel_dp_rate_limit_len(link_caps->rates,
-				       link_caps->num_rates, max_rate);
+	const struct intel_dp_link_caps_config_table *table = &link_caps->config_table;
+
+	return intel_dp_rate_limit_len(table->rates, table->num_rates, max_rate);
 }
 
 /**
@@ -163,10 +166,10 @@ int intel_dp_link_caps_common_rate(struct intel_dp_link_caps *link_caps, int ind
 	struct intel_display *display = to_intel_display(intel_dp);
 
 	if (drm_WARN_ON(display->drm,
-			index < 0 || index >= link_caps->num_rates))
+			index < 0 || index >= link_caps->config_table.num_rates))
 		return 162000;
 
-	return link_caps->rates[index];
+	return link_caps->config_table.rates[index];
 }
 
 /**
@@ -187,9 +190,9 @@ int intel_dp_link_caps_common_rate(struct intel_dp_link_caps *link_caps, int ind
  */
 int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate)
 {
-	return intel_dp_rate_index(link_caps->rates,
-				   link_caps->num_rates,
-				   rate);
+	const struct intel_dp_link_caps_config_table *table = &link_caps->config_table;
+
+	return intel_dp_rate_index(table->rates, table->num_rates, rate);
 }
 
 /**
@@ -202,12 +205,14 @@ int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int
  */
 int intel_dp_link_caps_max_common_rate(struct intel_dp_link_caps *link_caps)
 {
-	return intel_dp_link_caps_common_rate(link_caps, link_caps->num_rates - 1);
+	const struct intel_dp_link_caps_config_table *table = &link_caps->config_table;
+
+	return intel_dp_link_caps_common_rate(link_caps, table->num_rates - 1);
 }
 
 int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps)
 {
-	return link_caps->num_rates;
+	return link_caps->config_table.num_rates;
 }
 
 /**
@@ -227,13 +232,15 @@ int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps)
 void intel_dp_link_caps_all_common_rates(struct intel_dp_link_caps *link_caps,
 					 const int **rates, int *num_rates)
 {
-	*rates = link_caps->rates;
-	*num_rates = link_caps->num_rates;
+	const struct intel_dp_link_caps_config_table *table = &link_caps->config_table;
+
+	*rates = table->rates;
+	*num_rates = table->num_rates;
 }
 
 static int intel_dp_link_caps_max_common_lane_count(struct intel_dp_link_caps *link_caps)
 {
-	return link_caps->max_lane_count;
+	return link_caps->config_table.max_lane_count;
 }
 
 static int forced_lane_count(struct intel_dp_link_caps *link_caps)
@@ -291,12 +298,13 @@ static u32 calc_allowed_config_mask(struct intel_dp_link_caps *link_caps,
 				    const struct intel_dp_link_config *max_limits,
 				    const struct intel_dp_link_config *forced_params)
 {
+	struct intel_dp_link_caps_config_table *table = &link_caps->config_table;
 	struct intel_dp_link_config config;
 	u32 allowed_mask = 0;
 	int config_idx;
 
-	for (config_idx = 0; config_idx < link_caps->num_configs; config_idx++) {
-		const struct intel_dp_link_config_entry *lc = &link_caps->configs[config_idx];
+	for (config_idx = 0; config_idx < table->num_configs; config_idx++) {
+		const struct intel_dp_link_config_entry *lc = &table->configs[config_idx];
 
 		if (BIT(config_idx) & disabled_config_mask)
 			continue;
@@ -382,13 +390,14 @@ static void reset_all_restrictions_no_update(struct intel_dp_link_caps *link_cap
 static void compute_max_link_limits(struct intel_dp_link_caps *link_caps,
 				    struct intel_dp_link_config *max_link_limits)
 {
+	struct intel_dp_link_caps_config_table *table = &link_caps->config_table;
 	u32 allowed_mask = intel_dp_link_caps_get_allowed_config_mask(link_caps);
 	struct intel_dp_link_config max_config = {};
 	struct intel_dp_link_config link_config;
 	int config_idx;
 
-	for (config_idx = 0; config_idx < link_caps->num_configs; config_idx++) {
-		const struct intel_dp_link_config_entry *lc = &link_caps->configs[config_idx];
+	for (config_idx = 0; config_idx < table->num_configs; config_idx++) {
+		const struct intel_dp_link_config_entry *lc = &table->configs[config_idx];
 
 		if (!(BIT(config_idx) & allowed_mask))
 			continue;
@@ -573,13 +582,13 @@ static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 	       intel_dp_link_config_rate(link_caps, lc_b);
 }
 
-static bool current_common_caps_match(struct intel_dp_link_caps *link_caps,
+static bool current_common_caps_match(struct intel_dp_link_caps_config_table *table,
 				      const int *rates, int num_rates,
 				      int old_max_lane_count)
 {
-	int current_max_lane_count = link_caps->max_lane_count;
-	const int *current_rates = link_caps->rates;
-	int num_current_rates = link_caps->num_rates;
+	int current_max_lane_count = table->max_lane_count;
+	const int *current_rates = table->rates;
+	int num_current_rates = table->num_rates;
 
 	if (num_current_rates != num_rates)
 		return false;
@@ -626,6 +635,8 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 {
 	struct intel_dp *intel_dp = link_caps->dp;
 	struct intel_display *display = to_intel_display(intel_dp);
+	struct intel_dp_link_caps_config_table *table =
+		&link_caps->config_table;
 	struct intel_dp_link_config old_max_limits =
 		link_caps->max_limits;
 	int old_rates[DP_MAX_SUPPORTED_RATES];
@@ -640,26 +651,26 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 	if (drm_WARN_ON(display->drm, !is_power_of_2(max_lane_count)))
 		return false;
 
-	if (drm_WARN_ON(display->drm, num_rates > ARRAY_SIZE(link_caps->rates)))
+	if (drm_WARN_ON(display->drm, num_rates > ARRAY_SIZE(table->rates)))
 		return false;
 
 	num_common_lane_configs = ilog2(max_lane_count) + 1;
 
 	if (drm_WARN_ON(display->drm, num_rates * num_common_lane_configs >
-				    ARRAY_SIZE(link_caps->configs)))
+				    ARRAY_SIZE(table->configs)))
 		return false;
 
-	num_old_rates = link_caps->num_rates;
-	memcpy(old_rates, link_caps->rates, num_old_rates * sizeof(old_rates[0]));
-	old_max_lane_count = link_caps->max_lane_count;
+	num_old_rates = table->num_rates;
+	memcpy(old_rates, table->rates, num_old_rates * sizeof(old_rates[0]));
+	old_max_lane_count = table->max_lane_count;
 
-	memcpy(link_caps->rates, rates, num_rates * sizeof(rates[0]));
-	link_caps->num_rates = num_rates;
-	link_caps->max_lane_count = max_lane_count;
+	memcpy(table->rates, rates, num_rates * sizeof(rates[0]));
+	table->num_rates = num_rates;
+	table->max_lane_count = max_lane_count;
 
-	link_caps->num_configs = num_rates * num_common_lane_configs;
+	table->num_configs = num_rates * num_common_lane_configs;
 
-	lc = &link_caps->configs[0];
+	lc = &table->configs[0];
 	for (i = 0; i < num_rates; i++) {
 		for (j = 0; j < num_common_lane_configs; j++) {
 			lc->lane_count_exp = j;
@@ -669,12 +680,12 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 		}
 	}
 
-	sort_r(link_caps->configs, link_caps->num_configs,
-	       sizeof(link_caps->configs[0]),
+	sort_r(table->configs, table->num_configs,
+	       sizeof(table->configs[0]),
 	       link_config_cmp_by_bw, NULL,
 	       intel_dp);
 
-	if (!current_common_caps_match(link_caps, old_rates, num_old_rates,
+	if (!current_common_caps_match(table, old_rates, num_old_rates,
 				       old_max_lane_count))
 		link_params_changed = true;
 
@@ -698,12 +709,14 @@ void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps,
 			      int idx, int *link_rate, int *lane_count)
 {
 	struct intel_display *display = to_intel_display(link_caps->dp);
+	const struct intel_dp_link_caps_config_table *table =
+		&link_caps->config_table;
 	const struct intel_dp_link_config_entry *lc;
 
-	if (drm_WARN_ON(display->drm, idx < 0 || idx >= link_caps->num_configs))
+	if (drm_WARN_ON(display->drm, idx < 0 || idx >= table->num_configs))
 		idx = 0;
 
-	lc = &link_caps->configs[idx];
+	lc = &table->configs[idx];
 
 	*link_rate = intel_dp_link_config_rate(link_caps, lc);
 	*lane_count = intel_dp_link_config_lane_count(lc);
@@ -712,13 +725,14 @@ void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps,
 int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps,
 			       int link_rate, int lane_count)
 {
-	int link_rate_idx = intel_dp_rate_index(link_caps->rates, link_caps->num_rates,
+	const struct intel_dp_link_caps_config_table *table = &link_caps->config_table;
+	int link_rate_idx = intel_dp_rate_index(table->rates, table->num_rates,
 						link_rate);
 	int lane_count_exp = ilog2(lane_count);
 	int i;
 
-	for (i = 0; i < link_caps->num_configs; i++) {
-		const struct intel_dp_link_config_entry *lc = &link_caps->configs[i];
+	for (i = 0; i < table->num_configs; i++) {
+		const struct intel_dp_link_config_entry *lc = &table->configs[i];
 
 		if (lc->lane_count_exp == lane_count_exp &&
 		    lc->link_rate_idx == link_rate_idx)
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 068/108] drm/i915/dp_link_caps: Factor out a helper to look up a config table rate
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (66 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 067/108] drm/i915/dp_link_caps: Move config table members to a substruct Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 069/108] drm/i915/dp_link_caps: Pass config table pointer to rate lookup helper Imre Deak
                   ` (42 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Factor out a helper looking up a supported link rate from a config
table, used by a follow-up change.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c   | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 81c36e3326bb9..d5456c24714f4 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -139,6 +139,14 @@ struct intel_dp_link_caps {
 	struct intel_dp_link_config max_limits;
 };
 
+static int lookup_rate(const struct intel_dp_link_caps_config_table *table, int index)
+{
+	if (WARN_ON(index < 0 || index >= table->num_rates))
+		return 162000;
+
+	return table->rates[index];
+}
+
 /* Get length of common rates array potentially limited by max_rate. */
 static int intel_dp_link_caps_common_len_rate_limit(struct intel_dp_link_caps *link_caps,
 						    int max_rate)
@@ -162,14 +170,7 @@ static int intel_dp_link_caps_common_len_rate_limit(struct intel_dp_link_caps *l
  */
 int intel_dp_link_caps_common_rate(struct intel_dp_link_caps *link_caps, int index)
 {
-	struct intel_dp *intel_dp = link_caps->dp;
-	struct intel_display *display = to_intel_display(intel_dp);
-
-	if (drm_WARN_ON(display->drm,
-			index < 0 || index >= link_caps->config_table.num_rates))
-		return 162000;
-
-	return link_caps->config_table.rates[index];
+	return lookup_rate(&link_caps->config_table, index);
 }
 
 /**
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 069/108] drm/i915/dp_link_caps: Pass config table pointer to rate lookup helper
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (67 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 068/108] drm/i915/dp_link_caps: Factor out a helper to look up a config table rate Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 070/108] drm/i915/dp_link_caps: Factor out helper to get link config from table by index Imre Deak
                   ` (41 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Convert intel_dp_link_config_rate() to accept a pointer to the
config_table, instead of the full link_caps struct. This prepares for a
follow-up change that will precompute the table before committing it to
link_caps.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp_link_caps.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index d5456c24714f4..bd0a7a44279a3 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -274,10 +274,10 @@ void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 	forced_params->lane_count = forced_lane_count(link_caps);
 }
 
-static int intel_dp_link_config_rate(struct intel_dp_link_caps *link_caps,
+static int intel_dp_link_config_rate(const struct intel_dp_link_caps_config_table *table,
 				     const struct intel_dp_link_config_entry *lc)
 {
-	return intel_dp_link_caps_common_rate(link_caps, lc->link_rate_idx);
+	return lookup_rate(table, lc->link_rate_idx);
 }
 
 static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_entry *lc)
@@ -290,7 +290,7 @@ to_intel_dp_link_config(struct intel_dp_link_caps *link_caps,
 			const struct intel_dp_link_config_entry *lc,
 			struct intel_dp_link_config *config)
 {
-	config->rate = intel_dp_link_config_rate(link_caps, lc);
+	config->rate = intel_dp_link_config_rate(&link_caps->config_table, lc);
 	config->lane_count = intel_dp_link_config_lane_count(lc);
 }
 
@@ -562,7 +562,7 @@ void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps)
 static int intel_dp_link_config_bw(struct intel_dp_link_caps *link_caps,
 				   const struct intel_dp_link_config_entry *lc)
 {
-	return drm_dp_max_dprx_data_rate(intel_dp_link_config_rate(link_caps, lc),
+	return drm_dp_max_dprx_data_rate(intel_dp_link_config_rate(&link_caps->config_table, lc),
 					 intel_dp_link_config_lane_count(lc));
 }
 
@@ -579,8 +579,8 @@ static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 	if (bw_a != bw_b)
 		return bw_a - bw_b;
 
-	return intel_dp_link_config_rate(link_caps, lc_a) -
-	       intel_dp_link_config_rate(link_caps, lc_b);
+	return intel_dp_link_config_rate(&link_caps->config_table, lc_a) -
+	       intel_dp_link_config_rate(&link_caps->config_table, lc_b);
 }
 
 static bool current_common_caps_match(struct intel_dp_link_caps_config_table *table,
@@ -719,7 +719,7 @@ void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps,
 
 	lc = &table->configs[idx];
 
-	*link_rate = intel_dp_link_config_rate(link_caps, lc);
+	*link_rate = intel_dp_link_config_rate(&link_caps->config_table, lc);
 	*lane_count = intel_dp_link_config_lane_count(lc);
 }
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 070/108] drm/i915/dp_link_caps: Factor out helper to get link config from table by index
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (68 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 069/108] drm/i915/dp_link_caps: Pass config table pointer to rate lookup helper Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 071/108] drm/i915/dp_link_caps: Add helper to get config at iterator position Imre Deak
                   ` (40 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Factor out a helper that looks up a link configuration by index.
This provides the rate and lane count directly, avoiding the
indirect conversion via the packed config entry.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 43 ++++++++++++-------
 1 file changed, 27 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index bd0a7a44279a3..f17e30e84901b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -285,13 +285,28 @@ static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_ent
 	return 1 << lc->lane_count_exp;
 }
 
-static void
-to_intel_dp_link_config(struct intel_dp_link_caps *link_caps,
-			const struct intel_dp_link_config_entry *lc,
-			struct intel_dp_link_config *config)
+static int link_config_idx_to_rate(const struct intel_dp_link_caps_config_table *table,
+				   int config_idx)
 {
-	config->rate = intel_dp_link_config_rate(&link_caps->config_table, lc);
-	config->lane_count = intel_dp_link_config_lane_count(lc);
+	const struct intel_dp_link_config_entry *lc = &table->configs[config_idx];
+
+	return intel_dp_link_config_rate(table, lc);
+}
+
+static int link_config_idx_to_lane_count(const struct intel_dp_link_caps_config_table *table,
+					 int config_idx)
+{
+	const struct intel_dp_link_config_entry *lc = &table->configs[config_idx];
+
+	return intel_dp_link_config_lane_count(lc);
+}
+
+static void
+to_intel_dp_link_config(const struct intel_dp_link_caps_config_table *table,
+			int config_idx, struct intel_dp_link_config *config)
+{
+	config->rate = link_config_idx_to_rate(table, config_idx);
+	config->lane_count = link_config_idx_to_lane_count(table, config_idx);
 }
 
 static u32 calc_allowed_config_mask(struct intel_dp_link_caps *link_caps,
@@ -305,12 +320,10 @@ static u32 calc_allowed_config_mask(struct intel_dp_link_caps *link_caps,
 	int config_idx;
 
 	for (config_idx = 0; config_idx < table->num_configs; config_idx++) {
-		const struct intel_dp_link_config_entry *lc = &table->configs[config_idx];
-
 		if (BIT(config_idx) & disabled_config_mask)
 			continue;
 
-		to_intel_dp_link_config(link_caps, lc, &config);
+		to_intel_dp_link_config(table, config_idx, &config);
 
 		if (forced_params->rate &&
 		    forced_params->rate != config.rate)
@@ -398,12 +411,10 @@ static void compute_max_link_limits(struct intel_dp_link_caps *link_caps,
 	int config_idx;
 
 	for (config_idx = 0; config_idx < table->num_configs; config_idx++) {
-		const struct intel_dp_link_config_entry *lc = &table->configs[config_idx];
-
 		if (!(BIT(config_idx) & allowed_mask))
 			continue;
 
-		to_intel_dp_link_config(link_caps, lc, &link_config);
+		to_intel_dp_link_config(table, config_idx, &link_config);
 
 		max_config.rate = max(max_config.rate,
 				      link_config.rate);
@@ -712,15 +723,15 @@ void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps,
 	struct intel_display *display = to_intel_display(link_caps->dp);
 	const struct intel_dp_link_caps_config_table *table =
 		&link_caps->config_table;
-	const struct intel_dp_link_config_entry *lc;
+	struct intel_dp_link_config config;
 
 	if (drm_WARN_ON(display->drm, idx < 0 || idx >= table->num_configs))
 		idx = 0;
 
-	lc = &table->configs[idx];
+	to_intel_dp_link_config(table, idx, &config);
 
-	*link_rate = intel_dp_link_config_rate(&link_caps->config_table, lc);
-	*lane_count = intel_dp_link_config_lane_count(lc);
+	*link_rate = config.rate;
+	*lane_count = config.lane_count;
 }
 
 int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps,
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 071/108] drm/i915/dp_link_caps: Add helper to get config at iterator position
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (69 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 070/108] drm/i915/dp_link_caps: Factor out helper to get link config from table by index Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 072/108] drm/i915/dp_link_caps: Add helper to find position of matching config Imre Deak
                   ` (39 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add a helper to look up a link configuration for a given iteration order
at a given position, returning the canonical index and rate/lane info.
This prepares for iterating over any set of configurations in a
specified order.

This is needed by a follow-up replacing the configuration index based
look up in the fallback code (intel_dp_link_config_get()) with the
helper added here.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 73 +++++++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h | 63 ++++++++++++++++
 2 files changed, 136 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index f17e30e84901b..48b57aea557ca 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -15,6 +15,7 @@
 
 #include "intel_display_core.h"
 #include "intel_display_types.h"
+#include "intel_display_utils.h"
 #include "intel_dp.h"
 #include "intel_dp_link_caps.h"
 
@@ -309,6 +310,46 @@ to_intel_dp_link_config(const struct intel_dp_link_caps_config_table *table,
 	config->lane_count = link_config_idx_to_lane_count(table, config_idx);
 }
 
+static bool
+get_table_config_by_pos(const struct intel_dp_link_caps_config_table *config_table,
+			struct intel_dp_link_caps_config_order config_order,
+			int iter_pos,
+			struct intel_dp_link_config *config, int *config_idx)
+{
+	if (!in_range(iter_pos, 0, config_table->num_configs))
+		goto out_fail;
+
+	switch (config_order.dir) {
+	case INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_ASC:
+		break;
+	default:
+		MISSING_CASE(config_order.dir);
+
+		goto out_fail;
+	}
+
+	switch (config_order.key) {
+	case INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW:
+		*config_idx = iter_pos;
+
+		break;
+	default:
+		MISSING_CASE(config_order.key);
+
+		goto out_fail;
+	}
+
+	to_intel_dp_link_config(config_table, *config_idx, config);
+
+	return true;
+
+out_fail:
+	*config = INTEL_DP_LINK_CONFIG_NULL;
+	*config_idx = -1;
+
+	return false;
+}
+
 static u32 calc_allowed_config_mask(struct intel_dp_link_caps *link_caps,
 				    u32 disabled_config_mask,
 				    const struct intel_dp_link_config *max_limits,
@@ -370,6 +411,38 @@ u32 intel_dp_link_caps_get_allowed_config_mask(struct intel_dp_link_caps *link_c
 					&link_caps->max_limits, &forced_params);
 }
 
+/**
+ * intel_dp_link_caps_get_config_by_pos - get config at a given iterator position
+ * @link_caps: link capability state
+ * @config_order: iteration order
+ * @iter_pos: position in the @config_order iteration order
+ * @config: returned link configuration
+ * @config_idx: returned config index
+ *
+ * Look up the link config at iterator position @iter_pos in the order
+ * described by @config_order.
+ *
+ * Note that any mapping between @iter_pos and @config_idx is an
+ * implementation detail defined by @config_order and must not be
+ * relied upon. The returned @config_idx always, regardless of
+ * @config_order, uses the canonical configuration index/mask scheme
+ * shared by the link-caps API.
+ *
+ * Return:
+ * - %true  if @iter_pos is valid, storing the configuration in @config and
+ *          its index in @config_idx.
+ * - %false if @iter_pos is out of range, storing %INTEL_DP_LINK_CONFIG_NULL
+ *          in @config and -1 in @config_idx.
+ */
+bool intel_dp_link_caps_get_config_by_pos(struct intel_dp_link_caps *link_caps,
+					  struct intel_dp_link_caps_config_order config_order,
+					  int iter_pos,
+					  struct intel_dp_link_config *config, int *config_idx)
+{
+	return get_table_config_by_pos(&link_caps->config_table, config_order, iter_pos,
+				       config, config_idx);
+}
+
 static void set_max_link_limits_no_update(struct intel_dp_link_caps *link_caps,
 					  const struct intel_dp_link_config *max_link_limits)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 7fe0e4a028f26..79cd50db90ba6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -11,6 +11,64 @@ struct intel_dp;
 struct intel_dp_link_caps;
 struct intel_dp_link_config;
 
+/**
+ * enum intel_dp_link_caps_config_order_key - key used to order configurations
+ * @INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW:
+ *   Order configurations by bandwidth, then by link rate.
+ * @INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_NUM:
+ *   Number of ordering keys.
+ *
+ * Selects how a caller wants the configuration table to be ordered,
+ * together with an &enum intel_dp_link_caps_config_order_direction, for
+ * iteration queries.
+ *
+ * See also:
+ *  - &struct intel_dp_link_caps_config_order
+ */
+enum intel_dp_link_caps_config_order_key {
+	INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW,
+
+	INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_NUM
+};
+
+/**
+ * enum intel_dp_link_caps_config_order_direction - iteration direction
+ * @INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_ASC:
+ *   Iterate in ascending order according to the selected ordering key.
+ * @INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_NUM:
+ *   Number of ordering directions.
+ *
+ * Selects the direction associated with an
+ * &enum intel_dp_link_caps_config_order_key for iteration queries.
+ *
+ * See also:
+ *  - &struct intel_dp_link_caps_config_order
+ */
+enum intel_dp_link_caps_config_order_direction {
+	INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_ASC,
+
+	INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_NUM
+};
+
+/**
+ * struct intel_dp_link_caps_config_order - configuration ordering
+ * @key:
+ *   Key used to order configurations, see
+ *   &enum intel_dp_link_caps_config_order_key.
+ * @dir:
+ *   Direction of the selected ordering, see
+ *   &enum intel_dp_link_caps_config_order_direction.
+ *
+ * Describes an iteration order for link configurations.
+ *
+ * See also:
+ *  - intel_dp_link_caps_get_config_by_pos()
+ */
+struct intel_dp_link_caps_config_order {
+	enum intel_dp_link_caps_config_order_key key;
+	enum intel_dp_link_caps_config_order_direction dir;
+};
+
 int intel_dp_link_caps_common_rate(struct intel_dp_link_caps *link_caps, int index);
 int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate);
 int intel_dp_link_caps_max_common_rate(struct intel_dp_link_caps *link_caps);
@@ -24,6 +82,11 @@ u32 intel_dp_link_caps_get_allowed_config_mask(struct intel_dp_link_caps *link_c
 
 int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps,
 			       int link_rate, int lane_count);
+bool
+intel_dp_link_caps_get_config_by_pos(struct intel_dp_link_caps *link_caps,
+				     struct intel_dp_link_caps_config_order config_order,
+				     int iter_pos,
+				     struct intel_dp_link_config *config, int *config_idx);
 void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps,
 			      int idx, int *link_rate, int *lane_count);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 072/108] drm/i915/dp_link_caps: Add helper to find position of matching config
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (70 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 071/108] drm/i915/dp_link_caps: Add helper to get config at iterator position Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 073/108] drm/i915/dp_link_training: Reset the max link limits in the fallback code Imre Deak
                   ` (38 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add a helper to find the iteration position of a given link
configuration within a specified iteration order over the currently
allowed configurations. The rate being looked up may differ from the
nominal rate tracked for allowed configurations due to platform-specific
PLL divider restrictions. Fuzzy matching allows selecting the closest
supported rate.

This is needed by a follow-up change replacing the exact-rate look up in
the fallback code (intel_dp_link_config_index()) with the helper added
here.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 88 +++++++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h | 24 +++++
 2 files changed, 112 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 48b57aea557ca..284d28f9d98d7 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -6,6 +6,7 @@
 #include <linux/bitops.h>
 #include <linux/debugfs.h>
 #include <linux/log2.h>
+#include <linux/math.h>
 #include <linux/slab.h>
 #include <linux/sort.h>
 #include <linux/string.h>
@@ -443,6 +444,93 @@ bool intel_dp_link_caps_get_config_by_pos(struct intel_dp_link_caps *link_caps,
 				       config, config_idx);
 }
 
+static bool is_within_percent(int actual, int nominal, int percent)
+{
+	int diff = abs(actual - nominal);
+
+	if (WARN_ON(percent == 0 ||
+		    diff > INT_MAX / 100 || nominal > INT_MAX / percent))
+		return false;
+
+	return diff * 100 <= nominal * percent;
+}
+
+static int
+find_config_table_entry_pos(const struct intel_dp_link_caps_config_table *config_table,
+			    struct intel_dp_link_caps_config_order config_order, u32 config_mask,
+			    enum intel_dp_link_caps_config_match_type match_type,
+			    const struct intel_dp_link_config *link_config)
+{
+	struct intel_dp_link_config iter_config;
+	int iter_config_idx;
+	int iter_pos;
+
+	for (iter_pos = 0;
+	     get_table_config_by_pos(config_table, config_order, iter_pos,
+				     &iter_config, &iter_config_idx);
+	     iter_pos++) {
+		if (!(BIT(iter_config_idx) & config_mask))
+			continue;
+
+		if (iter_config.lane_count != link_config->lane_count)
+			continue;
+
+		/*
+		 * link_config->rate may be platform-derived rather than the nominal
+		 * supported link rate.
+		 *
+		 * When the caller requests fuzzy rate matching, accept a nominal rate
+		 * within 1 percent of the requested rate.
+		 *
+		 * The DP spec seems to allow at most 300 ppm of symbol clock tolerance,
+		 * excluding SSC. However, at least on g4x, the 2.7 Gbps rate exceeds
+		 * that (~5000ppm); see intel_dp_compute_rate(). So allow 10000 ppm, or
+		 * a 1 percent difference.
+		 *
+		 * The first match is also the best one, since nominal rates are guaranteed
+		 * to be spaced much farther apart than 1 percent.
+		 *
+		 * TODO: Track the nominal link rate separately, pass it here, and require
+		 * an exact match.
+		 */
+		if (iter_config.rate != link_config->rate &&
+		    (match_type == INTEL_DP_LINK_CAPS_CONFIG_MATCH_EXACT ||
+		     !is_within_percent(link_config->rate, iter_config.rate, 1)))
+			continue;
+
+		return iter_pos;
+	}
+
+	return -1;
+}
+
+/**
+ * intel_dp_link_caps_find_allowed_config_pos - find matching allowed config position
+ * @link_caps: link capabilities state
+ * @config_order: iteration order
+ * @match_type: requested match type
+ * @link_config: link configuration to match
+ *
+ * Search the currently allowed link configurations for a match to
+ * @link_config.
+ *
+ * Return:
+ * - The position of the first matching allowed configuration in the
+ *   @config_order iteration.
+ * - %-1 if no allowed configuration matches.
+ */
+int intel_dp_link_caps_find_allowed_config_pos(struct intel_dp_link_caps *link_caps,
+					       struct intel_dp_link_caps_config_order config_order,
+					       enum intel_dp_link_caps_config_match_type match_type,
+					       const struct intel_dp_link_config *link_config)
+{
+	u32 allowed_config_mask = intel_dp_link_caps_get_allowed_config_mask(link_caps);
+
+	return find_config_table_entry_pos(&link_caps->config_table, config_order,
+					   allowed_config_mask, match_type,
+					   link_config);
+}
+
 static void set_max_link_limits_no_update(struct intel_dp_link_caps *link_caps,
 					  const struct intel_dp_link_config *max_link_limits)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 79cd50db90ba6..cacdda15a36af 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -69,6 +69,26 @@ struct intel_dp_link_caps_config_order {
 	enum intel_dp_link_caps_config_order_direction dir;
 };
 
+/**
+ * enum intel_dp_link_caps_config_match_type - configuration match semantics
+ * @INTEL_DP_LINK_CAPS_CONFIG_MATCH_EXACT:
+ *   Require an exact nominal link rate match and an
+ *   exact lane count match.
+ * @INTEL_DP_LINK_CAPS_CONFIG_MATCH_FUZZY_RATE:
+ *   Require an exact lane count match, but allow the
+ *   requested link rate to match approximately to a
+ *   supported nominal link rate.
+ *
+ * Selects how
+ * intel_dp_link_caps_find_allowed_config_pos() matches
+ * the requested &struct intel_dp_link_config against the currently
+ * allowed configurations.
+ */
+enum intel_dp_link_caps_config_match_type {
+	INTEL_DP_LINK_CAPS_CONFIG_MATCH_EXACT,
+	INTEL_DP_LINK_CAPS_CONFIG_MATCH_FUZZY_RATE,
+};
+
 int intel_dp_link_caps_common_rate(struct intel_dp_link_caps *link_caps, int index);
 int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate);
 int intel_dp_link_caps_max_common_rate(struct intel_dp_link_caps *link_caps);
@@ -89,6 +109,10 @@ intel_dp_link_caps_get_config_by_pos(struct intel_dp_link_caps *link_caps,
 				     struct intel_dp_link_config *config, int *config_idx);
 void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps,
 			      int idx, int *link_rate, int *lane_count);
+int intel_dp_link_caps_find_allowed_config_pos(struct intel_dp_link_caps *link_caps,
+					       struct intel_dp_link_caps_config_order order,
+					       enum intel_dp_link_caps_config_match_type match_type,
+					       const struct intel_dp_link_config *config);
 
 void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
 				       struct intel_dp_link_config *max_link_limits);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 073/108] drm/i915/dp_link_training: Reset the max link limits in the fallback code
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (71 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 072/108] drm/i915/dp_link_caps: Add helper to find position of matching config Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 074/108] drm/i915/dp_link_training: Use config iterator for BW-order fallback Imre Deak
                   ` (37 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

The target maximum rate/lane count selected by the fallback logic may
exceed the current link_caps max_limits' rate/lane count, the latter of
which are used as a limit by the lookup functions when filtering allowed
configurations. To ensure the fallback search finds all relevant
candidates, temporarily reset the link_caps max_limits to the maximum
common supported capabilities.

After the fallback search completes, set the link_caps max_limits to the
configuration selected by the fallback logic, as before, determining
the allowed configurations for a subsequent modeset.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c | 41 ++++++++++++++++---
 1 file changed, 36 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index b7645bcbe0c2b..69396dbb94b2e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1874,10 +1874,12 @@ static bool reduce_link_params(struct intel_dp *intel_dp, const struct intel_crt
 static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
 						   const struct intel_crtc_state *crtc_state)
 {
+	struct intel_display *display = to_intel_display(intel_dp);
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_dp_link_config max_link_limits;
 	int new_link_rate;
 	int new_lane_count;
+	int err = -1;
 
 	if (intel_dp_is_edp(intel_dp) && !intel_dp->use_max_params) {
 		lt_dbg(intel_dp, DP_PHY_DPRX,
@@ -1886,14 +1888,34 @@ static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
 		return 0;
 	}
 
+	/*
+	 * Temporarily reset the max link limit before selecting the fallback
+	 * config.
+	 *
+	 * After fallback, the current logic narrows the allowed configurations
+	 * to the selected config's rate and lane count. That can make a later
+	 * fallback candidate fall outside the current max_limit, so reset it
+	 * before searching.
+	 *
+	 * TODO: Make max_limit just reflect the maximum of the allowed configs
+	 * at all times. Then fallback will stop narrowing the allowed set this
+	 * way, the limit will never need to increase, and this reset can be
+	 * removed.
+	 */
+	intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits);
+	intel_dp_link_caps_reset_max_limits(link_caps);
+
 	if (!reduce_link_params(intel_dp, crtc_state, &new_link_rate, &new_lane_count))
-		return -1;
+		goto out_restore_max_limits;
 
 	if (intel_dp_is_edp(intel_dp) &&
 	    !intel_dp_can_link_train_fallback_for_edp(intel_dp, new_link_rate, new_lane_count)) {
 		lt_dbg(intel_dp, DP_PHY_DPRX,
 		       "Retrying Link training for eDP with same parameters\n");
-		return 0;
+
+		err = 0;
+
+		goto out_restore_max_limits;
 	}
 
 	lt_dbg(intel_dp, DP_PHY_DPRX,
@@ -1904,10 +1926,19 @@ static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
 	max_link_limits.rate = new_link_rate;
 	max_link_limits.lane_count = new_lane_count;
 
-	/* TODO: handle an update failure */
-	intel_dp_link_caps_set_max_limits(link_caps, &max_link_limits);
+	err = 0;
 
-	return 0;
+out_restore_max_limits:
+	/*
+	 * Shouldn't fail: setting max_limits can only fail if they drop below
+	 * the optionally forced rate/lane-count parameters, but the reduced
+	 * config was chosen to satisfy those constraints.
+	 */
+	if (drm_WARN_ON(display->drm,
+			!intel_dp_link_caps_set_max_limits(link_caps, &max_link_limits)))
+		err = -1;
+
+	return err;
 }
 
 static bool intel_dp_schedule_fallback_link_training(struct intel_atomic_state *state,
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 074/108] drm/i915/dp_link_training: Use config iterator for BW-order fallback
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (72 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 073/108] drm/i915/dp_link_training: Reset the max link limits in the fallback code Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 075/108] drm/i915/dp_link_training: Look up configurations using fuzzy rate matching Imre Deak
                   ` (36 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Switch the BW-order fallback loop to look up an allowed configuration by
its iteration position rather than by its configuration index. Currently
the index and iteration position match for BW-order used by the
fallback, but future changes will make iteration positions key- and
direction-specific. For now, use the BW / ascending iteration order so
iteration positions match the config index as expected by the current
code.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 17 -----------
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  2 --
 .../drm/i915/display/intel_dp_link_training.c | 29 ++++++++++++++++++-
 3 files changed, 28 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 284d28f9d98d7..103490eec3d23 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -878,23 +878,6 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 	return link_params_changed;
 }
 
-void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps,
-			      int idx, int *link_rate, int *lane_count)
-{
-	struct intel_display *display = to_intel_display(link_caps->dp);
-	const struct intel_dp_link_caps_config_table *table =
-		&link_caps->config_table;
-	struct intel_dp_link_config config;
-
-	if (drm_WARN_ON(display->drm, idx < 0 || idx >= table->num_configs))
-		idx = 0;
-
-	to_intel_dp_link_config(table, idx, &config);
-
-	*link_rate = config.rate;
-	*lane_count = config.lane_count;
-}
-
 int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps,
 			       int link_rate, int lane_count)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index cacdda15a36af..b380beedd8990 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -107,8 +107,6 @@ intel_dp_link_caps_get_config_by_pos(struct intel_dp_link_caps *link_caps,
 				     struct intel_dp_link_caps_config_order config_order,
 				     int iter_pos,
 				     struct intel_dp_link_config *config, int *config_idx);
-void intel_dp_link_config_get(struct intel_dp_link_caps *link_caps,
-			      int idx, int *link_rate, int *lane_count);
 int intel_dp_link_caps_find_allowed_config_pos(struct intel_dp_link_caps *link_caps,
 					       struct intel_dp_link_caps_config_order order,
 					       enum intel_dp_link_caps_config_match_type match_type,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 69396dbb94b2e..9dd302bb4968b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1760,10 +1760,20 @@ static bool reduce_link_params_in_bw_order(struct intel_dp *intel_dp,
 					   const struct intel_crtc_state *crtc_state,
 					   int *new_link_rate, int *new_lane_count)
 {
+	struct intel_display *display = to_intel_display(intel_dp);
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp_link_caps_config_order bw_asc_order = {
+		.key = INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW,
+		.dir = INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_ASC,
+	};
+	struct intel_dp_link_config link_config = {
+		.rate = crtc_state->port_clock,
+		.lane_count = crtc_state->lane_count,
+	};
 	struct intel_dp_link_config forced_params;
 	int forced_lane_count;
 	int forced_rate;
+	int link_config_idx;
 	int link_rate;
 	int lane_count;
 	int i;
@@ -1775,7 +1785,24 @@ static bool reduce_link_params_in_bw_order(struct intel_dp *intel_dp,
 	i = intel_dp_link_config_index(intel_dp->link.caps,
 				       crtc_state->port_clock, crtc_state->lane_count);
 	for (i--; i >= 0; i--) {
-		intel_dp_link_config_get(intel_dp->link.caps, i, &link_rate, &lane_count);
+		bool config_found;
+
+		config_found = intel_dp_link_caps_get_config_by_pos(link_caps,
+								    bw_asc_order, i,
+								    &link_config,
+								    &link_config_idx);
+		if (drm_WARN_ON(display->drm, !config_found))
+			return false;
+
+		/*
+		 * Atm, the index of the configuration must match its
+		 * iteration position.
+		 */
+		if (drm_WARN_ON(display->drm, link_config_idx != i))
+			return false;
+
+		link_rate = link_config.rate;
+		lane_count = link_config.lane_count;
 
 		if ((forced_rate &&
 		     forced_rate != link_rate) ||
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 075/108] drm/i915/dp_link_training: Look up configurations using fuzzy rate matching
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (73 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 074/108] drm/i915/dp_link_training: Use config iterator for BW-order fallback Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 076/108] drm/i915/dp_link_caps: Pass table pointer to the sort compare function Imre Deak
                   ` (35 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Look up an allowed link configuration during the BW-order fallback using
a fuzzy rate match to account for differences between the computed link
rate and the nominal rate tracked by the allowed configurations.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 20 -------------------
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  2 --
 .../drm/i915/display/intel_dp_link_training.c | 19 +++++++++---------
 3 files changed, 10 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 103490eec3d23..7643c468588d0 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -878,26 +878,6 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 	return link_params_changed;
 }
 
-int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps,
-			       int link_rate, int lane_count)
-{
-	const struct intel_dp_link_caps_config_table *table = &link_caps->config_table;
-	int link_rate_idx = intel_dp_rate_index(table->rates, table->num_rates,
-						link_rate);
-	int lane_count_exp = ilog2(lane_count);
-	int i;
-
-	for (i = 0; i < table->num_configs; i++) {
-		const struct intel_dp_link_config_entry *lc = &table->configs[i];
-
-		if (lc->lane_count_exp == lane_count_exp &&
-		    lc->link_rate_idx == link_rate_idx)
-			return i;
-	}
-
-	return -1;
-}
-
 /**
  * intel_dp_link_caps_reset - reset link capability restrictions
  * @link_caps: link capabilities state
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index b380beedd8990..6599325932ab6 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -100,8 +100,6 @@ void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 					  struct intel_dp_link_config *forced_params);
 u32 intel_dp_link_caps_get_allowed_config_mask(struct intel_dp_link_caps *link_caps);
 
-int intel_dp_link_config_index(struct intel_dp_link_caps *link_caps,
-			       int link_rate, int lane_count);
 bool
 intel_dp_link_caps_get_config_by_pos(struct intel_dp_link_caps *link_caps,
 				     struct intel_dp_link_caps_config_order config_order,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index 9dd302bb4968b..fb20795a7086f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1782,8 +1782,16 @@ static bool reduce_link_params_in_bw_order(struct intel_dp *intel_dp,
 	forced_rate = forced_params.rate;
 	forced_lane_count = forced_params.lane_count;
 
-	i = intel_dp_link_config_index(intel_dp->link.caps,
-				       crtc_state->port_clock, crtc_state->lane_count);
+	/*
+	 * The computed link rate could differ from the nominal rate
+	 * due to platform specific PLL restrictions, so use a fuzzy
+	 * matching.
+	 */
+	i = intel_dp_link_caps_find_allowed_config_pos(link_caps,
+						       bw_asc_order,
+						       INTEL_DP_LINK_CAPS_CONFIG_MATCH_FUZZY_RATE,
+						       &link_config);
+
 	for (i--; i >= 0; i--) {
 		bool config_found;
 
@@ -1794,13 +1802,6 @@ static bool reduce_link_params_in_bw_order(struct intel_dp *intel_dp,
 		if (drm_WARN_ON(display->drm, !config_found))
 			return false;
 
-		/*
-		 * Atm, the index of the configuration must match its
-		 * iteration position.
-		 */
-		if (drm_WARN_ON(display->drm, link_config_idx != i))
-			return false;
-
 		link_rate = link_config.rate;
 		lane_count = link_config.lane_count;
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 076/108] drm/i915/dp_link_caps: Pass table pointer to the sort compare function
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (74 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 075/108] drm/i915/dp_link_training: Look up configurations using fuzzy rate matching Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 077/108] drm/i915/dp_link_caps: Compare config tables instead of link parameters Imre Deak
                   ` (34 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Convert the sort compare function to accept a pointer to the
config_table, instead of the full link_caps struct. This prepares for a
follow-up change that will precompute the table before committing it to
link_caps.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c  | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 7643c468588d0..53649aa710f94 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -731,28 +731,26 @@ void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps)
 	update_max_link_info(link_caps);
 }
 
-static int intel_dp_link_config_bw(struct intel_dp_link_caps *link_caps,
+static int intel_dp_link_config_bw(const struct intel_dp_link_caps_config_table *table,
 				   const struct intel_dp_link_config_entry *lc)
 {
-	return drm_dp_max_dprx_data_rate(intel_dp_link_config_rate(&link_caps->config_table, lc),
+	return drm_dp_max_dprx_data_rate(intel_dp_link_config_rate(table, lc),
 					 intel_dp_link_config_lane_count(lc));
 }
 
 static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 {
-	struct intel_dp *intel_dp = (struct intel_dp *)p;	/* remove const */
-	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
-
+	const struct intel_dp_link_caps_config_table *table = p;
 	const struct intel_dp_link_config_entry *lc_a = a;
 	const struct intel_dp_link_config_entry *lc_b = b;
-	int bw_a = intel_dp_link_config_bw(link_caps, lc_a);
-	int bw_b = intel_dp_link_config_bw(link_caps, lc_b);
+	int bw_a = intel_dp_link_config_bw(table, lc_a);
+	int bw_b = intel_dp_link_config_bw(table, lc_b);
 
 	if (bw_a != bw_b)
 		return bw_a - bw_b;
 
-	return intel_dp_link_config_rate(&link_caps->config_table, lc_a) -
-	       intel_dp_link_config_rate(&link_caps->config_table, lc_b);
+	return intel_dp_link_config_rate(table, lc_a) -
+	       intel_dp_link_config_rate(table, lc_b);
 }
 
 static bool current_common_caps_match(struct intel_dp_link_caps_config_table *table,
@@ -856,7 +854,7 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 	sort_r(table->configs, table->num_configs,
 	       sizeof(table->configs[0]),
 	       link_config_cmp_by_bw, NULL,
-	       intel_dp);
+	       table);
 
 	if (!current_common_caps_match(table, old_rates, num_old_rates,
 				       old_max_lane_count))
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 077/108] drm/i915/dp_link_caps: Compare config tables instead of link parameters
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (75 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 076/108] drm/i915/dp_link_caps: Pass table pointer to the sort compare function Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:51 ` [PATCH 078/108] drm/i915/dp_link_caps: Precompute config table before update Imre Deak
                   ` (33 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Replace change detection based on link parameters (max_lane_count,
rates, and num_rates) with direct comparison of the resulting config
tables.

Keep a temporary copy of the existing table and compare it against the
recomputed table.

This prepares for a follow-up change that will precompute the table
before committing it to link_caps.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 27 +++++++------------
 1 file changed, 9 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 53649aa710f94..b156b0ff0eedc 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -753,21 +753,17 @@ static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 	       intel_dp_link_config_rate(table, lc_b);
 }
 
-static bool current_common_caps_match(struct intel_dp_link_caps_config_table *table,
-				      const int *rates, int num_rates,
-				      int old_max_lane_count)
+static bool config_tables_match(const struct intel_dp_link_caps_config_table *table_a,
+				const struct intel_dp_link_caps_config_table *table_b)
 {
-	int current_max_lane_count = table->max_lane_count;
-	const int *current_rates = table->rates;
-	int num_current_rates = table->num_rates;
-
-	if (num_current_rates != num_rates)
+	if (table_a->num_rates != table_b->num_rates)
 		return false;
 
-	if (current_max_lane_count != old_max_lane_count)
+	if (table_a->max_lane_count != table_b->max_lane_count)
 		return false;
 
-	if (memcmp(current_rates, rates, num_rates * sizeof(rates[0])))
+	if (memcmp(table_a->rates, table_b->rates,
+		   table_a->num_rates * sizeof(table_a->rates[0])))
 		return false;
 
 	return true;
@@ -808,14 +804,12 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 	struct intel_display *display = to_intel_display(intel_dp);
 	struct intel_dp_link_caps_config_table *table =
 		&link_caps->config_table;
+	struct intel_dp_link_caps_config_table old_table;
 	struct intel_dp_link_config old_max_limits =
 		link_caps->max_limits;
-	int old_rates[DP_MAX_SUPPORTED_RATES];
 	struct intel_dp_link_config_entry *lc;
 	bool link_params_changed = false;
 	int num_common_lane_configs;
-	int old_max_lane_count;
-	int num_old_rates;
 	int i;
 	int j;
 
@@ -831,9 +825,7 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 				    ARRAY_SIZE(table->configs)))
 		return false;
 
-	num_old_rates = table->num_rates;
-	memcpy(old_rates, table->rates, num_old_rates * sizeof(old_rates[0]));
-	old_max_lane_count = table->max_lane_count;
+	old_table = *table;
 
 	memcpy(table->rates, rates, num_rates * sizeof(rates[0]));
 	table->num_rates = num_rates;
@@ -856,8 +848,7 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 	       link_config_cmp_by_bw, NULL,
 	       table);
 
-	if (!current_common_caps_match(table, old_rates, num_old_rates,
-				       old_max_lane_count))
+	if (!config_tables_match(table, &old_table))
 		link_params_changed = true;
 
 	/*
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 078/108] drm/i915/dp_link_caps: Precompute config table before update
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (76 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 077/108] drm/i915/dp_link_caps: Compare config tables instead of link parameters Imre Deak
@ 2026-04-28 12:51 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 079/108] drm/i915/dp_link_caps: Compare internal config entries during table matching Imre Deak
                   ` (32 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:51 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Factor out a function to precompute the link configuration table into a
temporary new_table before committing it to link_caps. This allows a
straightforward comparison with the existing table and enables a
follow-up change to merge the old and new tables as required.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 93 +++++++++++--------
 1 file changed, 52 insertions(+), 41 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index b156b0ff0eedc..65358ec34d44b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -769,6 +769,53 @@ static bool config_tables_match(const struct intel_dp_link_caps_config_table *ta
 	return true;
 }
 
+static bool build_config_table(struct intel_display *display,
+			       const int *rates, int num_rates, int max_lane_count,
+			       struct intel_dp_link_caps_config_table *table)
+{
+	struct intel_dp_link_config_entry *lc;
+	int num_common_lane_configs;
+	int i;
+	int j;
+
+	if (drm_WARN_ON(display->drm, !is_power_of_2(max_lane_count)))
+		return false;
+
+	if (drm_WARN_ON(display->drm, num_rates > ARRAY_SIZE(table->rates)))
+		return false;
+
+	num_common_lane_configs = ilog2(max_lane_count) + 1;
+
+	if (drm_WARN_ON(display->drm, num_rates * num_common_lane_configs >
+				    ARRAY_SIZE(table->configs)))
+		return false;
+
+	memset(table, 0, sizeof(*table));
+
+	memcpy(table->rates, rates, num_rates * sizeof(rates[0]));
+	table->num_rates = num_rates;
+	table->max_lane_count = max_lane_count;
+
+	table->num_configs = num_rates * num_common_lane_configs;
+
+	lc = &table->configs[0];
+	for (i = 0; i < num_rates; i++) {
+		for (j = 0; j < num_common_lane_configs; j++) {
+			lc->lane_count_exp = j;
+			lc->link_rate_idx = i;
+
+			lc++;
+		}
+	}
+
+	sort_r(table->configs, table->num_configs,
+	       sizeof(table->configs[0]),
+	       link_config_cmp_by_bw, NULL,
+	       table);
+
+	return true;
+}
+
 /**
  * intel_dp_link_caps_update - rebuild the supported link configuration state
  * @link_caps: link capabilities state
@@ -802,55 +849,19 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 {
 	struct intel_dp *intel_dp = link_caps->dp;
 	struct intel_display *display = to_intel_display(intel_dp);
-	struct intel_dp_link_caps_config_table *table =
-		&link_caps->config_table;
-	struct intel_dp_link_caps_config_table old_table;
+	struct intel_dp_link_caps_config_table new_table;
 	struct intel_dp_link_config old_max_limits =
 		link_caps->max_limits;
-	struct intel_dp_link_config_entry *lc;
 	bool link_params_changed = false;
-	int num_common_lane_configs;
-	int i;
-	int j;
 
-	if (drm_WARN_ON(display->drm, !is_power_of_2(max_lane_count)))
+	if (!build_config_table(display, rates, num_rates, max_lane_count, &new_table))
 		return false;
 
-	if (drm_WARN_ON(display->drm, num_rates > ARRAY_SIZE(table->rates)))
-		return false;
-
-	num_common_lane_configs = ilog2(max_lane_count) + 1;
-
-	if (drm_WARN_ON(display->drm, num_rates * num_common_lane_configs >
-				    ARRAY_SIZE(table->configs)))
-		return false;
-
-	old_table = *table;
-
-	memcpy(table->rates, rates, num_rates * sizeof(rates[0]));
-	table->num_rates = num_rates;
-	table->max_lane_count = max_lane_count;
-
-	table->num_configs = num_rates * num_common_lane_configs;
-
-	lc = &table->configs[0];
-	for (i = 0; i < num_rates; i++) {
-		for (j = 0; j < num_common_lane_configs; j++) {
-			lc->lane_count_exp = j;
-			lc->link_rate_idx = i;
-
-			lc++;
-		}
-	}
-
-	sort_r(table->configs, table->num_configs,
-	       sizeof(table->configs[0]),
-	       link_config_cmp_by_bw, NULL,
-	       table);
-
-	if (!config_tables_match(table, &old_table))
+	if (!config_tables_match(&new_table, &link_caps->config_table))
 		link_params_changed = true;
 
+	link_caps->config_table = new_table;
+
 	/*
 	 * A failure could be only due to a bug, the update function handles
 	 * that case by removing all restriction and resetting the max limit
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 079/108] drm/i915/dp_link_caps: Compare internal config entries during table matching
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (77 preceding siblings ...)
  2026-04-28 12:51 ` [PATCH 078/108] drm/i915/dp_link_caps: Precompute config table before update Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 080/108] drm/i915/dp_link_caps: Use virtual config indexing in config table Imre Deak
                   ` (31 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Include the packed configuration entries when comparing two link
configuration tables, so that any change in them can be detected.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp_link_caps.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 65358ec34d44b..a6390ed024940 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -762,10 +762,17 @@ static bool config_tables_match(const struct intel_dp_link_caps_config_table *ta
 	if (table_a->max_lane_count != table_b->max_lane_count)
 		return false;
 
+	if (table_a->num_configs != table_b->num_configs)
+		return false;
+
 	if (memcmp(table_a->rates, table_b->rates,
 		   table_a->num_rates * sizeof(table_a->rates[0])))
 		return false;
 
+	if (memcmp(table_a->configs, table_b->configs,
+		   table_a->num_configs * sizeof(table_a->configs[0])))
+		return false;
+
 	return true;
 }
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 080/108] drm/i915/dp_link_caps: Use virtual config indexing in config table
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (78 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 079/108] drm/i915/dp_link_caps: Compare internal config entries during table matching Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 081/108] drm/i915/dp_link_caps: Simplify idx->link rate/lane count lookup Imre Deak
                   ` (30 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Replace explicit storage of rate index and lane count exponent in each
configuration table entry with a virtual indexing scheme. Each entry's
rate index and lane exponent are derived from its position in the table
assuming a fixed rate/lane ordering and a fixed 4 lane-count stride:

  rate_idx = idx / 4
  lane_exp = idx % 4

To support different iteration orders, store a map from this virtual
index to the config_table::configs array and sort it as needed.

This also adds a way - for free - to iterate the configurations in a
rate/lane order besides the BW order currently supported, which will
be required by follow-up changes.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 106 +++++++++++++++---
 1 file changed, 89 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index a6390ed024940..0d828ad9f93a7 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -89,18 +89,45 @@ struct intel_dp_link_caps {
 		int rates[DP_MAX_SUPPORTED_RATES];
 		int max_lane_count;
 
-		/* common rate,lane_count configs in bw order */
+		/*
+		 * Number of configurations supported for the current sink
+		 * connection.
+		 */
 		int num_configs;
+		/*
+		 * Virtual rate/lane configuration space.
+		 *
+		 * Configurations are not stored explicitly. Instead, each
+		 * configuration is identified by an index in a conceptual
+		 * table ordered by (rate_idx, lane_count) in ascending order,
+		 * with a fixed lane stride of
+		 * INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS.
+		 *
+		 * For now the above index is stored in struct
+		 * intel_dp_link_config_entry::config_idx.
+		 *
+		 * A configuration can be reconstructed from its index as:
+		 *
+		 *   rate_idx  = idx / INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS
+		 *   lane_exp  = idx % INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS
+		 *   rate      = rates[rate_idx]
+		 *   lane_count = 1 << lane_exp
+		 *
+		 * In this conceptual table, only entries within the current
+		 * sink limits are valid, i.e. those allowed by the current
+		 * number of rates and maximum lane count.
+		 */
 #define INTEL_DP_MAX_LANE_COUNT			4
-#define INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS	(ilog2(INTEL_DP_MAX_LANE_COUNT) + 1)
-#define INTEL_DP_LANE_COUNT_EXP_BITS		order_base_2(INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS)
-#define INTEL_DP_LINK_RATE_IDX_BITS		(BITS_PER_TYPE(u8) - INTEL_DP_LANE_COUNT_EXP_BITS)
+
+#define INTEL_DP_LANE_COUNT_CONFIGS(__lane_count) \
+		(ilog2(__lane_count) + 1)
+#define INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS \
+		INTEL_DP_LANE_COUNT_CONFIGS(INTEL_DP_MAX_LANE_COUNT)
+
 #define INTEL_DP_MAX_LINK_CONFIGS		(DP_MAX_SUPPORTED_RATES * \
 						 INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS)
 		struct intel_dp_link_config_entry {
-			/* index into rates[] */
-			u8 link_rate_idx:INTEL_DP_LINK_RATE_IDX_BITS;
-			u8 lane_count_exp:INTEL_DP_LANE_COUNT_EXP_BITS;
+			u8 config_idx;
 		} configs[INTEL_DP_MAX_LINK_CONFIGS];
 	} config_table;
 
@@ -276,15 +303,25 @@ void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 	forced_params->lane_count = forced_lane_count(link_caps);
 }
 
+static int link_config_idx_to_rate_idx(int config_idx)
+{
+	return config_idx / INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS;
+}
+
+static int link_config_idx_to_lane_count_exp(int config_idx)
+{
+	return config_idx % INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS;
+}
+
 static int intel_dp_link_config_rate(const struct intel_dp_link_caps_config_table *table,
 				     const struct intel_dp_link_config_entry *lc)
 {
-	return lookup_rate(table, lc->link_rate_idx);
+	return lookup_rate(table, link_config_idx_to_rate_idx(lc->config_idx));
 }
 
 static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_entry *lc)
 {
-	return 1 << lc->lane_count_exp;
+	return 1 << link_config_idx_to_lane_count_exp(lc->config_idx);
 }
 
 static int link_config_idx_to_rate(const struct intel_dp_link_caps_config_table *table,
@@ -303,6 +340,33 @@ static int link_config_idx_to_lane_count(const struct intel_dp_link_caps_config_
 	return intel_dp_link_config_lane_count(lc);
 }
 
+/*
+ * Remap @from_pos, referring to the (row, col) point in row-major
+ * table-a with @from_cols columns per row, to the position in table-b
+ * with @to_cols columns per row referring to the same (row, col) point.
+ */
+static int remap_table_pos(int from_pos, int from_cols, int to_cols)
+{
+	int col = from_pos % from_cols;
+
+	if (WARN_ON(col >= to_cols))
+		return -1;
+
+	return from_pos / from_cols * to_cols + col;
+}
+
+static int remap_lane_stride_pos(int from_pos, int from_max_lane_count, int to_max_lane_count)
+{
+	return remap_table_pos(from_pos,
+			       INTEL_DP_LANE_COUNT_CONFIGS(from_max_lane_count),
+			       INTEL_DP_LANE_COUNT_CONFIGS(to_max_lane_count));
+}
+
+static int rate_lane_iter_pos_to_config_idx(int iter_pos, int max_lane_count)
+{
+	return remap_lane_stride_pos(iter_pos, max_lane_count, INTEL_DP_MAX_LANE_COUNT);
+}
+
 static void
 to_intel_dp_link_config(const struct intel_dp_link_caps_config_table *table,
 			int config_idx, struct intel_dp_link_config *config)
@@ -331,7 +395,7 @@ get_table_config_by_pos(const struct intel_dp_link_caps_config_table *config_tab
 
 	switch (config_order.key) {
 	case INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW:
-		*config_idx = iter_pos;
+		*config_idx = config_table->configs[iter_pos].config_idx;
 
 		break;
 	default:
@@ -783,7 +847,13 @@ static bool build_config_table(struct intel_display *display,
 	struct intel_dp_link_config_entry *lc;
 	int num_common_lane_configs;
 	int i;
-	int j;
+
+	if (drm_WARN_ON(display->drm,
+			num_rates < 1 || num_rates > ARRAY_SIZE(table->rates)))
+		return false;
+
+	if (drm_WARN_ON(display->drm, max_lane_count > INTEL_DP_MAX_LANE_COUNT))
+		return false;
 
 	if (drm_WARN_ON(display->drm, !is_power_of_2(max_lane_count)))
 		return false;
@@ -806,13 +876,15 @@ static bool build_config_table(struct intel_display *display,
 	table->num_configs = num_rates * num_common_lane_configs;
 
 	lc = &table->configs[0];
-	for (i = 0; i < num_rates; i++) {
-		for (j = 0; j < num_common_lane_configs; j++) {
-			lc->lane_count_exp = j;
-			lc->link_rate_idx = i;
+	for (i = 0; i < table->num_configs; i++) {
+		int config_idx;
 
-			lc++;
-		}
+		config_idx = rate_lane_iter_pos_to_config_idx(i, max_lane_count);
+		if (config_idx < 0)
+			return false;
+
+		lc->config_idx = config_idx;
+		lc++;
 	}
 
 	sort_r(table->configs, table->num_configs,
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 081/108] drm/i915/dp_link_caps: Simplify idx->link rate/lane count lookup
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (79 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 080/108] drm/i915/dp_link_caps: Use virtual config indexing in config table Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 082/108] drm/i915/dp_link_caps: Simplify BW order pos->config index array Imre Deak
                   ` (29 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Compute the rate and lane count for a configuration directly from its
table index, removing indirection via the thin wrapper functions.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 32 +++++--------------
 1 file changed, 8 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 0d828ad9f93a7..345419e7c0c29 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -313,31 +313,15 @@ static int link_config_idx_to_lane_count_exp(int config_idx)
 	return config_idx % INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS;
 }
 
-static int intel_dp_link_config_rate(const struct intel_dp_link_caps_config_table *table,
-				     const struct intel_dp_link_config_entry *lc)
-{
-	return lookup_rate(table, link_config_idx_to_rate_idx(lc->config_idx));
-}
-
-static int intel_dp_link_config_lane_count(const struct intel_dp_link_config_entry *lc)
-{
-	return 1 << link_config_idx_to_lane_count_exp(lc->config_idx);
-}
-
 static int link_config_idx_to_rate(const struct intel_dp_link_caps_config_table *table,
 				   int config_idx)
 {
-	const struct intel_dp_link_config_entry *lc = &table->configs[config_idx];
-
-	return intel_dp_link_config_rate(table, lc);
+	return lookup_rate(table, link_config_idx_to_rate_idx(config_idx));
 }
 
-static int link_config_idx_to_lane_count(const struct intel_dp_link_caps_config_table *table,
-					 int config_idx)
+static int link_config_idx_to_lane_count(int config_idx)
 {
-	const struct intel_dp_link_config_entry *lc = &table->configs[config_idx];
-
-	return intel_dp_link_config_lane_count(lc);
+	return 1 << link_config_idx_to_lane_count_exp(config_idx);
 }
 
 /*
@@ -372,7 +356,7 @@ to_intel_dp_link_config(const struct intel_dp_link_caps_config_table *table,
 			int config_idx, struct intel_dp_link_config *config)
 {
 	config->rate = link_config_idx_to_rate(table, config_idx);
-	config->lane_count = link_config_idx_to_lane_count(table, config_idx);
+	config->lane_count = link_config_idx_to_lane_count(config_idx);
 }
 
 static bool
@@ -798,8 +782,8 @@ void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps)
 static int intel_dp_link_config_bw(const struct intel_dp_link_caps_config_table *table,
 				   const struct intel_dp_link_config_entry *lc)
 {
-	return drm_dp_max_dprx_data_rate(intel_dp_link_config_rate(table, lc),
-					 intel_dp_link_config_lane_count(lc));
+	return drm_dp_max_dprx_data_rate(link_config_idx_to_rate(table, lc->config_idx),
+					 link_config_idx_to_lane_count(lc->config_idx));
 }
 
 static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
@@ -813,8 +797,8 @@ static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 	if (bw_a != bw_b)
 		return bw_a - bw_b;
 
-	return intel_dp_link_config_rate(table, lc_a) -
-	       intel_dp_link_config_rate(table, lc_b);
+	return link_config_idx_to_rate(table, lc_a->config_idx) -
+	       link_config_idx_to_rate(table, lc_b->config_idx);
 }
 
 static bool config_tables_match(const struct intel_dp_link_caps_config_table *table_a,
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 082/108] drm/i915/dp_link_caps: Simplify BW order pos->config index array
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (80 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 081/108] drm/i915/dp_link_caps: Simplify idx->link rate/lane count lookup Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 083/108] drm/i915/dp_link_caps: Add helper to get iteration order for a connector Imre Deak
                   ` (28 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Replace the config_idx entries with a flat position-to-index map array
in the config table, renamed to bw_order_map. The semantic remains
unchanged; the array maps BW-order positions to config indices as
before.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 59 +++++++++++--------
 1 file changed, 33 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 345419e7c0c29..685fbc34b8df9 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -103,9 +103,6 @@ struct intel_dp_link_caps {
 		 * with a fixed lane stride of
 		 * INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS.
 		 *
-		 * For now the above index is stored in struct
-		 * intel_dp_link_config_entry::config_idx.
-		 *
 		 * A configuration can be reconstructed from its index as:
 		 *
 		 *   rate_idx  = idx / INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS
@@ -126,9 +123,14 @@ struct intel_dp_link_caps {
 
 #define INTEL_DP_MAX_LINK_CONFIGS		(DP_MAX_SUPPORTED_RATES * \
 						 INTEL_DP_MAX_SUPPORTED_LANE_CONFIGS)
-		struct intel_dp_link_config_entry {
-			u8 config_idx;
-		} configs[INTEL_DP_MAX_LINK_CONFIGS];
+		/*
+		 * Indices of configurations sorted in ascending bandwidth
+		 * order.
+		 *
+		 * Each entry is an index into the virtual configuration space
+		 * described above.
+		 */
+		u8 bw_order_map[INTEL_DP_MAX_LINK_CONFIGS];
 	} config_table;
 
 	/*
@@ -379,7 +381,7 @@ get_table_config_by_pos(const struct intel_dp_link_caps_config_table *config_tab
 
 	switch (config_order.key) {
 	case INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW:
-		*config_idx = config_table->configs[iter_pos].config_idx;
+		*config_idx = config_table->bw_order_map[iter_pos];
 
 		break;
 	default:
@@ -779,26 +781,31 @@ void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps)
 	update_max_link_info(link_caps);
 }
 
-static int intel_dp_link_config_bw(const struct intel_dp_link_caps_config_table *table,
-				   const struct intel_dp_link_config_entry *lc)
+static int intel_dp_link_config_bw(const struct intel_dp_link_config *link_config)
 {
-	return drm_dp_max_dprx_data_rate(link_config_idx_to_rate(table, lc->config_idx),
-					 link_config_idx_to_lane_count(lc->config_idx));
+	return drm_dp_max_dprx_data_rate(link_config->rate, link_config->lane_count);
 }
 
 static int link_config_cmp_by_bw(const void *a, const void *b, const void *p)
 {
 	const struct intel_dp_link_caps_config_table *table = p;
-	const struct intel_dp_link_config_entry *lc_a = a;
-	const struct intel_dp_link_config_entry *lc_b = b;
-	int bw_a = intel_dp_link_config_bw(table, lc_a);
-	int bw_b = intel_dp_link_config_bw(table, lc_b);
+	struct intel_dp_link_config link_config_a;
+	struct intel_dp_link_config link_config_b;
+	u8 idx_a = *(u8 *)a;
+	u8 idx_b = *(u8 *)b;
+	int bw_a;
+	int bw_b;
+
+	to_intel_dp_link_config(table, idx_a, &link_config_a);
+	to_intel_dp_link_config(table, idx_b, &link_config_b);
+
+	bw_a = intel_dp_link_config_bw(&link_config_a);
+	bw_b = intel_dp_link_config_bw(&link_config_b);
 
 	if (bw_a != bw_b)
 		return bw_a - bw_b;
 
-	return link_config_idx_to_rate(table, lc_a->config_idx) -
-	       link_config_idx_to_rate(table, lc_b->config_idx);
+	return link_config_a.rate - link_config_b.rate;
 }
 
 static bool config_tables_match(const struct intel_dp_link_caps_config_table *table_a,
@@ -817,8 +824,8 @@ static bool config_tables_match(const struct intel_dp_link_caps_config_table *ta
 		   table_a->num_rates * sizeof(table_a->rates[0])))
 		return false;
 
-	if (memcmp(table_a->configs, table_b->configs,
-		   table_a->num_configs * sizeof(table_a->configs[0])))
+	if (memcmp(table_a->bw_order_map, table_b->bw_order_map,
+		   table_a->num_configs * sizeof(table_a->bw_order_map[0])))
 		return false;
 
 	return true;
@@ -828,8 +835,8 @@ static bool build_config_table(struct intel_display *display,
 			       const int *rates, int num_rates, int max_lane_count,
 			       struct intel_dp_link_caps_config_table *table)
 {
-	struct intel_dp_link_config_entry *lc;
 	int num_common_lane_configs;
+	u8 *bw_order_map;
 	int i;
 
 	if (drm_WARN_ON(display->drm,
@@ -848,7 +855,7 @@ static bool build_config_table(struct intel_display *display,
 	num_common_lane_configs = ilog2(max_lane_count) + 1;
 
 	if (drm_WARN_ON(display->drm, num_rates * num_common_lane_configs >
-				    ARRAY_SIZE(table->configs)))
+				    ARRAY_SIZE(table->bw_order_map)))
 		return false;
 
 	memset(table, 0, sizeof(*table));
@@ -859,7 +866,7 @@ static bool build_config_table(struct intel_display *display,
 
 	table->num_configs = num_rates * num_common_lane_configs;
 
-	lc = &table->configs[0];
+	bw_order_map = table->bw_order_map;
 	for (i = 0; i < table->num_configs; i++) {
 		int config_idx;
 
@@ -867,12 +874,12 @@ static bool build_config_table(struct intel_display *display,
 		if (config_idx < 0)
 			return false;
 
-		lc->config_idx = config_idx;
-		lc++;
+		*bw_order_map = config_idx;
+		bw_order_map++;
 	}
 
-	sort_r(table->configs, table->num_configs,
-	       sizeof(table->configs[0]),
+	sort_r(table->bw_order_map, table->num_configs,
+	       sizeof(table->bw_order_map[0]),
 	       link_config_cmp_by_bw, NULL,
 	       table);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 083/108] drm/i915/dp_link_caps: Add helper to get iteration order for a connector
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (81 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 082/108] drm/i915/dp_link_caps: Simplify BW order pos->config index array Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 084/108] drm/i915/dp_link_caps: Add reset and merge update modes Imre Deak
                   ` (27 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add a helper to select the link configuration iteration order for a
connector. This keeps the connector-specific ordering policy in the
link caps module and allows using the same ordering during configuration
computation and fallback.

Also add the rate/lane order key, used by SST connectors, and descending
order direction, used for maximum-configuration-first policies such as
intel_dp::use_max_params and MST.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 57 +++++++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h | 10 ++++
 2 files changed, 67 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 685fbc34b8df9..d7ffb8e8e9cf9 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -170,6 +170,52 @@ struct intel_dp_link_caps {
 	struct intel_dp_link_config max_limits;
 };
 
+static enum intel_dp_link_caps_config_order_key
+order_key_for_connector(struct intel_connector *connector)
+{
+	if (connector->mst.dp)
+		return INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW;
+	else
+		return INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_RATE_LANE;
+}
+
+static enum intel_dp_link_caps_config_order_direction
+order_dir_for_connector(struct intel_connector *connector)
+{
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+
+	if (connector->mst.dp || intel_dp->use_max_params)
+		return INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_DESC;
+	else
+		return INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_ASC;
+}
+
+/**
+ * intel_dp_link_caps_config_order_for_connector - get config iteration order
+ * @connector: connector to get the iteration order for
+ *
+ * Return the configuration ordering to use for @connector.
+ *
+ * The returned order is suitable for the configuration iterators.
+ *
+ * See also:
+ *  - @for_each_dp_link_config()
+ *  - @for_each_dp_link_config_idx()
+ *
+ * Return:
+ * Configuration ordering for @connector.
+ */
+struct intel_dp_link_caps_config_order
+intel_dp_link_caps_config_order_for_connector(struct intel_connector *connector)
+{
+	struct intel_dp_link_caps_config_order order = {
+		.key = order_key_for_connector(connector),
+		.dir = order_dir_for_connector(connector)
+	};
+
+	return order;
+}
+
 static int lookup_rate(const struct intel_dp_link_caps_config_table *table, int index)
 {
 	if (WARN_ON(index < 0 || index >= table->num_rates))
@@ -373,6 +419,9 @@ get_table_config_by_pos(const struct intel_dp_link_caps_config_table *config_tab
 	switch (config_order.dir) {
 	case INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_ASC:
 		break;
+	case INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_DESC:
+		iter_pos = config_table->num_configs - 1 - iter_pos;
+		break;
 	default:
 		MISSING_CASE(config_order.dir);
 
@@ -384,12 +433,20 @@ get_table_config_by_pos(const struct intel_dp_link_caps_config_table *config_tab
 		*config_idx = config_table->bw_order_map[iter_pos];
 
 		break;
+	case INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_RATE_LANE:
+		*config_idx =
+			rate_lane_iter_pos_to_config_idx(iter_pos,
+							 config_table->max_lane_count);
+		break;
 	default:
 		MISSING_CASE(config_order.key);
 
 		goto out_fail;
 	}
 
+	if (*config_idx < 0)
+		goto out_fail;
+
 	to_intel_dp_link_config(config_table, *config_idx, config);
 
 	return true;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 6599325932ab6..ff737dbb7f4ad 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -15,6 +15,8 @@ struct intel_dp_link_config;
  * enum intel_dp_link_caps_config_order_key - key used to order configurations
  * @INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW:
  *   Order configurations by bandwidth, then by link rate.
+ * @INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_RATE_LANE:
+ *   Order configurations by link rate, then by lane count.
  * @INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_NUM:
  *   Number of ordering keys.
  *
@@ -27,6 +29,7 @@ struct intel_dp_link_config;
  */
 enum intel_dp_link_caps_config_order_key {
 	INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW,
+	INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_RATE_LANE,
 
 	INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_NUM
 };
@@ -35,6 +38,8 @@ enum intel_dp_link_caps_config_order_key {
  * enum intel_dp_link_caps_config_order_direction - iteration direction
  * @INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_ASC:
  *   Iterate in ascending order according to the selected ordering key.
+ * @INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_DESC:
+ *   Iterate in descending order according to the selected ordering key.
  * @INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_NUM:
  *   Number of ordering directions.
  *
@@ -46,6 +51,7 @@ enum intel_dp_link_caps_config_order_key {
  */
 enum intel_dp_link_caps_config_order_direction {
 	INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_ASC,
+	INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_DESC,
 
 	INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_NUM
 };
@@ -62,6 +68,7 @@ enum intel_dp_link_caps_config_order_direction {
  * Describes an iteration order for link configurations.
  *
  * See also:
+ *  - intel_dp_link_caps_config_order_for_connector()
  *  - intel_dp_link_caps_get_config_by_pos()
  */
 struct intel_dp_link_caps_config_order {
@@ -89,6 +96,9 @@ enum intel_dp_link_caps_config_match_type {
 	INTEL_DP_LINK_CAPS_CONFIG_MATCH_FUZZY_RATE,
 };
 
+struct intel_dp_link_caps_config_order
+intel_dp_link_caps_config_order_for_connector(struct intel_connector *connector);
+
 int intel_dp_link_caps_common_rate(struct intel_dp_link_caps *link_caps, int index);
 int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate);
 int intel_dp_link_caps_max_common_rate(struct intel_dp_link_caps *link_caps);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 084/108] drm/i915/dp_link_caps: Add reset and merge update modes
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (82 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 083/108] drm/i915/dp_link_caps: Add helper to get iteration order for a connector Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 085/108] drm/i915/dp_link_caps: Add mask for disabled link configurations Imre Deak
                   ` (26 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add update modes to intel_dp_link_caps_update() to distinguish between
resetting link capability state for a new sink and merging newly read
capabilities into existing state.

Reset mode is used when a new sink is connected, after
intel_dp_reset_link_params() is called. Merge mode is used when an
already connected sink reports a capability change, preserving disabled
configurations that are still present after the update.

This patch only implements the reset mode, by resetting the maximum link
limits, the logic for merge behavior will be added by follow-up changes.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       |  9 ++++++++-
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 15 ++++++++++++++-
 .../gpu/drm/i915/display/intel_dp_link_caps.h | 19 ++++++++++++++++++-
 3 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 875e835848c39..0255aeff84b85 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -686,14 +686,21 @@ static void intel_dp_get_common_rates(struct intel_dp *intel_dp,
 /* Return %true if any supported or maximum link param changed. */
 static bool intel_dp_set_common_link_params(struct intel_dp *intel_dp)
 {
+	enum intel_dp_link_caps_update_mode update_mode =
+		INTEL_DP_LINK_CAPS_UPDATE_MERGE;
 	int num_common_rates;
 	int common_rates[DP_MAX_SUPPORTED_RATES];
 	bool link_params_changed = false;
 
 	intel_dp_get_common_rates(intel_dp, common_rates, &num_common_rates);
+
+	if (intel_dp->reset_link_params)
+		update_mode = INTEL_DP_LINK_CAPS_UPDATE_RESET;
+
 	if (intel_dp_link_caps_update(intel_dp->link.caps,
 				      common_rates, num_common_rates,
-				      intel_dp_max_common_lane_count(intel_dp)))
+				      intel_dp_max_common_lane_count(intel_dp),
+				      update_mode))
 		link_params_changed = true;
 
 	return link_params_changed;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index d7ffb8e8e9cf9..9c0ad5cf87259 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -949,10 +949,19 @@ static bool build_config_table(struct intel_display *display,
  * @rates: supported common link rates
  * @num_rates: number of entries in @rates
  * @max_lane_count: supported maximum lane count
+ * @update_mode: update mode controlling reset vs. merge behavior
  *
  * Rebuild the supported link configuration state from @rates and
  * @max_lane_count.
  *
+ * If @update_mode is %INTEL_DP_LINK_CAPS_UPDATE_RESET, reset the
+ * maximum link limits to the maximum supported rate and lane count, and
+ * re-enable all configurations.
+ *
+ * If @update_mode is %INTEL_DP_LINK_CAPS_UPDATE_MERGE, preserve the
+ * disabled state of configurations that were disabled before the update
+ * and are still present after it.
+ *
  * Configuration indices are not stable across calls to this function, so
  * callers should not cache such indices and masks built from them across
  * updates via this function.
@@ -972,7 +981,8 @@ static bool build_config_table(struct intel_display *display,
  * - %true if the supported link parameters have changed, %false otherwise.
  */
 bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
-			       const int *rates, int num_rates, int max_lane_count)
+			       const int *rates, int num_rates, int max_lane_count,
+			       enum intel_dp_link_caps_update_mode update_mode)
 {
 	struct intel_dp *intel_dp = link_caps->dp;
 	struct intel_display *display = to_intel_display(intel_dp);
@@ -989,6 +999,9 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 
 	link_caps->config_table = new_table;
 
+	if (update_mode == INTEL_DP_LINK_CAPS_UPDATE_RESET)
+		reset_max_link_limits_no_update(link_caps);
+
 	/*
 	 * A failure could be only due to a bug, the update function handles
 	 * that case by removing all restriction and resetting the max limit
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index ff737dbb7f4ad..ff66056adc9b5 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -96,6 +96,22 @@ enum intel_dp_link_caps_config_match_type {
 	INTEL_DP_LINK_CAPS_CONFIG_MATCH_FUZZY_RATE,
 };
 
+/**
+ * enum intel_dp_link_caps_update_mode - intel_dp_link_caps_update() mode
+ * @INTEL_DP_LINK_CAPS_UPDATE_RESET:
+ *	Reset max link limits and re-enable all configurations.
+ * @INTEL_DP_LINK_CAPS_UPDATE_MERGE:
+ *	Preserve the disabled state of configurations that remain present
+ *	after the update.
+ *
+ * Controls how intel_dp_link_caps_update() applies newly read sink
+ * capabilities to the existing link capability state.
+ */
+enum intel_dp_link_caps_update_mode {
+	INTEL_DP_LINK_CAPS_UPDATE_RESET,
+	INTEL_DP_LINK_CAPS_UPDATE_MERGE,
+};
+
 struct intel_dp_link_caps_config_order
 intel_dp_link_caps_config_order_for_connector(struct intel_connector *connector);
 
@@ -127,7 +143,8 @@ bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
 void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps);
 
 bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
-			       const int *rates, int num_rates, int max_lane_count);
+			       const int *rates, int num_rates, int max_lane_count,
+			       enum intel_dp_link_caps_update_mode update_mode);
 void intel_dp_link_caps_reset(struct intel_dp_link_caps *link_caps);
 
 void intel_dp_link_caps_debugfs_add(struct intel_connector *connector);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 085/108] drm/i915/dp_link_caps: Add mask for disabled link configurations
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (83 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 084/108] drm/i915/dp_link_caps: Add reset and merge update modes Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 086/108] drm/i915/dp_link_caps: Add link configuration iterators Imre Deak
                   ` (25 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add a disabled configuration mask to the link capability state.

This allows fallback code to disable only the configuration that failed
link training, instead of constraining later modesets via maximum link
rate or lane count. The code only needs to exclude the failed
configuration from the allowed set; all other supported configurations
remain available.

Use the mask when computing the allowed configuration set and when
validating maximum link limits, so disabled configurations are filtered
consistently.

Follow-up changes will preserve the mask across merge updates, clear it
on reset updates, and switch the fallback code to disable individual
configurations through this mask.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 45 ++++++++++++++++---
 1 file changed, 40 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 9c0ad5cf87259..7a4a8ec8fdf40 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -131,8 +131,41 @@ struct intel_dp_link_caps {
 		 * described above.
 		 */
 		u8 bw_order_map[INTEL_DP_MAX_LINK_CONFIGS];
+
+		/*
+		 * Mask of configurations disabled for the current sink
+		 * connection.
+		 *
+		 * Each bit corresponds to a configuration index in the
+		 * virtual configuration space. The same index space is used
+		 * by bw_order_map[] and all configuration masks, including
+		 * the allowed-configuration mask.
+		 *
+		 * Users disable configurations by setting bits in this mask.
+		 * Bits are cleared only internally in the following cases:
+		 * - sink disconnect
+		 * - forcing a link rate or lane count
+		 * - recovery from invalid cases after a sink capability
+		 *   change or internal inconsistencies that would otherwise
+		 *   leave no allowed configuration
+		 * - after intel_dp_link_caps_update(UPDATE_RESET) or
+		 *   intel_dp_link_caps_reset() is called
+		 *
+		 * In all these cases, all configurations are re-enabled.
+		 */
+		u32 disabled_config_mask;
 	} config_table;
 
+	/*
+	 * Allowed configurations are the supported configurations defined by
+	 * config_table.rates and config_table.max_lane_count, constrained by
+	 * config_table.disabled_config_mask and the forced_params and
+	 * max_limits values below.
+	 *
+	 * See intel_dp_link_caps_allowed_config_mask() for the mask of these
+	 * configurations.
+	 */
+
 	/*
 	 * Forced parameters requested via debugfs. Remains set across sink
 	 * disconnects.
@@ -160,15 +193,15 @@ struct intel_dp_link_caps {
 	 * max_limits.lane_count) tuple itself may not be an allowed
 	 * configuration.
 	 *
-	 * TODO: List the events that reset max_limits, after the
-	 * introduction of disabled_config_mask.
-	 *
 	 * TODO: Make max_limits reflect the maximum of the allowed
 	 * configurations at all times and stop making it settable via the
 	 * API, removing it as a constraint on the allowed configurations.
 	 */
 	struct intel_dp_link_config max_limits;
 };
+/* Assert that config masks have enough bits. */
+static_assert(BITS_PER_TYPE(u32) >=
+	      ARRAY_SIZE(((struct intel_dp_link_caps *)NULL)->config_table.bw_order_map));
 
 static enum intel_dp_link_caps_config_order_key
 order_key_for_connector(struct intel_connector *connector)
@@ -511,7 +544,8 @@ static u32 calc_allowed_config_mask(struct intel_dp_link_caps *link_caps,
 u32 intel_dp_link_caps_get_allowed_config_mask(struct intel_dp_link_caps *link_caps)
 {
 	struct intel_dp_link_config forced_params;
-	u32 disabled_mask = 0;	/* get the mask from link_caps. */
+	u32 disabled_mask =
+		link_caps->config_table.disabled_config_mask;
 
 	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
 
@@ -777,7 +811,8 @@ static bool max_link_limits_valid(struct intel_dp_link_caps *link_caps,
 				  const struct intel_dp_link_config *max_link_limits)
 {
 	struct intel_dp_link_config forced_params;
-	u32 disabled_mask = 0;	/* get the mask from link_caps. */
+	u32 disabled_mask =
+		link_caps->config_table.disabled_config_mask;
 	u32 allowed_mask;
 
 	intel_dp_link_caps_get_forced_params(link_caps, &forced_params);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 086/108] drm/i915/dp_link_caps: Add link configuration iterators
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (84 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 085/108] drm/i915/dp_link_caps: Add mask for disabled link configurations Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 087/108] drm/i915/dp_link_caps: Preserve disabled config mask during merge update Imre Deak
                   ` (24 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add helpers to iterate over a selected set of link configurations in a
given order.

Use the new iterators when computing the allowed configuration mask and
the maximum link limits, replacing open-coded walks over the
configuration table.

Use the native rate/lane iteration order.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 29 +++++-----
 .../gpu/drm/i915/display/intel_dp_link_caps.h | 54 +++++++++++++++++++
 2 files changed, 68 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 7a4a8ec8fdf40..eada84b0d1e39 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -203,6 +203,16 @@ struct intel_dp_link_caps {
 static_assert(BITS_PER_TYPE(u32) >=
 	      ARRAY_SIZE(((struct intel_dp_link_caps *)NULL)->config_table.bw_order_map));
 
+static struct intel_dp_link_caps_config_order rate_lane_asc_config_order(void)
+{
+	struct intel_dp_link_caps_config_order order = {
+		.key = INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_RATE_LANE,
+		.dir = INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_ASC
+	};
+
+	return order;
+}
+
 static enum intel_dp_link_caps_config_order_key
 order_key_for_connector(struct intel_connector *connector)
 {
@@ -496,17 +506,12 @@ static u32 calc_allowed_config_mask(struct intel_dp_link_caps *link_caps,
 				    const struct intel_dp_link_config *max_limits,
 				    const struct intel_dp_link_config *forced_params)
 {
-	struct intel_dp_link_caps_config_table *table = &link_caps->config_table;
 	struct intel_dp_link_config config;
 	u32 allowed_mask = 0;
 	int config_idx;
 
-	for (config_idx = 0; config_idx < table->num_configs; config_idx++) {
-		if (BIT(config_idx) & disabled_config_mask)
-			continue;
-
-		to_intel_dp_link_config(table, config_idx, &config);
-
+	for_each_dp_link_config_idx(link_caps, rate_lane_asc_config_order(),
+				    ~disabled_config_mask, &config, &config_idx) {
 		if (forced_params->rate &&
 		    forced_params->rate != config.rate)
 			continue;
@@ -706,18 +711,12 @@ static void reset_all_restrictions_no_update(struct intel_dp_link_caps *link_cap
 static void compute_max_link_limits(struct intel_dp_link_caps *link_caps,
 				    struct intel_dp_link_config *max_link_limits)
 {
-	struct intel_dp_link_caps_config_table *table = &link_caps->config_table;
 	u32 allowed_mask = intel_dp_link_caps_get_allowed_config_mask(link_caps);
 	struct intel_dp_link_config max_config = {};
 	struct intel_dp_link_config link_config;
-	int config_idx;
-
-	for (config_idx = 0; config_idx < table->num_configs; config_idx++) {
-		if (!(BIT(config_idx) & allowed_mask))
-			continue;
-
-		to_intel_dp_link_config(table, config_idx, &link_config);
 
+	for_each_dp_link_config(link_caps, rate_lane_asc_config_order(), allowed_mask,
+				&link_config) {
 		max_config.rate = max(max_config.rate,
 				      link_config.rate);
 		max_config.lane_count = max(max_config.lane_count,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index ff66056adc9b5..939586c74e644 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -4,6 +4,7 @@
 #ifndef __INTEL_DP_LINK_CAPS_H__
 #define __INTEL_DP_LINK_CAPS_H__
 
+#include <linux/bitops.h>
 #include <linux/types.h>
 
 struct intel_connector;
@@ -70,6 +71,8 @@ enum intel_dp_link_caps_config_order_direction {
  * See also:
  *  - intel_dp_link_caps_config_order_for_connector()
  *  - intel_dp_link_caps_get_config_by_pos()
+ *  - for_each_dp_link_config_idx()
+ *  - for_each_dp_link_config()
  */
 struct intel_dp_link_caps_config_order {
 	enum intel_dp_link_caps_config_order_key key;
@@ -112,6 +115,57 @@ enum intel_dp_link_caps_update_mode {
 	INTEL_DP_LINK_CAPS_UPDATE_MERGE,
 };
 
+/* Avoid "address is never NULL" warning in macro */
+static inline int *intel_dp_link_caps_first_non_null(int *p1, int *p2)
+{
+	return p1 ? p1 : p2;
+}
+
+/**
+ * for_each_dp_link_config_idx_iter - iterate selected configurations and indices
+ * @__link_caps:
+ *   &struct intel_dp_link_caps being queried
+ * @__iter_fn:
+ *   Iterator function called to get the config and config idx at a given
+ *   position
+ * @__config_order:
+ *   &struct intel_dp_link_caps_config_order describing the
+ *   iteration order
+ * @__config_mask:
+ *   mask of configuration indices to visit
+ * @__config:
+ *   pointer to &struct intel_dp_link_config filled for each match
+ * @__config_idx:
+ *   optional pointer to the configuration index
+ *
+ * Iterate the configurations selected by @__config_mask in the order described
+ * by @__config_order.
+ *
+ * The configuration mask uses the canonical configuration indexing shared by
+ * the whole API.
+ *
+ * This iterator calls intel_dp_link_caps_get_config_by_pos() internally, so the
+ * same locking rules apply: the caller must serialize iteration against
+ * concurrent updates and concurrent queries.
+ */
+#define for_each_dp_link_config_idx_iter(__link_caps, __iter_fn, __config_order, __config_mask, \
+					 __config, __config_idx) \
+	for (int __iter_pos = 0, \
+	     __iter_config_idx, \
+	     *__config_idx_p = intel_dp_link_caps_first_non_null((__config_idx), &(__iter_config_idx)); \
+	     (__iter_fn)((__link_caps), (__config_order), (__iter_pos), (__config), (__config_idx_p)); \
+	     (__iter_pos)++) \
+	     for_each_if((__config_mask) & BIT(*(__config_idx_p)))
+
+#define for_each_dp_link_config_idx(__link_caps, __config_order, __config_mask, \
+				    __config, __config_idx) \
+	for_each_dp_link_config_idx_iter(__link_caps, intel_dp_link_caps_get_config_by_pos, \
+					 __config_order, __config_mask, __config, __config_idx)
+
+#define for_each_dp_link_config(__link_caps, __config_order, __config_mask, __config) \
+	for_each_dp_link_config_idx((__link_caps), (__config_order), (__config_mask), \
+				    (__config), NULL)
+
 struct intel_dp_link_caps_config_order
 intel_dp_link_caps_config_order_for_connector(struct intel_connector *connector);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 087/108] drm/i915/dp_link_caps: Preserve disabled config mask during merge update
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (85 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 086/108] drm/i915/dp_link_caps: Add link configuration iterators Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 088/108] drm/i915/dp_link_caps: Account for disabled configs during max link info update Imre Deak
                   ` (23 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Preserve the disabled configuration mask when merging newly read sink
capabilities into the existing link capability state.

The mask is remapped from the old configuration table to the new one by
matching rate and lane count, so configurations that remain present
after the update stay disabled. Reset updates still clear the mask.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 69 +++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index eada84b0d1e39..9b69e7642717b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -501,6 +501,11 @@ get_table_config_by_pos(const struct intel_dp_link_caps_config_table *config_tab
 	return false;
 }
 
+static u32 config_table_all_mask(void)
+{
+	return GENMASK_U32(31, 0);
+}
+
 static u32 calc_allowed_config_mask(struct intel_dp_link_caps *link_caps,
 				    u32 disabled_config_mask,
 				    const struct intel_dp_link_config *max_limits,
@@ -650,6 +655,22 @@ find_config_table_entry_pos(const struct intel_dp_link_caps_config_table *config
 	return -1;
 }
 
+static int
+find_config_table_entry_idx(const struct intel_dp_link_caps_config_table *config_table,
+			    u32 config_mask,
+			    enum intel_dp_link_caps_config_match_type match_type,
+			    const struct intel_dp_link_config *link_config)
+{
+	int iter_pos;
+
+	iter_pos = find_config_table_entry_pos(config_table, rate_lane_asc_config_order(),
+					       config_mask, match_type, link_config);
+	if (iter_pos < 0)
+		return iter_pos;
+
+	return rate_lane_iter_pos_to_config_idx(iter_pos, config_table->max_lane_count);
+}
+
 /**
  * intel_dp_link_caps_find_allowed_config_pos - find matching allowed config position
  * @link_caps: link capabilities state
@@ -977,6 +998,41 @@ static bool build_config_table(struct intel_display *display,
 	return true;
 }
 
+/*
+ * For each entry selected by @config_mask in @link_caps->config_table,
+ * look up the config with the same rate and lane count parameters in
+ * @new_table and return a mask of the matching entries there.
+ *
+ * Each bit in the returned mask indexes an entry in @new_table, so
+ * this effectively remaps @config_mask from @link_caps->config_table
+ * to @new_table.
+ */
+static u32
+remap_config_mask_to_table(struct intel_dp_link_caps *link_caps,
+			   u32 config_mask,
+			   const struct intel_dp_link_caps_config_table *new_table)
+{
+	struct intel_dp_link_config config;
+	u32 new_config_mask = 0;
+	int config_idx;
+
+	for_each_dp_link_config_idx(link_caps, rate_lane_asc_config_order(), config_mask,
+				    &config, &config_idx) {
+		int to_idx;
+
+		to_idx = find_config_table_entry_idx(new_table,
+						     config_table_all_mask(),
+						     INTEL_DP_LINK_CAPS_CONFIG_MATCH_EXACT,
+						     &config);
+		if (to_idx < 0)
+			continue;
+
+		new_config_mask |= BIT(to_idx);
+	}
+
+	return new_config_mask;
+}
+
 /**
  * intel_dp_link_caps_update - rebuild the supported link configuration state
  * @link_caps: link capabilities state
@@ -1024,14 +1080,27 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 	struct intel_dp_link_config old_max_limits =
 		link_caps->max_limits;
 	bool link_params_changed = false;
+	u32 new_disabled_mask = 0;
 
 	if (!build_config_table(display, rates, num_rates, max_lane_count, &new_table))
 		return false;
 
+	if (update_mode == INTEL_DP_LINK_CAPS_UPDATE_MERGE) {
+		/*
+		 * Get the currently disabled configs remapped to the new table,
+		 * before setting the new table.
+		 */
+		new_disabled_mask =
+			remap_config_mask_to_table(link_caps,
+						   link_caps->config_table.disabled_config_mask,
+						   &new_table);
+	}
+
 	if (!config_tables_match(&new_table, &link_caps->config_table))
 		link_params_changed = true;
 
 	link_caps->config_table = new_table;
+	link_caps->config_table.disabled_config_mask = new_disabled_mask;
 
 	if (update_mode == INTEL_DP_LINK_CAPS_UPDATE_RESET)
 		reset_max_link_limits_no_update(link_caps);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 088/108] drm/i915/dp_link_caps: Account for disabled configs during max link info update
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (86 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 087/108] drm/i915/dp_link_caps: Preserve disabled config mask during merge update Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 089/108] drm/i915/dp_link_caps: Add debugfs entry showing allowed configurations Imre Deak
                   ` (22 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Account for disabled configurations when updating the maximum link
limits.

If a capability update leaves no allowed configuration, re-enable the
minimum configuration and reset the maximum link limits so at least one
configuration remains available.

Also add a helper to look up a configuration by its canonical index,
needed by the recovery path above and by follow-up modeset state
computation logic.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 116 +++++++++++++++++-
 .../gpu/drm/i915/display/intel_dp_link_caps.h |   3 +
 2 files changed, 116 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 9b69e7642717b..d53cd416a4e09 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -595,6 +595,42 @@ bool intel_dp_link_caps_get_config_by_pos(struct intel_dp_link_caps *link_caps,
 				       config, config_idx);
 }
 
+static bool config_idx_is_valid(struct intel_dp_link_caps *link_caps, int config_idx)
+{
+	if (link_config_idx_to_rate_idx(config_idx) >=
+	    link_caps->config_table.num_rates)
+		return false;
+
+	if (link_config_idx_to_lane_count(config_idx) >
+	    link_caps->config_table.max_lane_count)
+		return false;
+
+	return true;
+}
+
+/**
+ * intel_dp_link_caps_get_config_by_idx - get config for a given config index
+ * @link_caps: link capabilities state
+ * @config_idx: configuration index to look up
+ * @config: returned link configuration
+ *
+ * Look up the link configuration identified by @config_idx.
+ *
+ * Return:
+ * - %true  if @config_idx is valid, storing the configuration in @config.
+ * - %false if @config_idx is invalid.
+ */
+bool intel_dp_link_caps_get_config_by_idx(struct intel_dp_link_caps *link_caps, int config_idx,
+					  struct intel_dp_link_config *config)
+{
+	if (!config_idx_is_valid(link_caps, config_idx))
+		return false;
+
+	to_intel_dp_link_config(&link_caps->config_table, config_idx, config);
+
+	return true;
+}
+
 static bool is_within_percent(int actual, int nominal, int percent)
 {
 	int diff = abs(actual - nominal);
@@ -714,9 +750,15 @@ static void reset_max_link_limits_no_update(struct intel_dp_link_caps *link_caps
 	set_max_link_limits_no_update(link_caps, &max_link_limits);
 }
 
+static void reset_max_link_limits_reenable_all_no_update(struct intel_dp_link_caps *link_caps)
+{
+	link_caps->config_table.disabled_config_mask = 0;
+	reset_max_link_limits_no_update(link_caps);
+}
+
 static void reset_all_restrictions_no_update(struct intel_dp_link_caps *link_caps)
 {
-	reset_max_link_limits_no_update(link_caps);
+	reset_max_link_limits_reenable_all_no_update(link_caps);
 	link_caps->forced_params = INTEL_DP_LINK_CONFIG_NULL;
 }
 
@@ -759,20 +801,41 @@ static void compute_max_link_limits(struct intel_dp_link_caps *link_caps,
  * derived from that same set, so it can only be less than or equal to
  * the stored max_limits.
  *
+ * In addition, configurations may be disabled, further constraining the
+ * allowed set.
+ *
+ * Although the allowed mask itself depends on max_limits, this update
+ * must not change the effective allowed set. The recomputed limits still
+ * cover every configuration that is currently allowed.
+ *
  * A %false return indicates an internal error (either the stored
  * max_limits was below all allowed configurations, or
  * compute_max_link_limits() returned a larger value). The caller must
  * recover by removing all restrictions.
  *
+ * A %false return may also indicate an invalid state, e.g. after a sink
+ * capability update removes rates or lane counts and leaves no allowed
+ * configuration. The caller must restore a state where at least one
+ * configuration is enabled (see sanitize_disallowed_config()).
+ *
  * Return:
  * - %true  if max_limits was updated successfully.
- * - %false if an internal error was detected.
+ * - %false if an internal error was detected or the state is invalid.
  */
 static bool update_max_link_limits(struct intel_dp_link_caps *link_caps)
 {
 	struct intel_display *display = to_intel_display(link_caps->dp);
+	u32 old_allowed_mask = intel_dp_link_caps_get_allowed_config_mask(link_caps);
 	struct intel_dp_link_config new_limits;
 
+	/*
+	 * If the stored max_limits is below all enabled and forced
+	 * configurations, the allowed mask is empty. Fail and let the caller
+	 * recover (see function documentation).
+	 */
+	if (!old_allowed_mask)
+		return false;
+
 	compute_max_link_limits(link_caps, &new_limits);
 
 	if (drm_WARN_ON(display->drm,
@@ -782,8 +845,25 @@ static bool update_max_link_limits(struct intel_dp_link_caps *link_caps)
 			new_limits.lane_count > link_caps->max_limits.lane_count))
 		return false;
 
+	/*
+	 * The allowed mask shouldn't have changed, since the bounds could
+	 * only get updated due to configs that were already disabled in the
+	 * old mask. So the new limit values will not disable any configs.
+	 */
 	link_caps->max_limits = new_limits;
 
+	/*
+	 * Updating max_limits above must not change the allowed mask.
+	 *
+	 * The old allowed mask is already constrained by the old stored max_limits.
+	 * Since the recomputed max_limits is derived from that same allowed set, it
+	 * cannot exclude any configuration that was previously allowed.
+	 */
+	if (drm_WARN_ON(display->drm,
+			old_allowed_mask !=
+			intel_dp_link_caps_get_allowed_config_mask(link_caps)))
+		return false;
+
 	return true;
 }
 
@@ -893,6 +973,34 @@ void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps)
 	update_max_link_info(link_caps);
 }
 
+static void enable_link_config_no_update(struct intel_dp_link_caps *link_caps, int config_idx)
+{
+	struct intel_display *display = to_intel_display(link_caps->dp);
+
+	if (drm_WARN_ON(display->drm, !config_idx_is_valid(link_caps, config_idx)))
+		return;
+
+	link_caps->config_table.disabled_config_mask &= ~BIT(config_idx);
+}
+
+static void sanitize_disallowed_config(struct intel_dp_link_caps *link_caps)
+{
+	struct intel_display *display = to_intel_display(link_caps->dp);
+	struct intel_dp_link_config min_link_config;
+
+	if (intel_dp_link_caps_get_allowed_config_mask(link_caps))
+		return;
+
+	drm_dbg_kms(display->drm,
+		    "No allowed link config left, force enable the minimum config\n");
+
+	if (!intel_dp_link_caps_get_config_by_idx(link_caps, 0, &min_link_config))
+		return;
+
+	enable_link_config_no_update(link_caps, 0);
+	reset_max_link_limits_no_update(link_caps);
+}
+
 static int intel_dp_link_config_bw(const struct intel_dp_link_config *link_config)
 {
 	return drm_dp_max_dprx_data_rate(link_config->rate, link_config->lane_count);
@@ -1105,6 +1213,8 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
 	if (update_mode == INTEL_DP_LINK_CAPS_UPDATE_RESET)
 		reset_max_link_limits_no_update(link_caps);
 
+	sanitize_disallowed_config(link_caps);
+
 	/*
 	 * A failure could be only due to a bug, the update function handles
 	 * that case by removing all restriction and resetting the max limit
@@ -1135,7 +1245,7 @@ bool intel_dp_link_caps_update(struct intel_dp_link_caps *link_caps,
  */
 void intel_dp_link_caps_reset(struct intel_dp_link_caps *link_caps)
 {
-	reset_max_link_limits_no_update(link_caps);
+	reset_max_link_limits_reenable_all_no_update(link_caps);
 	/* On failure the following removes all restrictions. */
 	update_max_link_info(link_caps);
 }
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 939586c74e644..009bee0f7dffb 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -180,6 +180,9 @@ void intel_dp_link_caps_get_forced_params(struct intel_dp_link_caps *link_caps,
 					  struct intel_dp_link_config *forced_params);
 u32 intel_dp_link_caps_get_allowed_config_mask(struct intel_dp_link_caps *link_caps);
 
+bool intel_dp_link_caps_get_config_by_idx(struct intel_dp_link_caps *link_caps,
+					  int config_idx,
+					  struct intel_dp_link_config *config);
 bool
 intel_dp_link_caps_get_config_by_pos(struct intel_dp_link_caps *link_caps,
 				     struct intel_dp_link_caps_config_order config_order,
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 089/108] drm/i915/dp_link_caps: Add debugfs entry showing allowed configurations
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (87 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 088/108] drm/i915/dp_link_caps: Account for disabled configs during max link info update Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 090/108] drm/i915/dp: Add a mask of valid configurations for modeset computation Imre Deak
                   ` (21 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add a debugfs entry showing the currently allowed link configurations
in the connector's iteration order.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 44 +++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index d53cd416a4e09..13d39d07b42b5 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -1510,6 +1510,47 @@ static int i915_dp_max_lane_count_show(void *data, u64 *val)
 }
 DEFINE_DEBUGFS_ATTRIBUTE(i915_dp_max_lane_count_fops, i915_dp_max_lane_count_show, NULL, "%llu\n");
 
+static int intel_dp_allowed_link_configs_show(struct seq_file *m, void *data)
+{
+	struct intel_connector *connector = to_intel_connector(m->private);
+	struct intel_display *display = to_intel_display(connector);
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp_link_config link_config;
+	int err;
+	int i;
+
+	err = drm_modeset_lock_single_interruptible(&display->drm->mode_config.connection_mutex);
+	if (err)
+		return err;
+
+	intel_dp_flush_connector_commits(connector);
+
+	i = 0;
+	for_each_dp_link_config(link_caps,
+				intel_dp_link_caps_config_order_for_connector(connector),
+				intel_dp_link_caps_get_allowed_config_mask(link_caps),
+				&link_config) {
+		seq_printf(m, "%s%dx%d",
+			   i ? " " : "",
+			   link_config.lane_count, link_config.rate);
+		i++;
+	}
+
+	drm_modeset_unlock(&display->drm->mode_config.connection_mutex);
+
+	seq_putc(m, '\n');
+
+	return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(intel_dp_allowed_link_configs);
+
+/**
+ * intel_dp_link_caps_debugfs_add - add link caps debugfs files for a connector
+ * @connector: connector to add the debugfs files for
+ *
+ * Add the link-capability debugfs files for a DP @connector.
+ */
 void intel_dp_link_caps_debugfs_add(struct intel_connector *connector)
 {
 	struct dentry *root = connector->base.debugfs_entry;
@@ -1529,6 +1570,9 @@ void intel_dp_link_caps_debugfs_add(struct intel_connector *connector)
 
 	debugfs_create_file("i915_dp_max_lane_count", 0444, root,
 			    connector, &i915_dp_max_lane_count_fops);
+
+	debugfs_create_file("intel_dp_allowed_link_configs", 0444, root,
+			    connector, &intel_dp_allowed_link_configs_fops);
 }
 
 /**
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 090/108] drm/i915/dp: Add a mask of valid configurations for modeset computation
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (88 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 089/108] drm/i915/dp_link_caps: Add debugfs entry showing allowed configurations Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 091/108] drm/i915/dp: Iterate configurations via link_caps for SST non-DSC Imre Deak
                   ` (20 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add link_config_mask to link_config_limits to track the set of allowed
link configurations during modeset state computation. Keep the existing
min/max rate and lane count limits for now, until all users are
converted to use the configuration mask.

Also add helpers to select the maximum configuration from a mask in the
connector's iteration order. This allows callers to pick the effective
maximum configuration directly from the allowed set without iterating
the configurations.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       | 60 ++++++++++++++++++-
 drivers/gpu/drm/i915/display/intel_dp.h       | 10 ++++
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 44 ++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  5 ++
 4 files changed, 116 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 0255aeff84b85..f561e984b4d4b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -2207,6 +2207,40 @@ static int align_max_compressed_bpp_x16(const struct intel_connector *connector,
 	}
 }
 
+static int
+intel_dp_get_connector_max_link_config_idx(struct intel_connector *connector,
+					   const struct link_config_limits *limits)
+{
+	struct intel_display *display = to_intel_display(connector);
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp_link_caps_config_order order =
+		intel_dp_link_caps_config_order_for_connector(connector);
+	int config_idx;
+
+	config_idx = intel_dp_link_caps_get_max_config_idx(link_caps, order.key,
+							   limits->link_config_mask);
+	drm_WARN_ON(display->drm, config_idx < 0);
+
+	return config_idx;
+}
+
+bool
+intel_dp_get_connector_max_link_config(struct intel_connector *connector,
+				       const struct link_config_limits *limits,
+				       struct intel_dp_link_config *max_link_config)
+{
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	int config_idx;
+
+	config_idx = intel_dp_get_connector_max_link_config_idx(connector, limits);
+	if (config_idx < 0)
+		return false;
+
+	return intel_dp_link_caps_get_config_by_idx(link_caps, config_idx, max_link_config);
+}
+
 /*
  * Find the max compressed BPP we can find a link configuration for. The BPPs to
  * try depend on the source (platform) and sink.
@@ -2560,6 +2594,7 @@ intel_dp_compute_config_link_bpp_limits(struct intel_connector *connector,
 		&crtc_state->hw.adjusted_mode;
 	const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
 	const struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
+	struct intel_dp_link_config max_link_config;
 	int max_link_bpp_x16;
 
 	max_link_bpp_x16 = min(crtc_state->max_link_bpp_x16,
@@ -2589,14 +2624,17 @@ intel_dp_compute_config_link_bpp_limits(struct intel_connector *connector,
 
 	limits->link.max_bpp_x16 = max_link_bpp_x16;
 
+	if (!intel_dp_get_connector_max_link_config(connector, limits, &max_link_config))
+		return false;
+
 	drm_dbg_kms(display->drm,
-		    "[ENCODER:%d:%s][CRTC:%d:%s] DP link limits: pixel clock %d kHz DSC %s max lanes %d max rate %d max pipe_bpp %d min link_bpp " FXP_Q4_FMT " max link_bpp " FXP_Q4_FMT "\n",
+		    "[ENCODER:%d:%s][CRTC:%d:%s] DP link limits: pixel clock %d kHz DSC %s max link %dx%d max pipe_bpp %d min link_bpp " FXP_Q4_FMT " max link_bpp " FXP_Q4_FMT "\n",
 		    encoder->base.base.id, encoder->base.name,
 		    crtc->base.base.id, crtc->base.name,
 		    adjusted_mode->crtc_clock,
 		    str_on_off(dsc),
-		    limits->max_lane_count,
-		    limits->max_rate,
+		    max_link_config.lane_count,
+		    max_link_config.rate,
 		    limits->pipe.max_bpp,
 		    FXP_Q4_ARGS(limits->link.min_bpp_x16),
 		    FXP_Q4_ARGS(limits->link.max_bpp_x16));
@@ -2647,10 +2685,15 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
 			       struct link_config_limits *limits)
 {
 	struct intel_display *display = to_intel_display(intel_dp);
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	bool is_mst = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DP_MST);
 	struct intel_connector *connector =
 		to_intel_connector(conn_state->connector);
 
+	/*
+	 * Remove the following min/max rate and lane count setup, once
+	 * all users are converted to use link_config_mask instead.
+	 */
 	limits->min_rate = intel_dp_min_link_rate(intel_dp);
 	limits->max_rate = intel_dp_max_link_rate(intel_dp);
 
@@ -2659,6 +2702,8 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
 	limits->min_lane_count = intel_dp_min_lane_count(intel_dp);
 	limits->max_lane_count = intel_dp_max_lane_count(intel_dp);
 
+	limits->link_config_mask = intel_dp_link_caps_get_allowed_config_mask(link_caps);
+
 	limits->pipe.min_bpp = intel_dp_min_bpp(crtc_state->output_format);
 	if (is_mst) {
 		/*
@@ -2733,8 +2778,17 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
 		 * configuration, and typically on older panels these
 		 * values correspond to the native resolution of the panel.
 		 */
+		int max_config_idx;
+
 		limits->min_lane_count = limits->max_lane_count;
 		limits->min_rate = limits->max_rate;
+
+		max_config_idx = intel_dp_get_connector_max_link_config_idx(connector,
+									    limits);
+		if (max_config_idx < 0)
+			return false;
+
+		limits->link_config_mask = BIT(max_config_idx);
 	}
 
 	intel_dp_test_compute_config(intel_dp, crtc_state, limits);
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index 6d6bb9e23ff26..bfba29ba715d5 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -22,11 +22,18 @@ struct intel_crtc_state;
 struct intel_digital_port;
 struct intel_display;
 struct intel_dp;
+struct intel_dp_link_config;
 struct intel_encoder;
 
 struct link_config_limits {
+	/*
+	 * Remove the following min/max rate and lane count limits
+	 * once all users are converted to use link_config_mask
+	 * instead.
+	 */
 	int min_rate, max_rate;
 	int min_lane_count, max_lane_count;
+	u32 link_config_mask;
 	struct {
 		/* Uncompressed DSC input or link output bpp in 1 bpp units */
 		int min_bpp, max_bpp;
@@ -138,6 +145,9 @@ int intel_dp_dsc_compute_max_bpp(const struct intel_connector *connector,
 				 u8 dsc_max_bpc);
 int intel_dp_compute_min_compressed_bpp_x16(struct intel_connector *connector,
 					    enum intel_output_format output_format);
+bool intel_dp_get_connector_max_link_config(struct intel_connector *connector,
+					    const struct link_config_limits *limits,
+					    struct intel_dp_link_config *max_link_config);
 bool intel_dp_mode_valid_with_dsc(struct intel_connector *connector,
 				  int link_clock, int lane_count,
 				  int mode_clock, int mode_hdisplay,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 13d39d07b42b5..70f72a32a9a7a 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -734,6 +734,50 @@ int intel_dp_link_caps_find_allowed_config_pos(struct intel_dp_link_caps *link_c
 					   link_config);
 }
 
+static int get_max_config(struct intel_dp_link_caps *link_caps,
+			  enum intel_dp_link_caps_config_order_key order_key,
+			  u32 config_mask,
+			  struct intel_dp_link_config *config)
+{
+	struct intel_display *display = to_intel_display(link_caps->dp);
+	struct intel_dp_link_caps_config_order order = {
+		.key = order_key,
+		.dir = INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_DESC
+	};
+	int config_idx;
+
+	for_each_dp_link_config_idx(link_caps, order, config_mask, config, &config_idx)
+		break;
+
+	drm_WARN_ON(display->drm, config_idx < 0);
+
+	return config_idx;
+}
+
+/**
+ * intel_dp_link_caps_get_max_config_idx - get the index of the maximum config
+ * @link_caps: link capabilities state
+ * @order_key: ordering key used to choose the maximum config
+ * @config_mask: mask of candidate configurations
+ *
+ * Find the maximum configuration from @config_mask according to @order_key.
+ *
+ * See also:
+ * - &enum intel_dp_link_caps_config_order_key
+ *
+ * Return:
+ * - Configuration index of the maximum matching configuration.
+ * - %-1 if no configuration is selected by @config_mask.
+ */
+int intel_dp_link_caps_get_max_config_idx(struct intel_dp_link_caps *link_caps,
+					  enum intel_dp_link_caps_config_order_key order_key,
+					  u32 config_mask)
+{
+	struct intel_dp_link_config config;
+
+	return get_max_config(link_caps, order_key, config_mask, &config);
+}
+
 static void set_max_link_limits_no_update(struct intel_dp_link_caps *link_caps,
 					  const struct intel_dp_link_config *max_link_limits)
 {
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 009bee0f7dffb..1dfd66380a96f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -27,6 +27,7 @@ struct intel_dp_link_config;
  *
  * See also:
  *  - &struct intel_dp_link_caps_config_order
+ *  - intel_dp_link_caps_get_max_config_idx()
  */
 enum intel_dp_link_caps_config_order_key {
 	INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW,
@@ -193,6 +194,10 @@ int intel_dp_link_caps_find_allowed_config_pos(struct intel_dp_link_caps *link_c
 					       enum intel_dp_link_caps_config_match_type match_type,
 					       const struct intel_dp_link_config *config);
 
+int intel_dp_link_caps_get_max_config_idx(struct intel_dp_link_caps *link_caps,
+					  enum intel_dp_link_caps_config_order_key order_key,
+					  u32 config_mask);
+
 void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
 				       struct intel_dp_link_config *max_link_limits);
 bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 091/108] drm/i915/dp: Iterate configurations via link_caps for SST non-DSC
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (89 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 090/108] drm/i915/dp: Add a mask of valid configurations for modeset computation Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 092/108] drm/i915/dp: Iterate configurations via link_caps for SST DSC Imre Deak
                   ` (19 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Use the link caps configuration iterator for DP SST link configuration
computation for non-DSC mode. This is a step towards unifying
configuration selection and iteration across connector types and between
compute and fallback paths.

The iteration preserves the DP SST connector rate/lane ordering used by
the current code.

This also allows removing the now unused common rate count helper.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 47 ++++++++++++-------------
 1 file changed, 22 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index f561e984b4d4b..bec78ddad7f09 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -1758,43 +1758,40 @@ intel_dp_compute_link_config_wide(struct intel_dp *intel_dp,
 				  const struct drm_connector_state *conn_state,
 				  const struct link_config_limits *limits)
 {
+	struct intel_connector *connector = to_intel_connector(conn_state->connector);
+	int bpp, clock = intel_dp_mode_clock(pipe_config, conn_state);
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
-	int bpp, i, lane_count, clock = intel_dp_mode_clock(pipe_config, conn_state);
-	int link_rate, link_avail;
+	struct intel_dp_link_caps_config_order order =
+		intel_dp_link_caps_config_order_for_connector(connector);
+	int link_avail;
 
 	for (bpp = fxp_q4_to_int(limits->link.max_bpp_x16);
 	     bpp >= fxp_q4_to_int(limits->link.min_bpp_x16);
 	     bpp -= 2 * 3) {
 		int link_bpp_x16 =
 			intel_dp_output_format_link_bpp_x16(pipe_config->output_format, bpp);
+		struct intel_dp_link_config link_config;
 
-		for (i = 0; i < intel_dp_link_caps_num_common_rates(intel_dp->link.caps); i++) {
-			link_rate = intel_dp_link_caps_common_rate(link_caps, i);
-			if (link_rate < limits->min_rate ||
-			    link_rate > limits->max_rate)
-				continue;
-
-			for (lane_count = limits->min_lane_count;
-			     lane_count <= limits->max_lane_count;
-			     lane_count <<= 1) {
-				const struct drm_display_mode *adjusted_mode =
+		for_each_dp_link_config(link_caps, order, limits->link_config_mask, &link_config) {
+			const struct drm_display_mode *adjusted_mode =
 					&pipe_config->hw.adjusted_mode;
-				int mode_rate =
-					intel_dp_link_required(link_rate, lane_count,
-							       clock, adjusted_mode->hdisplay,
-							       link_bpp_x16, 0);
+			int mode_rate;
 
-				link_avail = intel_dp_max_link_data_rate(intel_dp,
-									 link_rate,
-									 lane_count);
+			mode_rate = intel_dp_link_required(link_config.rate,
+							   link_config.lane_count,
+							   clock, adjusted_mode->hdisplay,
+							   link_bpp_x16, 0);
 
-				if (mode_rate <= link_avail) {
-					pipe_config->lane_count = lane_count;
-					pipe_config->pipe_bpp = bpp;
-					pipe_config->port_clock = link_rate;
+			link_avail = intel_dp_max_link_data_rate(intel_dp,
+								 link_config.rate,
+								 link_config.lane_count);
 
-					return 0;
-				}
+			if (mode_rate <= link_avail) {
+				pipe_config->lane_count = link_config.lane_count;
+				pipe_config->pipe_bpp = bpp;
+				pipe_config->port_clock = link_config.rate;
+
+				return 0;
 			}
 		}
 	}
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 092/108] drm/i915/dp: Iterate configurations via link_caps for SST DSC
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (90 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 091/108] drm/i915/dp: Iterate configurations via link_caps for SST non-DSC Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 093/108] drm/i915/dp: Use link caps for eDP DSC config selection Imre Deak
                   ` (18 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Use the link caps configuration iterator for DP SST link configuration
computation for DSC mode. This is a step towards unifying configuration
selection and iteration across connector types and between compute and
fallback paths.

The iteration preserves the DP SST connector rate/lane ordering used by
the current code.

This also allows removing the now unused common rate count helper.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       | 90 +++++++++----------
 .../gpu/drm/i915/display/intel_dp_link_caps.c |  5 --
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  1 -
 3 files changed, 42 insertions(+), 54 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index bec78ddad7f09..62fed6de83b12 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -1990,60 +1990,54 @@ static int dsc_compute_link_config(struct intel_dp *intel_dp,
 				   const struct link_config_limits *limits,
 				   int dsc_bpp_x16)
 {
-	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	const struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode;
-	int link_rate, lane_count;
-	int i;
+	struct intel_connector *connector = to_intel_connector(conn_state->connector);
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp_link_caps_config_order order =
+		intel_dp_link_caps_config_order_for_connector(connector);
+	struct intel_dp_link_config link_config;
 
-	for (i = 0; i < intel_dp_link_caps_num_common_rates(intel_dp->link.caps); i++) {
-		link_rate = intel_dp_link_caps_common_rate(link_caps, i);
-		if (link_rate < limits->min_rate || link_rate > limits->max_rate)
-			continue;
+	for_each_dp_link_config(link_caps, order, limits->link_config_mask, &link_config) {
+		/*
+		 * FIXME: intel_dp_mtp_tu_compute_config() requires
+		 * ->lane_count and ->port_clock set before we know
+		 * they'll work. If we end up failing altogether,
+		 * they'll remain in crtc state. This shouldn't matter,
+		 * as we'd then bail out from compute config, but it's
+		 * just ugly.
+		 */
+		pipe_config->lane_count = link_config.lane_count;
+		pipe_config->port_clock = link_config.rate;
 
-		for (lane_count = limits->min_lane_count;
-		     lane_count <= limits->max_lane_count;
-		     lane_count <<= 1) {
+		if (drm_dp_is_uhbr_rate(link_config.rate)) {
+			int ret;
 
-			/*
-			 * FIXME: intel_dp_mtp_tu_compute_config() requires
-			 * ->lane_count and ->port_clock set before we know
-			 * they'll work. If we end up failing altogether,
-			 * they'll remain in crtc state. This shouldn't matter,
-			 * as we'd then bail out from compute config, but it's
-			 * just ugly.
-			 */
-			pipe_config->lane_count = lane_count;
-			pipe_config->port_clock = link_rate;
+			ret = intel_dp_mtp_tu_compute_config(intel_dp,
+							     pipe_config,
+							     conn_state,
+							     dsc_bpp_x16,
+							     dsc_bpp_x16,
+							     0, true);
+			if (ret)
+				continue;
+		} else {
+			unsigned long bw_overhead_flags =
+				pipe_config->fec_enable ? DRM_DP_BW_OVERHEAD_FEC : 0;
+			int line_slice_count =
+				intel_dsc_line_slice_count(&pipe_config->dsc.slice_config);
 
-			if (drm_dp_is_uhbr_rate(link_rate)) {
-				int ret;
-
-				ret = intel_dp_mtp_tu_compute_config(intel_dp,
-								     pipe_config,
-								     conn_state,
-								     dsc_bpp_x16,
-								     dsc_bpp_x16,
-								     0, true);
-				if (ret)
-					continue;
-			} else {
-				unsigned long bw_overhead_flags =
-					pipe_config->fec_enable ? DRM_DP_BW_OVERHEAD_FEC : 0;
-				int line_slice_count =
-					intel_dsc_line_slice_count(&pipe_config->dsc.slice_config);
-
-				if (!is_bw_sufficient_for_dsc_config(intel_dp,
-								     link_rate, lane_count,
-								     adjusted_mode->crtc_clock,
-								     adjusted_mode->hdisplay,
-								     line_slice_count,
-								     dsc_bpp_x16,
-								     bw_overhead_flags))
-					continue;
-			}
-
-			return 0;
+			if (!is_bw_sufficient_for_dsc_config(intel_dp,
+							     link_config.rate,
+							     link_config.lane_count,
+							     adjusted_mode->crtc_clock,
+							     adjusted_mode->hdisplay,
+							     line_slice_count,
+							     dsc_bpp_x16,
+							     bw_overhead_flags))
+				continue;
 		}
+
+		return 0;
 	}
 
 	return -EINVAL;
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 70f72a32a9a7a..2ec55856636f5 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -331,11 +331,6 @@ int intel_dp_link_caps_max_common_rate(struct intel_dp_link_caps *link_caps)
 	return intel_dp_link_caps_common_rate(link_caps, table->num_rates - 1);
 }
 
-int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps)
-{
-	return link_caps->config_table.num_rates;
-}
-
 /**
  * intel_dp_link_caps_all_common_rates - get all common link rates
  * @link_caps: link capabilities state
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 1dfd66380a96f..a907b99cd4cf9 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -173,7 +173,6 @@ intel_dp_link_caps_config_order_for_connector(struct intel_connector *connector)
 int intel_dp_link_caps_common_rate(struct intel_dp_link_caps *link_caps, int index);
 int intel_dp_link_caps_common_rate_idx(struct intel_dp_link_caps *link_caps, int rate);
 int intel_dp_link_caps_max_common_rate(struct intel_dp_link_caps *link_caps);
-int intel_dp_link_caps_num_common_rates(struct intel_dp_link_caps *link_caps);
 void intel_dp_link_caps_all_common_rates(struct intel_dp_link_caps *link_caps,
 					 const int **rates, int *num_rates);
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 093/108] drm/i915/dp: Use link caps for eDP DSC config selection
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (91 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 092/108] drm/i915/dp: Iterate configurations via link_caps for SST DSC Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 094/108] drm/i915/dp_mst: Use link caps for non-DSC " Imre Deak
                   ` (17 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Use the link caps helper to select the maximum eDP link configuration
for DSC computation, instead of using the separate max rate and lane
count limits, which may not form a valid configuration after individual
configs are disabled by fallback.

This is a step towards unifying configuration selection and iteration
across connector types and between compute and fallback paths.

The state computation should likely consider all allowed configurations,
as noted in the code comment; for now keep the existing eDP DSC behavior
of selecting the maximum configuration determined by the eDP connector
rate / lane config iteration order.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index 62fed6de83b12..c33209ec7782f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -2243,7 +2243,7 @@ static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp,
 				      int pipe_bpp)
 {
 	struct intel_display *display = to_intel_display(intel_dp);
-	const struct intel_connector *connector = to_intel_connector(conn_state->connector);
+	struct intel_connector *connector = to_intel_connector(conn_state->connector);
 	int min_bpp_x16, max_bpp_x16, bpp_step_x16;
 	int bpp_x16;
 	int ret;
@@ -2255,8 +2255,19 @@ static int dsc_compute_compressed_bpp(struct intel_dp *intel_dp,
 	max_bpp_x16 = align_max_compressed_bpp_x16(connector, pipe_config->output_format,
 						   pipe_bpp, max_bpp_x16);
 	if (intel_dp_is_edp(intel_dp)) {
-		pipe_config->port_clock = limits->max_rate;
-		pipe_config->lane_count = limits->max_lane_count;
+		struct intel_dp_link_config max_link_config;
+
+		/*
+		 * FIXME: Clarify why eDP does not use the regular SST BW
+		 * check and instead always uses the maximum link config,
+		 * regardless of intel_dp::use_max_params. Then unify this eDP
+		 * path with the regular DP path.
+		 */
+		if (!intel_dp_get_connector_max_link_config(connector, limits, &max_link_config))
+			return -EINVAL;
+
+		pipe_config->port_clock = max_link_config.rate;
+		pipe_config->lane_count = max_link_config.lane_count;
 
 		pipe_config->dsc.compressed_bpp_x16 = max_bpp_x16;
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 094/108] drm/i915/dp_mst: Use link caps for non-DSC config selection
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (92 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 093/108] drm/i915/dp: Use link caps for eDP DSC config selection Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 095/108] drm/i915/dp_mst: Use link caps for MST DSC " Imre Deak
                   ` (16 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Use the link caps helper to select the maximum MST link configuration
for non-DSC computation, instead of using the separate max rate and lane
count limits, which may not form a valid configuration after individual
configs are disabled by fallback.

This is a step towards unifying configuration selection and iteration
across connector types and between compute and fallback paths.

In some cases all configurations should be considered, as noted in the
code comment; for now keep the existing behavior of selecting the
maximum bandwidth configuration as determined by the MST connector's BW
config iteration order.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp_mst.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 4736bfeb25e06..35f298255a677 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -445,8 +445,20 @@ static int mst_stream_compute_link_config(struct intel_dp *intel_dp,
 					  struct drm_connector_state *conn_state,
 					  const struct link_config_limits *limits)
 {
-	crtc_state->lane_count = limits->max_lane_count;
-	crtc_state->port_clock = limits->max_rate;
+	struct intel_connector *connector = to_intel_connector(conn_state->connector);
+	struct intel_dp_link_config max_link_config;
+
+	/*
+	 * FIXME: Use a proper iteration over the link configurations, instead
+	 * of using only the max BW config. For instance UHBR rate configs may
+	 * have additional limitations over non-UHBR ones, due to the DSC DPT
+	 * bpp maximum limit.
+	 */
+	if (!intel_dp_get_connector_max_link_config(connector, limits, &max_link_config))
+		return -EINVAL;
+
+	crtc_state->port_clock = max_link_config.rate;
+	crtc_state->lane_count = max_link_config.lane_count;
 
 	/*
 	 * FIXME: allocate the BW according to link_bpp, which in the case of
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 095/108] drm/i915/dp_mst: Use link caps for MST DSC config selection
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (93 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 094/108] drm/i915/dp_mst: Use link caps for non-DSC " Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 096/108] drm/i915/dp_test: Use link caps for compliance link configs Imre Deak
                   ` (15 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Use the link caps helper to select the maximum DP MST link configuration
for DSC computation, instead of using the separate max rate and lane
count limits, which may not form a valid configuration after individual
configs are disabled by fallback.

Also look up the maximum rate for state computation via the configuration
mask when checking the DSC hblank expansion quirk.

This is a step towards unifying configuration selection and iteration
across connector types and between compute and fallback paths.

The state computation should likely consider all allowed configurations,
as noted in the code comment; for now keep the existing DP MST DSC
behavior of selecting the maximum BW configuration determined by the MST
connector BW config iteration order.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 21 +++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  4 ++
 drivers/gpu/drm/i915/display/intel_dp_mst.c   | 44 ++++++++++++++++---
 3 files changed, 63 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 2ec55856636f5..f822c8952df3b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -749,6 +749,27 @@ static int get_max_config(struct intel_dp_link_caps *link_caps,
 	return config_idx;
 }
 
+/**
+ * intel_dp_link_caps_get_max_config - get the maximum config in a given order
+ * @link_caps: link capabilities state
+ * @order_key: ordering key used to rank candidate configurations
+ * @config_mask: mask of candidate configurations
+ * @max_config: returned maximum link configuration
+ *
+ * Find the last configuration from @config_mask in the iteration order
+ * selected by @order_key, and store it in @max_config.
+ *
+ * See also:
+ * - &enum intel_dp_link_caps_config_order_key
+ */
+void intel_dp_link_caps_get_max_config(struct intel_dp_link_caps *link_caps,
+				       enum intel_dp_link_caps_config_order_key order_key,
+				       u32 config_mask,
+				       struct intel_dp_link_config *max_config)
+{
+	get_max_config(link_caps, order_key, config_mask, max_config);
+}
+
 /**
  * intel_dp_link_caps_get_max_config_idx - get the index of the maximum config
  * @link_caps: link capabilities state
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index a907b99cd4cf9..742b88e6b0643 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -27,6 +27,7 @@ struct intel_dp_link_config;
  *
  * See also:
  *  - &struct intel_dp_link_caps_config_order
+ *  - intel_dp_link_caps_get_max_config()
  *  - intel_dp_link_caps_get_max_config_idx()
  */
 enum intel_dp_link_caps_config_order_key {
@@ -193,6 +194,9 @@ int intel_dp_link_caps_find_allowed_config_pos(struct intel_dp_link_caps *link_c
 					       enum intel_dp_link_caps_config_match_type match_type,
 					       const struct intel_dp_link_config *config);
 
+void intel_dp_link_caps_get_max_config(struct intel_dp_link_caps *link_caps,
+				       enum intel_dp_link_caps_config_order_key order_key,
+				       u32 config_mask, struct intel_dp_link_config *config);
 int intel_dp_link_caps_get_max_config_idx(struct intel_dp_link_caps *link_caps,
 					  enum intel_dp_link_caps_config_order_key order_key,
 					  u32 config_mask);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c b/drivers/gpu/drm/i915/display/intel_dp_mst.c
index 35f298255a677..080966ec3fd31 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
@@ -477,6 +477,7 @@ static int mst_stream_dsc_compute_link_config(struct intel_dp *intel_dp,
 {
 	struct intel_display *display = to_intel_display(intel_dp);
 	struct intel_connector *connector = to_intel_connector(conn_state->connector);
+	struct intel_dp_link_config max_link_config;
 
 	crtc_state->pipe_bpp = limits->pipe.max_bpp;
 
@@ -484,8 +485,17 @@ static int mst_stream_dsc_compute_link_config(struct intel_dp *intel_dp,
 		    "DSC Sink supported compressed min bpp " FXP_Q4_FMT " compressed max bpp " FXP_Q4_FMT "\n",
 		    FXP_Q4_ARGS(limits->link.min_bpp_x16), FXP_Q4_ARGS(limits->link.max_bpp_x16));
 
-	crtc_state->lane_count = limits->max_lane_count;
-	crtc_state->port_clock = limits->max_rate;
+	/*
+	 * FIXME: Use a proper iteration over the link configurations, instead
+	 * of using only the max BW config. For instance UHBR rate configs may
+	 * have additional limitations over non-UHBR ones, due to the DSC DPT
+	 * bpp maximum limit.
+	 */
+	if (!intel_dp_get_connector_max_link_config(connector, limits, &max_link_config))
+		return -EINVAL;
+
+	crtc_state->port_clock = max_link_config.rate;
+	crtc_state->lane_count = max_link_config.lane_count;
 
 	return intel_dp_mtp_tu_compute_config(intel_dp, crtc_state, conn_state,
 					      limits->link.min_bpp_x16,
@@ -501,6 +511,20 @@ static int mode_hblank_period_ns(const struct drm_display_mode *mode)
 				     mode->crtc_clock);
 }
 
+static int get_connector_max_rate(const struct intel_connector *connector,
+				  const struct link_config_limits *limits)
+{
+	struct intel_dp *intel_dp = intel_attached_dp((struct intel_connector *)connector);
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp_link_config max_link_config;
+
+	intel_dp_link_caps_get_max_config(link_caps,
+					  INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_RATE_LANE,
+					  limits->link_config_mask, &max_link_config);
+
+	return max_link_config.rate;
+}
+
 static bool
 hblank_expansion_quirk_needs_dsc(const struct intel_connector *connector,
 				 const struct intel_crtc_state *crtc_state,
@@ -511,11 +535,13 @@ hblank_expansion_quirk_needs_dsc(const struct intel_connector *connector,
 	bool is_uhbr_sink = connector->mst.dp &&
 			    drm_dp_128b132b_supported(connector->mst.dp->dpcd);
 	int hblank_limit = is_uhbr_sink ? 500 : 300;
+	int max_rate;
 
 	if (!connector->dp.dsc_hblank_expansion_quirk)
 		return false;
 
-	if (is_uhbr_sink && !drm_dp_is_uhbr_rate(limits->max_rate))
+	max_rate = get_connector_max_rate(connector, limits);
+	if (is_uhbr_sink && !drm_dp_is_uhbr_rate(max_rate))
 		return false;
 
 	if (mode_hblank_period_ns(adjusted_mode) > hblank_limit)
@@ -537,6 +563,7 @@ adjust_limits_for_dsc_hblank_expansion_quirk(struct intel_dp *intel_dp,
 	struct intel_display *display = to_intel_display(connector);
 	const struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
 	int min_bpp_x16 = limits->link.min_bpp_x16;
+	int max_rate;
 
 	if (!hblank_expansion_quirk_needs_dsc(connector, crtc_state, limits))
 		return true;
@@ -563,11 +590,16 @@ adjust_limits_for_dsc_hblank_expansion_quirk(struct intel_dp *intel_dp,
 		return true;
 	}
 
-	drm_WARN_ON(display->drm, limits->min_rate != limits->max_rate);
+	/*
+	 * Atm, supporting only a single allowed link configuration, which
+	 * ensures that max_rate == min_rate.
+	 */
+	drm_WARN_ON(display->drm, !is_power_of_2(limits->link_config_mask));
 
-	if (limits->max_rate < 540000)
+	max_rate = get_connector_max_rate(connector, limits);
+	if (max_rate < 540000)
 		min_bpp_x16 = fxp_q4_from_int(13);
-	else if (limits->max_rate < 810000)
+	else if (max_rate < 810000)
 		min_bpp_x16 = fxp_q4_from_int(10);
 
 	if (limits->link.min_bpp_x16 >= min_bpp_x16)
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 096/108] drm/i915/dp_test: Use link caps for compliance link configs
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (94 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 095/108] drm/i915/dp_mst: Use link caps for MST DSC " Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 097/108] drm/i915/dp: Remove min/max link config limits Imre Deak
                   ` (14 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Use the link caps configuration mask when applying DP compliance test
link parameters during state computation. Expose a link caps API query
function required for the configuration selection.

Preserve the legacy behavior of falling back to all configurations with
the requested lane count if the requested rate and lane count pair is
not allowed.

In case no valid configuration is found fail the modeset.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c       |  3 +-
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 23 +++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  6 +-
 drivers/gpu/drm/i915/display/intel_dp_test.c  | 92 +++++++++++++++----
 drivers/gpu/drm/i915/display/intel_dp_test.h  |  3 +-
 5 files changed, 107 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index c33209ec7782f..d577cdb1dc4e7 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -2793,7 +2793,8 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
 		limits->link_config_mask = BIT(max_config_idx);
 	}
 
-	intel_dp_test_compute_config(intel_dp, crtc_state, limits);
+	if (!intel_dp_test_compute_config(connector, crtc_state, limits))
+		return false;
 
 	return intel_dp_compute_config_link_bpp_limits(connector,
 						       crtc_state,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index f822c8952df3b..6eb5b67b6168b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -702,6 +702,29 @@ find_config_table_entry_idx(const struct intel_dp_link_caps_config_table *config
 	return rate_lane_iter_pos_to_config_idx(iter_pos, config_table->max_lane_count);
 }
 
+/**
+ * intel_dp_link_caps_find_allowed_config_idx - find index of matching allowed config
+ * @link_caps: link capabilities state
+ * @match_type: requested match type
+ * @link_config: link configuration to match
+ *
+ * Search the currently allowed link configurations for a match to
+ * @link_config.
+ *
+ * Return:
+ * * Index of the first matching allowed configuration.
+ * * %-1 if no allowed configuration matches.
+ */
+int intel_dp_link_caps_find_allowed_config_idx(struct intel_dp_link_caps *link_caps,
+					       enum intel_dp_link_caps_config_match_type match_type,
+					       const struct intel_dp_link_config *link_config)
+{
+	return find_config_table_entry_idx(&link_caps->config_table,
+					   intel_dp_link_caps_get_allowed_config_mask(link_caps),
+					   match_type,
+					   link_config);
+}
+
 /**
  * intel_dp_link_caps_find_allowed_config_pos - find matching allowed config position
  * @link_caps: link capabilities state
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 742b88e6b0643..1e4ce6a58e4fd 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -92,7 +92,8 @@ struct intel_dp_link_caps_config_order {
  *   supported nominal link rate.
  *
  * Selects how
- * intel_dp_link_caps_find_allowed_config_pos() matches
+ * intel_dp_link_caps_find_allowed_config_pos() and
+ * intel_dp_link_caps_find_allowed_config_idx() match
  * the requested &struct intel_dp_link_config against the currently
  * allowed configurations.
  */
@@ -189,6 +190,9 @@ intel_dp_link_caps_get_config_by_pos(struct intel_dp_link_caps *link_caps,
 				     struct intel_dp_link_caps_config_order config_order,
 				     int iter_pos,
 				     struct intel_dp_link_config *config, int *config_idx);
+int intel_dp_link_caps_find_allowed_config_idx(struct intel_dp_link_caps *link_caps,
+					       enum intel_dp_link_caps_config_match_type match_type,
+					       const struct intel_dp_link_config *config);
 int intel_dp_link_caps_find_allowed_config_pos(struct intel_dp_link_caps *link_caps,
 					       struct intel_dp_link_caps_config_order order,
 					       enum intel_dp_link_caps_config_match_type match_type,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_test.c b/drivers/gpu/drm/i915/display/intel_dp_test.c
index 0b791eee3b910..fcc71d21be2fd 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_test.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_test.c
@@ -28,13 +28,66 @@ void intel_dp_test_reset(struct intel_dp *intel_dp)
 	memset(&intel_dp->compliance, 0, sizeof(intel_dp->compliance));
 }
 
+static u32 find_link_configs_for_lane_count(struct intel_connector *connector,
+					    struct intel_dp_link_caps *link_caps,
+					    const struct link_config_limits *limits,
+					    int lane_count)
+{
+	struct intel_dp_link_config link_config;
+	struct intel_dp_link_caps_config_order order =
+		intel_dp_link_caps_config_order_for_connector(connector);
+	int link_config_idx;
+	u32 mask = 0;
+
+	for_each_dp_link_config_idx(link_caps, order, limits->link_config_mask,
+				    &link_config, &link_config_idx) {
+		if (link_config.lane_count == lane_count)
+			mask |= BIT(link_config_idx);
+	}
+
+	return mask;
+}
+
+static u32 find_test_link_configs(struct intel_connector *connector,
+				  struct intel_dp_link_caps *link_caps,
+				  const struct link_config_limits *limits,
+				  const struct intel_dp_link_config *link_params)
+{
+	u32 mask = 0;
+	int idx;
+
+	idx = intel_dp_link_caps_find_allowed_config_idx(link_caps,
+							 INTEL_DP_LINK_CAPS_CONFIG_MATCH_EXACT,
+							 link_params);
+
+	/* Preserve the legacy behavior: if the requested (rate, lane_count)
+	 * combination is not an allowed config, fall back to all configs
+	 * matching the requested lane count.
+	 *
+	 * TODO: Recheck whether this behavior is actually correct.
+	 */
+	if (idx >= 0 && (limits->link_config_mask & BIT(idx)))
+		mask = BIT(idx);
+	else
+		mask = find_link_configs_for_lane_count(connector, link_caps,
+							limits,
+							link_params->lane_count);
+
+	return mask;
+
+}
+
 /* Adjust link config limits based on compliance test requests. */
-void intel_dp_test_compute_config(struct intel_dp *intel_dp,
+bool intel_dp_test_compute_config(struct intel_connector *connector,
 				  struct intel_crtc_state *pipe_config,
 				  struct link_config_limits *limits)
 {
+	struct intel_dp *intel_dp = intel_attached_dp(connector);
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
 	struct intel_display *display = to_intel_display(intel_dp);
+	struct intel_dp_link_config requested_config;
+	u32 requested_config_mask;
 
 	/* For DP Compliance we override the computed bpp for the pipe */
 	if (intel_dp->compliance.test_data.bpc != 0) {
@@ -48,24 +101,29 @@ void intel_dp_test_compute_config(struct intel_dp *intel_dp,
 	}
 
 	/* Use values requested by Compliance Test Request */
-	if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
-		int index;
+	if (intel_dp->compliance.test_type != DP_TEST_LINK_TRAINING)
+		return true;
 
-		/* Validate the compliance test data since max values
-		 * might have changed due to link train fallback.
-		 */
-		if (intel_dp_link_params_valid(intel_dp, intel_dp->compliance.test_link_rate,
-					       intel_dp->compliance.test_lane_count)) {
-			index = intel_dp_link_caps_common_rate_idx(link_caps,
-								   intel_dp->compliance.test_link_rate);
-			if (index >= 0) {
-				limits->min_rate = intel_dp->compliance.test_link_rate;
-				limits->max_rate = intel_dp->compliance.test_link_rate;
-			}
-			limits->min_lane_count = intel_dp->compliance.test_lane_count;
-			limits->max_lane_count = intel_dp->compliance.test_lane_count;
-		}
+	requested_config.rate = intel_dp->compliance.test_link_rate;
+	requested_config.lane_count = intel_dp->compliance.test_lane_count;
+
+	requested_config_mask = find_test_link_configs(connector, link_caps,
+						       limits,
+						       &requested_config);
+
+	if (requested_config_mask == 0) {
+		drm_dbg_kms(display->drm,
+			    "[ENCODER:%d:%s] Invalid autotest link config parameters: %dx%d\n",
+			    encoder->base.base.id, encoder->base.name,
+			    requested_config.lane_count,
+			    requested_config.rate);
+
+		return false;
 	}
+
+	limits->link_config_mask = requested_config_mask;
+
+	return true;
 }
 
 /* Compliance test status bits  */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_test.h b/drivers/gpu/drm/i915/display/intel_dp_test.h
index dcc167e4c7f65..a08f37a63dc9a 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_test.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_test.h
@@ -6,6 +6,7 @@
 
 #include <linux/types.h>
 
+struct intel_connector;
 struct intel_crtc_state;
 struct intel_display;
 struct intel_dp;
@@ -13,7 +14,7 @@ struct link_config_limits;
 
 void intel_dp_test_reset(struct intel_dp *intel_dp);
 void intel_dp_test_request(struct intel_dp *intel_dp);
-void intel_dp_test_compute_config(struct intel_dp *intel_dp,
+bool intel_dp_test_compute_config(struct intel_connector *connector,
 				  struct intel_crtc_state *pipe_config,
 				  struct link_config_limits *limits);
 bool intel_dp_test_phy(struct intel_dp *intel_dp);
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 097/108] drm/i915/dp: Remove min/max link config limits
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (95 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 096/108] drm/i915/dp_test: Use link caps for compliance link configs Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 098/108] drm/i915/dp_link_training: Account for disabled configs during SST fallback Imre Deak
                   ` (13 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Remove the min/max rate and lane count fields from struct
link_config_limits after all state computation is converted to use the
configuration mask.

A simple min/max range cannot fully describe the valid configuration
set once individual configurations are disabled (for example by
fallback), as it may allow combinations that are not actually valid.
The configuration mask, on the other hand, always represents a
consistent set of allowed configurations.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 72 -------------------------
 drivers/gpu/drm/i915/display/intel_dp.h |  7 ---
 2 files changed, 79 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
index d577cdb1dc4e7..16ead049b5bf8 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -352,38 +352,6 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
 	return min3(source_max, sink_max, lane_max);
 }
 
-static int intel_dp_max_lane_count(struct intel_dp *intel_dp)
-{
-	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
-	struct intel_dp_link_config max_link_limits;
-	int lane_count;
-
-	intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits);
-	lane_count = max_link_limits.lane_count;
-
-	switch (lane_count) {
-	case 1:
-	case 2:
-	case 4:
-		return lane_count;
-	default:
-		MISSING_CASE(lane_count);
-		return 1;
-	}
-}
-
-static int intel_dp_min_lane_count(struct intel_dp *intel_dp)
-{
-	struct intel_dp_link_config forced_params;
-
-	intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params);
-
-	if (forced_params.lane_count)
-		return forced_params.lane_count;
-
-	return 1;
-}
-
 int intel_dp_link_bw_overhead(int link_clock, int lane_count, int hdisplay,
 			      int dsc_slice_count, int bpp_x16, unsigned long flags)
 {
@@ -1552,31 +1520,6 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp)
 	drm_dbg_kms(display->drm, "common rates: %s\n", seq_buf_str(&s));
 }
 
-static int
-intel_dp_max_link_rate(struct intel_dp *intel_dp)
-{
-	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
-	struct intel_dp_link_config max_link_limits;
-
-	intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits);
-
-	return max_link_limits.rate;
-}
-
-static int
-intel_dp_min_link_rate(struct intel_dp *intel_dp)
-{
-	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
-	struct intel_dp_link_config forced_params;
-
-	intel_dp_link_caps_get_forced_params(intel_dp->link.caps, &forced_params);
-
-	if (forced_params.rate)
-		return forced_params.rate;
-
-	return intel_dp_link_caps_common_rate(link_caps, 0);
-}
-
 int intel_dp_rate_select(struct intel_dp *intel_dp, int rate)
 {
 	struct intel_display *display = to_intel_display(intel_dp);
@@ -2692,18 +2635,6 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
 	struct intel_connector *connector =
 		to_intel_connector(conn_state->connector);
 
-	/*
-	 * Remove the following min/max rate and lane count setup, once
-	 * all users are converted to use link_config_mask instead.
-	 */
-	limits->min_rate = intel_dp_min_link_rate(intel_dp);
-	limits->max_rate = intel_dp_max_link_rate(intel_dp);
-
-	limits->min_rate = min(limits->min_rate, limits->max_rate);
-
-	limits->min_lane_count = intel_dp_min_lane_count(intel_dp);
-	limits->max_lane_count = intel_dp_max_lane_count(intel_dp);
-
 	limits->link_config_mask = intel_dp_link_caps_get_allowed_config_mask(link_caps);
 
 	limits->pipe.min_bpp = intel_dp_min_bpp(crtc_state->output_format);
@@ -2782,9 +2713,6 @@ intel_dp_compute_config_limits(struct intel_dp *intel_dp,
 		 */
 		int max_config_idx;
 
-		limits->min_lane_count = limits->max_lane_count;
-		limits->min_rate = limits->max_rate;
-
 		max_config_idx = intel_dp_get_connector_max_link_config_idx(connector,
 									    limits);
 		if (max_config_idx < 0)
diff --git a/drivers/gpu/drm/i915/display/intel_dp.h b/drivers/gpu/drm/i915/display/intel_dp.h
index bfba29ba715d5..c4bad94524c52 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.h
+++ b/drivers/gpu/drm/i915/display/intel_dp.h
@@ -26,13 +26,6 @@ struct intel_dp_link_config;
 struct intel_encoder;
 
 struct link_config_limits {
-	/*
-	 * Remove the following min/max rate and lane count limits
-	 * once all users are converted to use link_config_mask
-	 * instead.
-	 */
-	int min_rate, max_rate;
-	int min_lane_count, max_lane_count;
 	u32 link_config_mask;
 	struct {
 		/* Uncompressed DSC input or link output bpp in 1 bpp units */
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 098/108] drm/i915/dp_link_training: Account for disabled configs during SST fallback
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (96 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 097/108] drm/i915/dp: Remove min/max link config limits Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 099/108] drm/i915/dp_link_training: Disable failed config during fallback Imre Deak
                   ` (12 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Account for disabled configurations when selecting the next SST
fallback configuration in rate/lane order.

The rate and lane count reductions are applied independently, so the
resulting link parameter tuple may not be an allowed configuration once
individual configurations can be disabled. Keep reducing until an
allowed configuration is found.

While at it add a TODO comment to the rate look-up to handle non-nominal
computed rates.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../drm/i915/display/intel_dp_link_training.c | 65 ++++++++++++++++---
 1 file changed, 57 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index fb20795a7086f..a9955f04d507f 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1834,6 +1834,7 @@ static int reduce_link_rate(struct intel_dp *intel_dp, int current_rate)
 	if (forced_params.rate)
 		return -1;
 
+	/* FIXME: Account for a non-nominal current_rate */
 	rate_index = intel_dp_link_caps_common_rate_idx(link_caps,
 							current_rate);
 
@@ -1863,30 +1864,78 @@ static int reduce_lane_count(struct intel_dp *intel_dp, int current_lane_count)
 	return current_lane_count >> 1;
 }
 
-static bool reduce_link_params_in_rate_lane_order(struct intel_dp *intel_dp,
-						  const struct intel_crtc_state *crtc_state,
-						  int *new_link_rate, int *new_lane_count)
+static bool __reduce_link_params_in_rate_lane_order(struct intel_dp *intel_dp,
+						    const struct intel_dp_link_config *old_config,
+						    struct intel_dp_link_config *new_config)
 {
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	int link_rate;
 	int lane_count;
 
-	lane_count = crtc_state->lane_count;
-	link_rate = reduce_link_rate(intel_dp, crtc_state->port_clock);
+	lane_count = old_config->lane_count;
+	link_rate = reduce_link_rate(intel_dp, old_config->rate);
 	if (link_rate < 0) {
-		lane_count = reduce_lane_count(intel_dp, crtc_state->lane_count);
+		lane_count = reduce_lane_count(intel_dp, old_config->lane_count);
 		link_rate = intel_dp_link_caps_max_common_rate(link_caps);
 	}
 
 	if (lane_count < 0)
 		return false;
 
-	*new_link_rate = link_rate;
-	*new_lane_count = lane_count;
+	new_config->rate = link_rate;
+	new_config->lane_count = lane_count;
 
 	return true;
 }
 
+static bool reduce_link_params_in_rate_lane_order(struct intel_dp *intel_dp,
+						  const struct intel_crtc_state *crtc_state,
+						  int *new_link_rate, int *new_lane_count)
+{
+	struct intel_display *display = to_intel_display(intel_dp);
+	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
+	struct intel_dp_link_config old_config = {
+		.rate = crtc_state->port_clock,
+		.lane_count = crtc_state->lane_count,
+	};
+
+	/*
+	 * Guaranteed to terminate: either the rate decreases, or the rate wraps
+	 * to maximum and the lane decreases, guaranteeing that the minimum
+	 * (rate, lane) combination is reached.
+	 */
+	for (;;) {
+		struct intel_dp_link_config target_config;
+
+		if (!__reduce_link_params_in_rate_lane_order(intel_dp,
+							     &old_config, &target_config))
+			return false;
+
+		if (drm_WARN_ON(display->drm,
+				target_config.rate >= old_config.rate &&
+				target_config.lane_count >= old_config.lane_count))
+			return false;
+
+		/*
+		 * Rate and lane count were reduced independently, so the
+		 * resulting tuple may not be enabled at all, and either
+		 * parameter may even lie outside the range of enabled
+		 * configs. The target returned above has already a nominal
+		 * rate, so require hare an exact match.
+		 */
+		if (intel_dp_link_caps_find_allowed_config_idx(link_caps,
+							       INTEL_DP_LINK_CAPS_CONFIG_MATCH_EXACT,
+							       &target_config) >= 0) {
+			*new_link_rate = target_config.rate;
+			*new_lane_count = target_config.lane_count;
+
+			return true;
+		}
+
+		old_config = target_config;
+	}
+}
+
 static bool reduce_link_params(struct intel_dp *intel_dp, const struct intel_crtc_state *crtc_state,
 			       int *new_link_rate, int *new_lane_count)
 {
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 099/108] drm/i915/dp_link_training: Disable failed config during fallback
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (97 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 098/108] drm/i915/dp_link_training: Account for disabled configs during SST fallback Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 100/108] drm/i915/kunit: Enable KUnit tests Imre Deak
                   ` (11 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Disable the link configuration that failed training when selecting
fallback parameters.

Fallback still selects the next configuration using the existing
fallback order, but now also removes the failed configuration from the
allowed set. Functionally, this only affects the case where an MST <-> SST
mode switch occurs on the same root connector: previously, a configuration
that failed training in one mode could be reused in the other mode due
to the differing config iteration orders.

The current fallback logic also sets a temporary maximum link limit
across the allowed configurations to constrain subsequent modesets. This
legacy behavior is preserved for now; it will be removed once the
fallback logic relies solely on the individually disabled configurations
to restrict the allowed set.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 29 +++++++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h |  2 ++
 .../drm/i915/display/intel_dp_link_training.c | 27 +++++++++++++++++
 3 files changed, 58 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index 6eb5b67b6168b..e7f3d40c5ec08 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -1056,6 +1056,35 @@ void intel_dp_link_caps_reset_max_limits(struct intel_dp_link_caps *link_caps)
 	update_max_link_info(link_caps);
 }
 
+/**
+ * intel_dp_link_caps_disable_config - disable a configuration
+ * @link_caps: link capabilities state
+ * @config_idx: configuration index to disable
+ *
+ * Disable the configuration identified by @config_idx and update the derived
+ * maximum-link information accordingly. This removes the configuration from
+ * the set of allowed configurations.
+ *
+ * The configuration remains disallowed until intel_dp_link_caps_reset() is
+ * called, which normally happens after a connector disconnect, or until some
+ * error condition triggers recovery because the set of allowed
+ * configurations would otherwise become empty.
+ *
+ * Return:
+ * - %true  if @config_idx was valid and the derived state was updated.
+ * - %false if @config_idx was invalid or the derived state could not be
+ *   updated.
+ */
+bool intel_dp_link_caps_disable_config(struct intel_dp_link_caps *link_caps, int config_idx)
+{
+	if (!config_idx_is_valid(link_caps, config_idx))
+		return false;
+
+	link_caps->config_table.disabled_config_mask |= BIT(config_idx);
+
+	return update_max_link_info(link_caps);
+}
+
 static void enable_link_config_no_update(struct intel_dp_link_caps *link_caps, int config_idx)
 {
 	struct intel_display *display = to_intel_display(link_caps->dp);
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index 1e4ce6a58e4fd..da2eb1f7453a0 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -205,6 +205,8 @@ int intel_dp_link_caps_get_max_config_idx(struct intel_dp_link_caps *link_caps,
 					  enum intel_dp_link_caps_config_order_key order_key,
 					  u32 config_mask);
 
+bool intel_dp_link_caps_disable_config(struct intel_dp_link_caps *link_caps, int idx);
+
 void intel_dp_link_caps_get_max_limits(struct intel_dp_link_caps *link_caps,
 				       struct intel_dp_link_config *max_link_limits);
 bool intel_dp_link_caps_set_max_limits(struct intel_dp_link_caps *link_caps,
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index a9955f04d507f..c47d2bc84460a 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -1954,6 +1954,11 @@ static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
 	struct intel_display *display = to_intel_display(intel_dp);
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
 	struct intel_dp_link_config max_link_limits;
+	struct intel_dp_link_config current_config = {
+		.rate = crtc_state->port_clock,
+		.lane_count = crtc_state->lane_count,
+	};
+	int current_config_idx;
 	int new_link_rate;
 	int new_lane_count;
 	int err = -1;
@@ -1965,6 +1970,13 @@ static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
 		return 0;
 	}
 
+	current_config_idx =
+		intel_dp_link_caps_find_allowed_config_idx(link_caps,
+							   INTEL_DP_LINK_CAPS_CONFIG_MATCH_FUZZY_RATE,
+							   &current_config);
+	if (drm_WARN_ON(display->drm, current_config_idx < 0))
+		return -1;
+
 	/*
 	 * Temporarily reset the max link limit before selecting the fallback
 	 * config.
@@ -1982,6 +1994,13 @@ static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
 	intel_dp_link_caps_get_max_limits(link_caps, &max_link_limits);
 	intel_dp_link_caps_reset_max_limits(link_caps);
 
+	/*
+	 * TODO: Make fallback depend only on disabling the current config,
+	 * once max_limit no longer constrains the allowed config set. Then
+	 * disabling the current config will define the allowed configs for
+	 * the subsequent modeset, so there will be no need to select a
+	 * reduced config separately here.
+	 */
 	if (!reduce_link_params(intel_dp, crtc_state, &new_link_rate, &new_lane_count))
 		goto out_restore_max_limits;
 
@@ -1995,6 +2014,14 @@ static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
 		goto out_restore_max_limits;
 	}
 
+	/*
+	 * Shouldn't fail: the current config was enabled, and reducing the
+	 * link parameters should still leave the fallback config allowed.
+	 */
+	if (drm_WARN_ON(display->drm,
+			!intel_dp_link_caps_disable_config(link_caps, current_config_idx)))
+		return -1;
+
 	lt_dbg(intel_dp, DP_PHY_DPRX,
 	       "Reducing link parameters from %dx%d to %dx%d\n",
 	       crtc_state->lane_count, crtc_state->port_clock,
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 100/108] drm/i915/kunit: Enable KUnit tests
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (98 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 099/108] drm/i915/dp_link_training: Disable failed config during fallback Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 101/108] drm/i915/kunit: Add DP link test stub Imre Deak
                   ` (10 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add KUnit configuration for i915 and a local .kunitconfig to run the
tests.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/.kunitconfig  | 12 ++++++++++++
 drivers/gpu/drm/i915/Kconfig.debug | 12 ++++++++++++
 2 files changed, 24 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/.kunitconfig

diff --git a/drivers/gpu/drm/i915/.kunitconfig b/drivers/gpu/drm/i915/.kunitconfig
new file mode 100644
index 0000000000000..70e55432bad64
--- /dev/null
+++ b/drivers/gpu/drm/i915/.kunitconfig
@@ -0,0 +1,12 @@
+CONFIG_EXPERT=y
+CONFIG_MODULES=y
+CONFIG_KUNIT=y
+CONFIG_PCI=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+CONFIG_DRM=y
+CONFIG_DRM_I915=y
+CONFIG_DRM_I915_KUNIT_TEST=y
diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug
index 52a3a59b4ba2c..dc43dcfbadb6e 100644
--- a/drivers/gpu/drm/i915/Kconfig.debug
+++ b/drivers/gpu/drm/i915/Kconfig.debug
@@ -220,6 +220,18 @@ config DRM_I915_SELFTEST_BROKEN
 
 	  If in doubt, say "N".
 
+config DRM_I915_KUNIT_TEST
+	tristate "KUnit tests for the drm i915 driver" if !KUNIT_ALL_TESTS
+	depends on DRM_I915 && KUNIT && DEBUG_FS
+	default KUNIT_ALL_TESTS
+	help
+	  Choose this option to allow the driver to perform selftests under
+	  the kunit framework
+
+	  Recommended for driver developers only.
+
+	  If in doubt, say "N".
+
 config DRM_I915_LOW_LEVEL_TRACEPOINTS
 	bool "Enable low level request tracing events"
 	depends on DRM_I915
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 101/108] drm/i915/kunit: Add DP link test stub
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (99 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 100/108] drm/i915/kunit: Enable KUnit tests Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-29  7:36   ` [PATCH v2 " Imre Deak
  2026-04-28 12:52 ` [PATCH 102/108] drm/xe/kunit: Add display test config Imre Deak
                   ` (9 subsequent siblings)
  110 siblings, 1 reply; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add a Kunit stub test module for DP link test cases.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/Makefile                 |  2 +
 drivers/gpu/drm/i915/display/tests/Makefile   |  7 +++
 .../i915/display/tests/intel_dp_link_test.c   | 46 +++++++++++++++++++
 3 files changed, 55 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/display/tests/Makefile
 create mode 100644 drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 0c04c6d9bb13e..ff2b22271454b 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -385,6 +385,8 @@ i915-y += \
 i915-$(CONFIG_DRM_I915_DP_TUNNEL) += \
 	display/intel_dp_tunnel.o
 
+obj-$(CONFIG_DRM_I915_KUNIT_TEST) += display/tests/
+
 i915-$(CONFIG_DRM_I915_GVT) += \
 	display/intel_gvt_api.o
 
diff --git a/drivers/gpu/drm/i915/display/tests/Makefile b/drivers/gpu/drm/i915/display/tests/Makefile
new file mode 100644
index 0000000000000..ad250974160f6
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/tests/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+subdir-ccflags-y += -I$(srctree)/drivers/gpu/drm/i915/display/
+
+obj-$(CONFIG_DRM_I915_KUNIT_TEST) += i915_display_test.o
+i915_display_test-y = \
+	intel_dp_link_test.o
diff --git a/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
new file mode 100644
index 0000000000000..1efcfdc53c936
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include <kunit/test.h>
+
+struct test_ctx {
+};
+
+static struct kunit_case intel_dp_link_test_cases[] = {
+	{}
+};
+
+static struct test_ctx test_ctx;
+
+static int intel_dp_link_test_init(struct kunit *test)
+{
+	test->priv = &test_ctx;
+
+	return 0;
+}
+
+static void intel_dp_link_test_exit(struct kunit *test)
+{
+}
+
+static int intel_dp_link_test_suite_init(struct kunit_suite *test_suite)
+{
+	return 0;
+}
+
+static struct kunit_suite intel_dp_link_test_suite = {
+	.name = "intel_dp_link",
+	.suite_init = intel_dp_link_test_suite_init,
+	.init = intel_dp_link_test_init,
+	.exit = intel_dp_link_test_exit,
+	.test_cases = intel_dp_link_test_cases,
+};
+
+kunit_test_suites(&intel_dp_link_test_suite);
+
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION("Intel DP link KUnit tests");
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 102/108] drm/xe/kunit: Add display test config
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (100 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 101/108] drm/i915/kunit: Add DP link test stub Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 103/108] drm/xe/kunit: Build DP link display tests Imre Deak
                   ` (8 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add a separate xe KUnit config for display tests.

The existing xe .kunitconfig builds xe statically, which is suitable for
non-display xe tests. The display code can only be enabled for xe when
xe is built as a module, so add a separate display config with DRM_XE=m
and DRM_XE_DISPLAY=y.

This can be folded back into the main xe KUnit config once the display
code becomes a separate module.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/xe/.gitignore           |  1 +
 drivers/gpu/drm/xe/.kunitconfig-display | 11 +++++++++++
 2 files changed, 12 insertions(+)
 create mode 100644 drivers/gpu/drm/xe/.kunitconfig-display

diff --git a/drivers/gpu/drm/xe/.gitignore b/drivers/gpu/drm/xe/.gitignore
index 8778bf132674d..6dad8a5a21355 100644
--- a/drivers/gpu/drm/xe/.gitignore
+++ b/drivers/gpu/drm/xe/.gitignore
@@ -2,3 +2,4 @@
 *.hdrtest
 /generated
 /xe_gen_wa_oob
+!.kunitconfig-display
diff --git a/drivers/gpu/drm/xe/.kunitconfig-display b/drivers/gpu/drm/xe/.kunitconfig-display
new file mode 100644
index 0000000000000..17020aa4ded3a
--- /dev/null
+++ b/drivers/gpu/drm/xe/.kunitconfig-display
@@ -0,0 +1,11 @@
+CONFIG_EXPERT=y
+CONFIG_MODULES=y
+CONFIG_KUNIT=y
+CONFIG_PCI=y
+CONFIG_DEBUG_FS=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DRM=m
+CONFIG_DRM_XE=m
+CONFIG_DRM_XE_DISPLAY=y
+CONFIG_DRM_XE_KUNIT_TEST=m
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 103/108] drm/xe/kunit: Build DP link display tests
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (101 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 102/108] drm/xe/kunit: Add display test config Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 104/108] drm/i915/kunit: setup DP link test context Imre Deak
                   ` (7 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Hook the shared i915 display DP link KUnit tests into the xe display
test build.

Build the shared display test source from the i915 display test directory
when xe display support is enabled.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/xe/Makefile               |  3 +++
 drivers/gpu/drm/xe/display/tests/Makefile | 11 +++++++++++
 2 files changed, 14 insertions(+)
 create mode 100644 drivers/gpu/drm/xe/display/tests/Makefile

diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index 9450d487123a3..fb2bcdeca6f72 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -371,6 +371,9 @@ xe-$(CONFIG_DRM_XE_DP_TUNNEL) += \
 
 obj-$(CONFIG_DRM_XE) += xe.o
 obj-$(CONFIG_DRM_XE_KUNIT_TEST) += tests/
+ifeq ($(CONFIG_DRM_XE_DISPLAY),y)
+	obj-$(CONFIG_DRM_XE_KUNIT_TEST) += display/tests/
+endif
 
 # header test
 hdrtest_find_args := -not -path xe_rtp_helpers.h
diff --git a/drivers/gpu/drm/xe/display/tests/Makefile b/drivers/gpu/drm/xe/display/tests/Makefile
new file mode 100644
index 0000000000000..1a582febe17a6
--- /dev/null
+++ b/drivers/gpu/drm/xe/display/tests/Makefile
@@ -0,0 +1,11 @@
+subdir-ccflags-$(CONFIG_DRM_XE_DISPLAY) += \
+	-I$(srctree)/drivers/gpu/drm/i915/display/
+
+# Rule to build display code shared with i915
+$(obj)/i915-display/tests/%.o: $(srctree)/drivers/gpu/drm/i915/display/tests/%.c FORCE
+	$(call cmd,force_checksrc)
+	$(call if_changed_rule,cc_o_c)
+
+obj-$(CONFIG_DRM_XE_KUNIT_TEST) += xe_display_test.o
+xe_display_test-y = \
+		i915-display/tests/intel_dp_link_test.o
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 104/108] drm/i915/kunit: setup DP link test context
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (102 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 103/108] drm/xe/kunit: Build DP link display tests Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 105/108] drm/i915/kunit: Export link training and caps funcs for testing Imre Deak
                   ` (6 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Initialize a reusable test context for DP link KUnit tests. Sets up
minimal device, connector, encoder, and DP structures, and seeds the
pseudo-random generator for deterministic test runs.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../i915/display/tests/intel_dp_link_test.c   | 47 +++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
index 1efcfdc53c936..83f09d8cc4aeb 100644
--- a/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
+++ b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
@@ -5,7 +5,32 @@
 
 #include <kunit/test.h>
 
+#include <linux/compiler.h>
+#include <linux/device.h>
+#include <linux/prandom.h>
+#include <linux/random.h>
+
+#include <drm/display/drm_dp_helper.h>
+
+#include <drm/intel/display_member.h>
+
+#include "intel_connector.h"
+#include "intel_display_core.h"
+#include "intel_display_types.h"
+
 struct test_ctx {
+	struct {
+		struct intel_display display;
+		struct device device;
+		struct __intel_generic_device generic_device;
+
+		struct intel_connector connector;
+		struct intel_dp dp;
+
+		struct intel_crtc_state crtc_state;
+	} dev;
+
+	struct rnd_state rnd;
 };
 
 static struct kunit_case intel_dp_link_test_cases[] = {
@@ -16,6 +41,26 @@ static struct test_ctx test_ctx;
 
 static int intel_dp_link_test_init(struct kunit *test)
 {
+	struct intel_digital_port *dig_port;
+	struct intel_encoder *encoder;
+
+	/* Reset the dev state for each test. */
+	memset(&test_ctx.dev, 0, sizeof(test_ctx.dev));
+
+	test_ctx.dev.generic_device.drm.dev = &test_ctx.dev.device;
+
+	test_ctx.dev.display.drm = &test_ctx.dev.generic_device.drm;
+	test_ctx.dev.generic_device.display = &test_ctx.dev.display;
+
+	encoder = &dp_to_dig_port(&test_ctx.dev.dp)->base;
+	encoder->base.dev = &test_ctx.dev.generic_device.drm;
+
+	dig_port = dp_to_dig_port(&test_ctx.dev.dp);
+	dig_port->base.type = INTEL_OUTPUT_DP;
+
+	test_ctx.dev.connector.encoder = encoder;
+	test_ctx.dev.dp.attached_connector = &test_ctx.dev.connector;
+
 	test->priv = &test_ctx;
 
 	return 0;
@@ -27,6 +72,8 @@ static void intel_dp_link_test_exit(struct kunit *test)
 
 static int intel_dp_link_test_suite_init(struct kunit_suite *test_suite)
 {
+	prandom_seed_state(&test_ctx.rnd, 0);
+
 	return 0;
 }
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 105/108] drm/i915/kunit: Export link training and caps funcs for testing
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (103 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 104/108] drm/i915/kunit: setup DP link test context Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 106/108] drm/i915/kunit: DP link: add baseline fixed table reference test Imre Deak
                   ` (5 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Export the link caps and link training helpers needed by the DP link
KUnit tests.

Use test ops tables instead of exporting the helpers directly, avoiding
symbol name collisions between the i915 and xe builds of the shared
display code.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../gpu/drm/i915/display/intel_dp_link_caps.c | 29 +++++++++++++++
 .../gpu/drm/i915/display/intel_dp_link_caps.h | 36 +++++++++++++++++++
 .../drm/i915/display/intel_dp_link_training.c | 36 +++++++++++++++++--
 .../drm/i915/display/intel_dp_link_training.h | 29 +++++++++++++++
 .../i915/display/tests/intel_dp_link_test.c   | 17 +++++++++
 5 files changed, 145 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
index e7f3d40c5ec08..b2a6c9a0d981b 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.c
@@ -1721,3 +1721,32 @@ void intel_dp_link_caps_cleanup(struct intel_dp_link_caps *link_caps)
 {
 	kfree(link_caps);
 }
+
+#if IS_ENABLED(CONFIG_KUNIT)
+
+#define __INIT_MEMBER(__name, __fn) \
+	.__name = __fn,
+
+#define INTEL_DP_LINK_CAPS_TEST_OPS_INIT \
+	INTEL_DP_LINK_CAPS_TEST_OPS_MEMBERS(__INIT_MEMBER)
+
+#ifdef I915
+
+const struct intel_dp_link_caps_test_ops i915_display_dp_link_caps_test_ops = {
+	INTEL_DP_LINK_CAPS_TEST_OPS_INIT
+};
+EXPORT_SYMBOL(i915_display_dp_link_caps_test_ops);
+
+#else
+
+const struct intel_dp_link_caps_test_ops intel_display_dp_link_caps_test_ops = {
+	INTEL_DP_LINK_CAPS_TEST_OPS_INIT
+};
+EXPORT_SYMBOL(intel_display_dp_link_caps_test_ops);
+
+#endif	/* I915 */
+
+#undef INTEL_DP_LINK_CAPS_TEST_OPS_INIT
+#undef __INIT_MEMBER
+
+#endif	/* CONFIG_KUNIT */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
index da2eb1f7453a0..892559484fdca 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_caps.h
@@ -223,4 +223,40 @@ void intel_dp_link_caps_debugfs_add(struct intel_connector *connector);
 struct intel_dp_link_caps *intel_dp_link_caps_init(struct intel_dp *intel_dp);
 void intel_dp_link_caps_cleanup(struct intel_dp_link_caps *link_caps);
 
+#if IS_ENABLED(CONFIG_KUNIT)
+
+#define INTEL_DP_LINK_CAPS_TEST_OPS_MEMBERS(__X) \
+	__X(config_order_for_connector,	intel_dp_link_caps_config_order_for_connector) \
+	__X(get_config_by_pos,		intel_dp_link_caps_get_config_by_pos) \
+	__X(get_allowed_config_mask,	intel_dp_link_caps_get_allowed_config_mask) \
+	__X(find_allowed_config_idx,	intel_dp_link_caps_find_allowed_config_idx) \
+	__X(set_max_limits,		intel_dp_link_caps_set_max_limits) \
+	__X(get_max_limits,		intel_dp_link_caps_get_max_limits) \
+	__X(reset_max_limits,		intel_dp_link_caps_reset_max_limits) \
+	__X(disable_config,		intel_dp_link_caps_disable_config) \
+	__X(update,			intel_dp_link_caps_update) \
+	__X(init,			intel_dp_link_caps_init) \
+	__X(cleanup,			intel_dp_link_caps_cleanup)
+
+#define __DECLARE_MEMBER(__name, __fn) \
+	typeof(__fn) *__name;
+
+#define INTEL_DP_LINK_CAPS_TEST_OPS_DECLARE \
+	INTEL_DP_LINK_CAPS_TEST_OPS_MEMBERS(__DECLARE_MEMBER)
+
+struct intel_dp_link_caps_test_ops {
+	INTEL_DP_LINK_CAPS_TEST_OPS_DECLARE
+};
+
+#undef INTEL_DP_LINK_CAPS_TEST_OPS_DECLARE
+#undef __DECLARE_MEMBER
+
+#ifdef I915
+extern const struct intel_dp_link_caps_test_ops i915_display_dp_link_caps_test_ops;
+#else
+extern const struct intel_dp_link_caps_test_ops intel_display_dp_link_caps_test_ops;
+#endif	/* I915 */
+
+#endif	/* CONFIG_KUNIT */
+
 #endif /* __INTEL_DP_LINK_CAPS_H__ */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
index c47d2bc84460a..fd249e4ebd1ce 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c
@@ -21,6 +21,8 @@
  * IN THE SOFTWARE.
  */
 
+#include <kunit/visibility.h>
+
 #include <linux/debugfs.h>
 #include <linux/iopoll.h>
 
@@ -1948,8 +1950,9 @@ static bool reduce_link_params(struct intel_dp *intel_dp, const struct intel_crt
 							     new_link_rate, new_lane_count);
 }
 
-static int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
-						   const struct intel_crtc_state *crtc_state)
+VISIBLE_IF_KUNIT
+int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
+					    const struct intel_crtc_state *crtc_state)
 {
 	struct intel_display *display = to_intel_display(intel_dp);
 	struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
@@ -2906,3 +2909,32 @@ void intel_dp_link_training_cleanup(struct intel_dp_link_training *link_training
 {
 	kfree(link_training);
 }
+
+#if IS_ENABLED(CONFIG_KUNIT)
+
+#define __INIT_MEMBER(__name, __fn) \
+	.__name = __fn,
+
+#define INTEL_DP_LINK_TRAINING_TEST_OPS_INIT \
+	INTEL_DP_LINK_TRAINING_TEST_OPS_MEMBERS(__INIT_MEMBER)
+
+#ifdef I915
+
+const struct intel_dp_link_training_test_ops i915_display_dp_link_training_test_ops = {
+	INTEL_DP_LINK_TRAINING_TEST_OPS_INIT
+};
+EXPORT_SYMBOL(i915_display_dp_link_training_test_ops);
+
+#else
+
+const struct intel_dp_link_training_test_ops intel_display_dp_link_training_test_ops = {
+	INTEL_DP_LINK_TRAINING_TEST_OPS_INIT
+};
+EXPORT_SYMBOL(intel_display_dp_link_training_test_ops);
+
+#endif	/* I915 */
+
+#undef INTEL_DP_LINK_TRAINING_TEST_OPS_INIT
+#undef __INIT_MEMBER
+
+#endif	/* CONFIG_KUNIT */
diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.h b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
index f80e979f7436c..f4c758b8c71e1 100644
--- a/drivers/gpu/drm/i915/display/intel_dp_link_training.h
+++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.h
@@ -70,4 +70,33 @@ void intel_dp_link_training_reset(struct intel_dp_link_training *link_training);
 struct intel_dp_link_training *intel_dp_link_training_init(struct intel_dp *intel_dp);
 void intel_dp_link_training_cleanup(struct intel_dp_link_training *link_training);
 
+#if IS_ENABLED(CONFIG_KUNIT)
+
+int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
+					    const struct intel_crtc_state *crtc_state);
+
+#define INTEL_DP_LINK_TRAINING_TEST_OPS_MEMBERS(__X) \
+	__X(get_fallback_values,	intel_dp_get_link_train_fallback_values)
+
+#define __DECLARE_MEMBER(__name, __fn) \
+	typeof(__fn) *__name;
+
+#define INTEL_DP_LINK_TRAINING_TEST_OPS_DECLARE \
+	INTEL_DP_LINK_TRAINING_TEST_OPS_MEMBERS(__DECLARE_MEMBER)
+
+struct intel_dp_link_training_test_ops {
+	INTEL_DP_LINK_TRAINING_TEST_OPS_DECLARE
+};
+
+#undef INTEL_DP_LINK_TRAINING_TEST_OPS_DECLARE
+#undef __DECLARE_MEMBER
+
+#ifdef I915
+extern const struct intel_dp_link_training_test_ops i915_display_dp_link_training_test_ops;
+#else
+extern const struct intel_dp_link_training_test_ops intel_display_dp_link_training_test_ops;
+#endif	/* I915 */
+
+#endif	/* CONFIG_KUNIT */
+
 #endif /* __INTEL_DP_LINK_TRAINING_H__ */
diff --git a/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
index 83f09d8cc4aeb..15179b4d08d1a 100644
--- a/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
+++ b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
@@ -17,6 +17,8 @@
 #include "intel_connector.h"
 #include "intel_display_core.h"
 #include "intel_display_types.h"
+#include "intel_dp_link_caps.h"
+#include "intel_dp_link_training.h"
 
 struct test_ctx {
 	struct {
@@ -30,6 +32,9 @@ struct test_ctx {
 		struct intel_crtc_state crtc_state;
 	} dev;
 
+	const struct intel_dp_link_caps_test_ops *link_caps_ops;
+	const struct intel_dp_link_training_test_ops *link_training_ops;
+
 	struct rnd_state rnd;
 };
 
@@ -61,6 +66,8 @@ static int intel_dp_link_test_init(struct kunit *test)
 	test_ctx.dev.connector.encoder = encoder;
 	test_ctx.dev.dp.attached_connector = &test_ctx.dev.connector;
 
+	test_ctx.dev.dp.link.caps = test_ctx.link_caps_ops->init(&test_ctx.dev.dp);
+
 	test->priv = &test_ctx;
 
 	return 0;
@@ -68,10 +75,20 @@ static int intel_dp_link_test_init(struct kunit *test)
 
 static void intel_dp_link_test_exit(struct kunit *test)
 {
+	struct test_ctx *ctx = test->priv;
+
+	ctx->link_caps_ops->cleanup(ctx->dev.dp.link.caps);
 }
 
 static int intel_dp_link_test_suite_init(struct kunit_suite *test_suite)
 {
+#ifdef I915
+	test_ctx.link_caps_ops = &i915_display_dp_link_caps_test_ops;
+	test_ctx.link_training_ops = &i915_display_dp_link_training_test_ops;
+#else
+	test_ctx.link_caps_ops = &intel_display_dp_link_caps_test_ops;
+	test_ctx.link_training_ops = &intel_display_dp_link_training_test_ops;
+#endif
 	prandom_seed_state(&test_ctx.rnd, 0);
 
 	return 0;
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 106/108] drm/i915/kunit: DP link: add baseline fixed table reference test
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (104 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 105/108] drm/i915/kunit: Export link training and caps funcs for testing Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 107/108] drm/i915/kunit: DP link: add update config tests Imre Deak
                   ` (4 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add a simple baseline test for DP link caps iteration using a fixed
standard DP configuration table. This provides a minimal validity check,
independent of more complex test setups, verifying the iterator returns
expected configurations in ascending and descending order.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../i915/display/tests/intel_dp_link_test.c   | 238 ++++++++++++++++++
 1 file changed, 238 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
index 15179b4d08d1a..e6feb68cb912f 100644
--- a/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
+++ b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
@@ -7,6 +7,7 @@
 
 #include <linux/compiler.h>
 #include <linux/device.h>
+#include <linux/log2.h>
 #include <linux/prandom.h>
 #include <linux/random.h>
 
@@ -20,6 +21,34 @@
 #include "intel_dp_link_caps.h"
 #include "intel_dp_link_training.h"
 
+#define test_for_each_dp_link_config_idx(__test_ctx, __config_order, __config_mask, \
+					 __config, __config_idx) \
+	for_each_dp_link_config_idx_iter((__test_ctx)->dev.dp.link.caps, \
+					 (__test_ctx)->link_caps_ops->get_config_by_pos, \
+					 (__config_order), (__config_mask), (__config), (__config_idx))
+
+#define test_for_each_dp_link_config(__test_ctx, __config_order, __config_mask, __config) \
+	test_for_each_dp_link_config_idx((__test_ctx), (__config_order), (__config_mask), \
+					 (__config), NULL)
+
+#define LINK_TEST_NUM_LANE_CONFIGS(__max_lane_count) \
+	(ilog2(__max_lane_count) + 1)
+
+#define LINK_TEST_NUM_CONFIGS(__num_rates, __max_lane_count) \
+	((__num_rates) * LINK_TEST_NUM_LANE_CONFIGS(__max_lane_count))
+
+#define LINK_TEST_MAX_LANE_COUNT		((u32)4)
+#define LINK_TEST_MAX_CONFIGS			LINK_TEST_NUM_CONFIGS(DP_MAX_SUPPORTED_RATES, \
+								      LINK_TEST_MAX_LANE_COUNT)
+
+#define LINK_TEST_NUM_RANDOM_ITERATIONS		50
+
+enum test_config_order_key {
+	TEST_CONFIG_ORDER_KEY_BW,
+	TEST_CONFIG_ORDER_KEY_RATE_LANE,
+	TEST_CONFIG_ORDER_KEY_LANE_RATE,
+};
+
 struct test_ctx {
 	struct {
 		struct intel_display display;
@@ -38,7 +67,216 @@ struct test_ctx {
 	struct rnd_state rnd;
 };
 
+struct test_config_order {
+	enum test_config_order_key key;
+	enum intel_dp_link_caps_config_order_direction dir;
+};
+
+struct link_rate_set {
+	const int *entries;
+	int size;
+};
+
+struct link_config_set {
+	struct intel_dp_link_config entries[LINK_TEST_MAX_CONFIGS];
+	int size;
+};
+
+static const int standard_dp_link_rates[] = {
+	162000, 270000, 540000, 810000, 1000000, 1350000, 2000000
+};
+
+#define LINK_TEST_NUM_STANDARD_RATES (ARRAY_SIZE(standard_dp_link_rates))
+
+static const struct link_config_set standard_dp_link_configs[] = {
+	[TEST_CONFIG_ORDER_KEY_BW] = {                        /* MBps    PBN    */
+		.entries = {
+			{ .rate =  162000, .lane_count = 1 }, /*  162.0    3.00 */
+			{ .rate =  270000, .lane_count = 1 }, /*  270.0    5.00 */
+			{ .rate =  162000, .lane_count = 2 }, /*  324.0    6.00 */
+			{ .rate =  270000, .lane_count = 2 }, /*  540.0   10.00 */
+			{ .rate =  540000, .lane_count = 1 }, /*  540.0   10.00 */
+			{ .rate =  162000, .lane_count = 4 }, /*  648.0   12.00 */
+			{ .rate =  810000, .lane_count = 1 }, /*  810.0   15.00 */
+			{ .rate =  270000, .lane_count = 4 }, /* 1080.0   20.00 */
+			{ .rate =  540000, .lane_count = 2 }, /* 1080.0   20.00 */
+			{ .rate = 1000000, .lane_count = 1 }, /* 1208.9   22.39 */
+			{ .rate =  810000, .lane_count = 2 }, /* 1620.0   30.00 */
+			{ .rate = 1350000, .lane_count = 1 }, /* 1632.0   30.22 */
+			{ .rate =  540000, .lane_count = 4 }, /* 2160.0   40.00 */
+			{ .rate = 1000000, .lane_count = 2 }, /* 2417.8   44.77 */
+			{ .rate = 2000000, .lane_count = 1 }, /* 2417.8   44.77 */
+			{ .rate =  810000, .lane_count = 4 }, /* 3240.0   60.00 */
+			{ .rate = 1350000, .lane_count = 2 }, /* 3264.0   60.44 */
+			{ .rate = 1000000, .lane_count = 4 }, /* 4835.6   89.55 */
+			{ .rate = 2000000, .lane_count = 2 }, /* 4835.6   89.55 */
+			{ .rate = 1350000, .lane_count = 4 }, /* 6527.9  120.89 */
+			{ .rate = 2000000, .lane_count = 4 }, /* 9671.1  179.09 */
+		},
+		.size = LINK_TEST_NUM_CONFIGS(ARRAY_SIZE(standard_dp_link_rates),
+					      LINK_TEST_MAX_LANE_COUNT),
+	},
+	[TEST_CONFIG_ORDER_KEY_RATE_LANE] = {
+		.entries = {
+			{ .rate = 162000,  .lane_count = 1 },
+			{ .rate = 162000,  .lane_count = 2 },
+			{ .rate = 162000,  .lane_count = 4 },
+
+			{ .rate = 270000,  .lane_count = 1 },
+			{ .rate = 270000,  .lane_count = 2 },
+			{ .rate = 270000,  .lane_count = 4 },
+
+			{ .rate = 540000,  .lane_count = 1 },
+			{ .rate = 540000,  .lane_count = 2 },
+			{ .rate = 540000,  .lane_count = 4 },
+
+			{ .rate = 810000,  .lane_count = 1 },
+			{ .rate = 810000,  .lane_count = 2 },
+			{ .rate = 810000,  .lane_count = 4 },
+
+			{ .rate = 1000000, .lane_count = 1 },
+			{ .rate = 1000000, .lane_count = 2 },
+			{ .rate = 1000000, .lane_count = 4 },
+
+			{ .rate = 1350000, .lane_count = 1 },
+			{ .rate = 1350000, .lane_count = 2 },
+			{ .rate = 1350000, .lane_count = 4 },
+
+			{ .rate = 2000000, .lane_count = 1 },
+			{ .rate = 2000000, .lane_count = 2 },
+			{ .rate = 2000000, .lane_count = 4 },
+		},
+		.size = LINK_TEST_NUM_CONFIGS(ARRAY_SIZE(standard_dp_link_rates),
+					      LINK_TEST_MAX_LANE_COUNT),
+	},
+	[TEST_CONFIG_ORDER_KEY_LANE_RATE] = {
+		.entries = {
+			{ .rate = 162000,  .lane_count = 1 },
+			{ .rate = 270000,  .lane_count = 1 },
+			{ .rate = 540000,  .lane_count = 1 },
+			{ .rate = 810000,  .lane_count = 1 },
+			{ .rate = 1000000, .lane_count = 1 },
+			{ .rate = 1350000, .lane_count = 1 },
+			{ .rate = 2000000, .lane_count = 1 },
+
+			{ .rate = 162000,  .lane_count = 2 },
+			{ .rate = 270000,  .lane_count = 2 },
+			{ .rate = 540000,  .lane_count = 2 },
+			{ .rate = 810000,  .lane_count = 2 },
+			{ .rate = 1000000, .lane_count = 2 },
+			{ .rate = 1350000, .lane_count = 2 },
+			{ .rate = 2000000, .lane_count = 2 },
+
+			{ .rate = 162000,  .lane_count = 4 },
+			{ .rate = 270000,  .lane_count = 4 },
+			{ .rate = 540000,  .lane_count = 4 },
+			{ .rate = 810000,  .lane_count = 4 },
+			{ .rate = 1000000, .lane_count = 4 },
+			{ .rate = 1350000, .lane_count = 4 },
+			{ .rate = 2000000, .lane_count = 4 },
+		},
+		.size = LINK_TEST_NUM_CONFIGS(ARRAY_SIZE(standard_dp_link_rates),
+					      LINK_TEST_MAX_LANE_COUNT),
+	},
+};
+
+static bool link_configs_match(const struct intel_dp_link_config *a,
+			       const struct intel_dp_link_config *b)
+{
+	return a->rate == b->rate && a->lane_count == b->lane_count;
+}
+
+static u32 get_all_config_mask(void)
+{
+	return GENMASK_U32(LINK_TEST_MAX_CONFIGS - 1, 0);
+}
+
+static const struct intel_dp_link_caps_config_order config_orders[] = {
+	{
+		.key = INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW,
+		.dir = INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_ASC,
+	}, {
+		.key = INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW,
+		.dir = INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_DESC,
+	}, {
+		.key = INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_RATE_LANE,
+		.dir = INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_ASC,
+	}, {
+		.key = INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_RATE_LANE,
+		.dir = INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_DESC,
+	}
+};
+
+static enum test_config_order_key
+link_caps_to_test_config_order_key(struct kunit *test, enum intel_dp_link_caps_config_order_key key)
+{
+	switch (key) {
+	case INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW:
+		return TEST_CONFIG_ORDER_KEY_BW;
+	case INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_RATE_LANE:
+		return TEST_CONFIG_ORDER_KEY_RATE_LANE;
+	default:
+		KUNIT_FAIL_AND_ABORT(test, "Missing link caps order key: %d\n", key);
+	}
+}
+
+static const struct link_config_set *
+link_caps_config_order_key_to_set(struct kunit *test, enum intel_dp_link_caps_config_order_key key)
+{
+	enum test_config_order_key test_order_key =
+		link_caps_to_test_config_order_key(test, key);
+
+	return &standard_dp_link_configs[test_order_key];
+}
+
+/*
+ * TEST: Baseline with fixed reference table
+ * -----------------------------------------
+ * Verify the link_caps config iterator using fixed standard DP config tables.
+ */
+static void baseline_test_for_order(struct kunit *test,
+				    struct intel_dp_link_caps *link_caps,
+				    struct intel_dp_link_caps_config_order config_order)
+{
+	struct test_ctx *ctx = test->priv;
+	const struct link_config_set *config_set =
+		link_caps_config_order_key_to_set(test, config_order.key);
+	struct intel_dp_link_config iter_config;
+	int pos = 0;
+
+	test_for_each_dp_link_config(ctx, config_order, get_all_config_mask(), &iter_config) {
+		int idx = pos;
+
+		if (config_order.dir == INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_DESC)
+			idx = config_set->size - idx - 1;
+
+		KUNIT_EXPECT_TRUE(test, link_configs_match(&iter_config,
+							   &config_set->entries[idx]));
+
+		pos++;
+	}
+}
+
+static void intel_dp_link_caps_test_baseline(struct kunit *test)
+{
+	struct test_ctx *ctx = test->priv;
+	struct intel_dp_link_caps *link_caps = ctx->dev.dp.link.caps;
+	const struct intel_dp_link_caps_test_ops *ops =
+		ctx->link_caps_ops;
+	int i;
+
+	ops->update(link_caps,
+		    standard_dp_link_rates, LINK_TEST_NUM_STANDARD_RATES,
+		    LINK_TEST_MAX_LANE_COUNT,
+		    INTEL_DP_LINK_CAPS_UPDATE_RESET);
+
+	for (i = 0; i < ARRAY_SIZE(config_orders); i++)
+		baseline_test_for_order(test, link_caps, config_orders[i]);
+}
+
 static struct kunit_case intel_dp_link_test_cases[] = {
+	KUNIT_CASE(intel_dp_link_caps_test_baseline),
+
 	{}
 };
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 107/108] drm/i915/kunit: DP link: add update config tests
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (105 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 106/108] drm/i915/kunit: DP link: add baseline fixed table reference test Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 12:52 ` [PATCH 108/108] drm/i915/kunit: DP link: add fallback tests Imre Deak
                   ` (3 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add KUnit tests for link_caps updates, covering reset and merge updates
when supported rates and lane counts shrink or expand.

The tests also cover updates with disabled configurations, including
random shrink and expand sequences, to verify that disabled state,
allowed configurations, ordering, and max limits stay consistent across
updates.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../i915/display/tests/intel_dp_link_test.c   | 763 ++++++++++++++++++
 1 file changed, 763 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
index e6feb68cb912f..10c4679f31efd 100644
--- a/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
+++ b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
@@ -82,12 +82,29 @@ struct link_config_set {
 	int size;
 };
 
+struct test_config_table {
+	struct kunit *test;
+
+	struct link_rate_set rates;
+	int max_lane_count;
+	struct link_config_set disabled_configs;
+};
+
 static const int standard_dp_link_rates[] = {
 	162000, 270000, 540000, 810000, 1000000, 1350000, 2000000
 };
 
 #define LINK_TEST_NUM_STANDARD_RATES (ARRAY_SIZE(standard_dp_link_rates))
 
+#define INIT_STANDARD_TABLE(__test, __num_rates, __max_lane_count) { \
+	.test = (__test), \
+	.rates = { \
+		.entries = standard_dp_link_rates, \
+		.size = (__num_rates), \
+	}, \
+	.max_lane_count = (__max_lane_count), \
+}
+
 static const struct link_config_set standard_dp_link_configs[] = {
 	[TEST_CONFIG_ORDER_KEY_BW] = {                        /* MBps    PBN    */
 		.entries = {
@@ -180,12 +197,56 @@ static const struct link_config_set standard_dp_link_configs[] = {
 	},
 };
 
+static int lookup_rate(const struct link_rate_set *rate_set, int rate)
+{
+	int i;
+
+	for (i = 0; i < rate_set->size; i++)
+		if (rate_set->entries[i] == rate)
+			return i;
+
+	return -1;
+}
+
+static bool has_rate(const struct link_rate_set *rate_set, int rate)
+{
+	return lookup_rate(rate_set, rate) >= 0;
+}
+
 static bool link_configs_match(const struct intel_dp_link_config *a,
 			       const struct intel_dp_link_config *b)
 {
 	return a->rate == b->rate && a->lane_count == b->lane_count;
 }
 
+static int lookup_config(const struct link_config_set *config_set,
+			 const struct intel_dp_link_config *config)
+{
+	int i;
+
+	for (i = 0; i < config_set->size; i++)
+		if (link_configs_match(&config_set->entries[i], config))
+			return i;
+
+	return -1;
+}
+
+static bool has_config(const struct link_config_set *config_set,
+		       const struct intel_dp_link_config *config)
+{
+	return lookup_config(config_set, config) >= 0;
+}
+
+static void add_config(struct kunit *test,
+		       struct link_config_set *config_set,
+		       const struct intel_dp_link_config *config)
+{
+	KUNIT_ASSERT_LT(test, config_set->size, ARRAY_SIZE(config_set->entries));
+
+	config_set->entries[config_set->size] = *config;
+	config_set->size++;
+}
+
 static u32 get_all_config_mask(void)
 {
 	return GENMASK_U32(LINK_TEST_MAX_CONFIGS - 1, 0);
@@ -274,9 +335,711 @@ static void intel_dp_link_caps_test_baseline(struct kunit *test)
 		baseline_test_for_order(test, link_caps, config_orders[i]);
 }
 
+static int get_num_configs(int num_rates, int max_lane_count)
+{
+	return num_rates * LINK_TEST_NUM_LANE_CONFIGS(max_lane_count);
+}
+
+static int rand_in_range(struct test_ctx *ctx, int min, int max)
+{
+	return min + (prandom_u32_state(&ctx->rnd) % (max - min + 1));
+}
+
+/*
+ * TEST: Update reset
+ * ------------------
+ * Verify that resetting link_caps with the DP standard rates/lane
+ * counts updates the configuration table accordingly for all
+ * combinations.
+ */
+static u32 get_link_caps_enabled_config_mask(struct kunit *test,
+					     struct intel_dp_link_caps *link_caps)
+{
+	struct test_ctx *ctx = test->priv;
+	const struct intel_dp_link_caps_test_ops *ops =
+		ctx->link_caps_ops;
+	struct intel_dp_link_config old_limits;
+	u32 mask;
+
+	/*
+	 * The link_caps allowed config mask is limited by both the disabled
+	 * state of the configs and the current max limits parameters. To get
+	 * the enabled mask unaffected by the max limit parameters, get the
+	 * allowed mask by resetting the max limits temporarily.
+	 */
+	ops->get_max_limits(link_caps, &old_limits);
+	ops->reset_max_limits(link_caps);
+
+	mask = ops->get_allowed_config_mask(link_caps);
+
+	ops->set_max_limits(link_caps, &old_limits);
+
+	return mask;
+}
+
+static void verify_bw_asc_config_order(struct kunit *test,
+				       const struct intel_dp_link_config *last_config,
+				       const struct intel_dp_link_config *config)
+{
+	int config_bw = drm_dp_max_dprx_data_rate(config->rate,
+						  config->lane_count);
+	int last_config_bw = drm_dp_max_dprx_data_rate(last_config->rate,
+							  last_config->lane_count);
+
+	KUNIT_EXPECT_GE(test, config_bw, last_config_bw);
+	if (config_bw == last_config_bw)
+		KUNIT_EXPECT_GT(test, config->rate, last_config->rate);
+}
+
+static void verify_bw_desc_config_order(struct kunit *test,
+					const struct intel_dp_link_config *last_config,
+					const struct intel_dp_link_config *config)
+{
+	int config_bw = drm_dp_max_dprx_data_rate(config->rate,
+						  config->lane_count);
+	int last_config_bw = drm_dp_max_dprx_data_rate(last_config->rate,
+							  last_config->lane_count);
+
+	KUNIT_EXPECT_LE(test, config_bw, last_config_bw);
+	if (config_bw == last_config_bw)
+		KUNIT_EXPECT_LT(test, config->rate, last_config->rate);
+}
+
+static void verify_rate_lane_asc_config_order(struct kunit *test,
+					      const struct intel_dp_link_config *last_config,
+					      const struct intel_dp_link_config *config)
+{
+	KUNIT_EXPECT_GE(test, config->rate, last_config->rate);
+	if (config->rate == last_config->rate)
+		KUNIT_EXPECT_GT(test, config->lane_count, last_config->lane_count);
+}
+
+static void verify_rate_lane_desc_config_order(struct kunit *test,
+					       const struct intel_dp_link_config *last_config,
+					       const struct intel_dp_link_config *config)
+{
+	KUNIT_EXPECT_LE(test, config->rate, last_config->rate);
+	if (config->rate == last_config->rate)
+		KUNIT_EXPECT_LT(test, config->lane_count, last_config->lane_count);
+}
+
+static void verify_config_order(struct kunit *test,
+				struct intel_dp_link_caps_config_order config_order,
+				const struct intel_dp_link_config *last_config,
+				const struct intel_dp_link_config *config)
+{
+	switch (config_order.key) {
+	case INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_BW:
+		if (config_order.dir == INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_ASC)
+			verify_bw_asc_config_order(test, last_config, config);
+		else
+			verify_bw_desc_config_order(test, last_config, config);
+		break;
+	case INTEL_DP_LINK_CAPS_CONFIG_ORDER_KEY_RATE_LANE:
+		if (config_order.dir == INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_ASC)
+			verify_rate_lane_asc_config_order(test, last_config, config);
+		else
+			verify_rate_lane_desc_config_order(test, last_config, config);
+		break;
+	default:
+		KUNIT_FAIL_AND_ABORT(test, "Missing order key: %d", config_order.key);
+	}
+}
+
+static void
+verify_link_caps_for_order(const struct test_config_table *expected_table,
+			   struct intel_dp_link_caps *link_caps,
+			   struct intel_dp_link_caps_config_order config_order)
+{
+	struct kunit *test = expected_table->test;
+	struct test_ctx *ctx = test->priv;
+	const struct intel_dp_link_caps_test_ops *ops =
+		ctx->link_caps_ops;
+	struct intel_dp_link_config expected_max_limits = {};
+	struct intel_dp_link_config actual_max_limits;
+	struct intel_dp_link_config last_config = {};
+	struct intel_dp_link_config iter_config;
+	int num_actual_configs = 0;
+	int iter_config_idx;
+
+	test_for_each_dp_link_config_idx(ctx, config_order, get_all_config_mask(),
+					 &iter_config, &iter_config_idx) {
+		bool config_disabled;
+
+		num_actual_configs++;
+
+		/*
+		 * Verify the config's rate/lane-count values and its ordering relative
+		 * to the previous config.
+		 */
+		if (last_config.rate)
+			verify_config_order(test, config_order, &last_config, &iter_config);
+		last_config = iter_config;
+
+		KUNIT_EXPECT_TRUE(test, has_rate(&expected_table->rates,
+						 iter_config.rate));
+		KUNIT_EXPECT_LE(test, iter_config.lane_count,
+				      expected_table->max_lane_count);
+		KUNIT_EXPECT_TRUE(test, is_power_of_2(iter_config.lane_count));
+
+		/* Verify the config's disabled state */
+		config_disabled = !(get_link_caps_enabled_config_mask(test, link_caps) &
+				    BIT(iter_config_idx));
+		KUNIT_EXPECT_EQ(test, config_disabled,
+				      has_config(&expected_table->disabled_configs,
+						 &iter_config));
+
+		/*
+		 * Update the max limits for allowed configs, verified at the
+		 * end for the whole config table.
+		 */
+		if (!(ops->get_allowed_config_mask(link_caps) &
+		      BIT(iter_config_idx)))
+			continue;
+
+		expected_max_limits.rate = max(expected_max_limits.rate,
+					       iter_config.rate);
+		expected_max_limits.lane_count = max(expected_max_limits.lane_count,
+						     iter_config.lane_count);
+	}
+
+	KUNIT_EXPECT_EQ(test, num_actual_configs,
+			      get_num_configs(expected_table->rates.size,
+					      expected_table->max_lane_count));
+
+	ops->get_max_limits(link_caps, &actual_max_limits);
+	KUNIT_EXPECT_TRUE(test, link_configs_match(&expected_max_limits,
+						   &actual_max_limits));
+}
+
+static void verify_link_caps(const struct test_config_table *expected_table,
+			     struct intel_dp_link_caps *link_caps)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(config_orders); i++)
+		verify_link_caps_for_order(expected_table, link_caps, config_orders[i]);
+}
+
+/*
+ * Filter out the disabled configs, which got removed after a configuration
+ * shrink step reduced the maximum rate and/or maximum lane count of the
+ * configurations.
+ *
+ * Also make sure that at least one configuration (the minimal config) remains
+ * enabled after a shrink step.
+ */
+static void update_disabled_configs(struct test_config_table *expected_table)
+{
+	struct kunit *test = expected_table->test;
+	struct link_config_set new_disabled_configs = {};
+	const struct intel_dp_link_config min_config = {
+		.rate = expected_table->rates.entries[0],
+		.lane_count = 1,
+	};
+	bool min_config_disabled = false;
+	int num_configs;
+	int i;
+
+	num_configs = get_num_configs(expected_table->rates.size,
+				      expected_table->max_lane_count);
+
+	for (i = 0; i < expected_table->disabled_configs.size; i++) {
+		const struct intel_dp_link_config *config =
+			&expected_table->disabled_configs.entries[i];
+
+		if (config->rate >
+			expected_table->rates.entries[expected_table->rates.size - 1] ||
+		    config->lane_count >
+			expected_table->max_lane_count)
+			continue;
+
+		/*
+		 * Mark the minimum config disabled only at the end, and only if that
+		 * would not leave all configs disabled.
+		 */
+		if (link_configs_match(config, &min_config)) {
+			min_config_disabled = true;
+
+			continue;
+		}
+
+		add_config(test, &new_disabled_configs, config);
+	}
+
+	expected_table->disabled_configs = new_disabled_configs;
+
+	if (min_config_disabled &&
+	    expected_table->disabled_configs.size + 1 < num_configs)
+		add_config(test, &expected_table->disabled_configs, &min_config);
+}
+
+static void update_link_caps_and_verify(struct test_config_table *expected_table,
+					struct intel_dp_link_caps *link_caps,
+					enum intel_dp_link_caps_update_mode update_mode)
+{
+	struct kunit *test = expected_table->test;
+	struct test_ctx *ctx = test->priv;
+	const struct intel_dp_link_caps_test_ops *ops =
+		ctx->link_caps_ops;
+
+	update_disabled_configs(expected_table);
+
+	ops->update(link_caps,
+		    expected_table->rates.entries, expected_table->rates.size,
+		    expected_table->max_lane_count,
+		    update_mode);
+
+	/*
+	 * In case of adding new configurations vs. replacing the current
+	 * ones with new ones, the max limits tracked by link_caps don't
+	 * get updated automatically, do that here as expected by all the
+	 * test cases.
+	 */
+	if (update_mode == INTEL_DP_LINK_CAPS_UPDATE_MERGE)
+		ops->reset_max_limits(link_caps);
+
+	verify_link_caps(expected_table, link_caps);
+}
+
+static void intel_dp_link_caps_test_update_reset(struct kunit *test)
+{
+	struct test_ctx *ctx = test->priv;
+	struct intel_dp_link_caps *link_caps = ctx->dev.dp.link.caps;
+	int max_lane_count;
+	int num_rates;
+
+	for (max_lane_count = 1;
+	     max_lane_count <= LINK_TEST_MAX_LANE_COUNT;
+	     max_lane_count <<= 1) {
+		for (num_rates = 1;
+		     num_rates <= LINK_TEST_NUM_STANDARD_RATES;
+		     num_rates++) {
+			struct test_config_table expected_table =
+				INIT_STANDARD_TABLE(test, num_rates,
+							     max_lane_count);
+
+			update_link_caps_and_verify(&expected_table, link_caps,
+						    INTEL_DP_LINK_CAPS_UPDATE_RESET);
+		}
+	}
+}
+
+/*
+ * TEST: Update shrink and expand
+ * ------------------------------
+ * Verify that removing or adding supported rates/lane counts updates
+ * the configuration table accordingly.
+ */
+static void disable_configs_and_verify(struct kunit *test,
+				       struct intel_dp_link_caps *link_caps,
+				       struct test_config_table *expected_table,
+				       const struct link_config_set *config_set)
+{
+	struct test_ctx *ctx = test->priv;
+	const struct intel_dp_link_caps_test_ops *ops =
+		ctx->link_caps_ops;
+	int i;
+
+	for (i = 0; i < config_set->size; i++) {
+		int config_idx;
+
+		config_idx = ops->find_allowed_config_idx(link_caps,
+							  INTEL_DP_LINK_CAPS_CONFIG_MATCH_EXACT,
+							  &config_set->entries[i]);
+		KUNIT_ASSERT_GE(test, config_idx, 0);
+
+		KUNIT_ASSERT_FALSE(test, has_config(&expected_table->disabled_configs,
+						    &config_set->entries[i]));
+		add_config(test, &expected_table->disabled_configs, &config_set->entries[i]);
+
+		ops->disable_config(link_caps, config_idx);
+
+		verify_link_caps(expected_table, link_caps);
+	}
+}
+
+static void disable_configs_for_shrink_and_verify(struct test_config_table *expected_table,
+						  struct intel_dp_link_caps *link_caps)
+{
+	struct kunit *test = expected_table->test;
+	struct link_config_set config_set = {};
+	struct intel_dp_link_config max_config;
+
+	/*
+	 * When configs shrink disable the config with the
+	 * second-highest rate,lane params, so the disabled config
+	 * stays around after the configs got shrunk.
+	 */
+	KUNIT_ASSERT_GE(test, expected_table->rates.size, 2);
+	KUNIT_ASSERT_GE(test, expected_table->max_lane_count, 2);
+
+	max_config.rate = expected_table->rates.entries[expected_table->rates.size - 2];
+	max_config.lane_count = expected_table->max_lane_count >> 1;
+
+	add_config(test, &config_set, &max_config);
+	disable_configs_and_verify(test, link_caps, expected_table,
+			&config_set);
+}
+
+static void disable_configs_for_expand_and_verify(struct test_config_table *expected_table,
+						  struct intel_dp_link_caps *link_caps)
+{
+	struct kunit *test = expected_table->test;
+	struct link_config_set config_set = {};
+	struct intel_dp_link_config max_config;
+
+	KUNIT_ASSERT_GE(test, expected_table->rates.size, 1);
+
+	max_config.rate = expected_table->rates.entries[expected_table->rates.size - 1];
+	max_config.lane_count = expected_table->max_lane_count;
+
+	add_config(test, &config_set, &max_config);
+	disable_configs_and_verify(test, link_caps, expected_table,
+				   &config_set);
+}
+
+static void get_nth_rate_lane_config(const struct test_config_table *expected_table, int n,
+				     struct intel_dp_link_config *config)
+{
+	int num_lane_configs = LINK_TEST_NUM_LANE_CONFIGS(expected_table->max_lane_count);
+	int rate_idx = n / num_lane_configs;
+	int lane_count_exp = n % num_lane_configs;
+
+	config->rate = expected_table->rates.entries[rate_idx];
+	config->lane_count = 1 << lane_count_exp;
+}
+
+static void test_update_rates_shrink(struct kunit *test, bool disable_configs)
+{
+	struct test_ctx *ctx = test->priv;
+	struct intel_dp_link_caps *link_caps = ctx->dev.dp.link.caps;
+	struct test_config_table expected_table =
+		INIT_STANDARD_TABLE(test, LINK_TEST_NUM_STANDARD_RATES,
+					  LINK_TEST_MAX_LANE_COUNT);
+
+	update_link_caps_and_verify(&expected_table, link_caps,
+				    INTEL_DP_LINK_CAPS_UPDATE_RESET);
+
+	while (expected_table.rates.size > 1) {
+		if (disable_configs)
+			disable_configs_for_shrink_and_verify(&expected_table, link_caps);
+
+		expected_table.rates.size--;
+
+		update_link_caps_and_verify(&expected_table, link_caps,
+					    INTEL_DP_LINK_CAPS_UPDATE_MERGE);
+	}
+}
+
+static void intel_dp_link_caps_test_update_rates_shrink(struct kunit *test)
+{
+	test_update_rates_shrink(test, false);
+}
+
+static void intel_dp_link_caps_test_update_rates_shrink_disable(struct kunit *test)
+{
+	test_update_rates_shrink(test, true);
+}
+
+static void test_update_rates_expand(struct kunit *test, bool disable_configs)
+{
+	struct test_ctx *ctx = test->priv;
+	struct intel_dp_link_caps *link_caps = ctx->dev.dp.link.caps;
+	struct test_config_table expected_table =
+		INIT_STANDARD_TABLE(test, 1, LINK_TEST_MAX_LANE_COUNT);
+
+	update_link_caps_and_verify(&expected_table, link_caps,
+				    INTEL_DP_LINK_CAPS_UPDATE_RESET);
+
+	while (expected_table.rates.size < LINK_TEST_NUM_STANDARD_RATES) {
+		if (disable_configs)
+			disable_configs_for_expand_and_verify(&expected_table, link_caps);
+
+		expected_table.rates.size++;
+
+		update_link_caps_and_verify(&expected_table, link_caps,
+					    INTEL_DP_LINK_CAPS_UPDATE_MERGE);
+	}
+}
+
+static void intel_dp_link_caps_test_update_rates_expand(struct kunit *test)
+{
+	test_update_rates_expand(test, false);
+}
+
+static void intel_dp_link_caps_test_update_rates_expand_disable(struct kunit *test)
+{
+	test_update_rates_expand(test, true);
+}
+
+static void test_update_lanes_shrink(struct kunit *test, bool disable_configs)
+{
+	struct test_ctx *ctx = test->priv;
+	struct intel_dp_link_caps *link_caps = ctx->dev.dp.link.caps;
+	struct test_config_table expected_table =
+		INIT_STANDARD_TABLE(test, LINK_TEST_NUM_STANDARD_RATES,
+					  LINK_TEST_MAX_LANE_COUNT);
+
+	update_link_caps_and_verify(&expected_table, link_caps,
+				    INTEL_DP_LINK_CAPS_UPDATE_RESET);
+
+	while (expected_table.max_lane_count > 1) {
+		if (disable_configs)
+			disable_configs_for_shrink_and_verify(&expected_table, link_caps);
+
+		expected_table.max_lane_count >>= 1;
+
+		update_link_caps_and_verify(&expected_table, link_caps,
+					    INTEL_DP_LINK_CAPS_UPDATE_MERGE);
+	}
+}
+
+static void intel_dp_link_caps_test_update_lanes_shrink(struct kunit *test)
+{
+	test_update_lanes_shrink(test, false);
+}
+
+static void intel_dp_link_caps_test_update_lanes_shrink_disable(struct kunit *test)
+{
+	test_update_lanes_shrink(test, true);
+}
+
+static void test_update_lanes_expand(struct kunit *test, bool disable_configs)
+{
+	struct test_ctx *ctx = test->priv;
+	struct intel_dp_link_caps *link_caps = ctx->dev.dp.link.caps;
+	struct test_config_table expected_table =
+		INIT_STANDARD_TABLE(test, LINK_TEST_NUM_STANDARD_RATES, 1);
+
+	update_link_caps_and_verify(&expected_table, link_caps,
+				    INTEL_DP_LINK_CAPS_UPDATE_RESET);
+
+	while (expected_table.max_lane_count < LINK_TEST_MAX_LANE_COUNT) {
+		if (disable_configs)
+			disable_configs_for_expand_and_verify(&expected_table, link_caps);
+
+		expected_table.max_lane_count <<= 1;
+
+		update_link_caps_and_verify(&expected_table, link_caps,
+					    INTEL_DP_LINK_CAPS_UPDATE_MERGE);
+	}
+}
+
+static void intel_dp_link_caps_test_update_lanes_expand(struct kunit *test)
+{
+	test_update_lanes_expand(test, false);
+}
+
+static void intel_dp_link_caps_test_update_lanes_expand_disable(struct kunit *test)
+{
+	test_update_lanes_expand(test, true);
+}
+
+static void disable_random_configs_and_verify(struct test_config_table *expected_table,
+					      struct intel_dp_link_caps *link_caps)
+{
+	struct kunit *test = expected_table->test;
+	struct test_ctx *ctx = test->priv;
+	struct link_config_set config_set = {};
+	u32 disabled_config_mask;
+	int num_configs;
+	int i;
+
+	num_configs = get_num_configs(expected_table->rates.size,
+				      expected_table->max_lane_count);
+	disabled_config_mask = prandom_u32_state(&ctx->rnd) &
+			       GENMASK_U32(num_configs - 1, 0);
+
+	for (i = 0; i < num_configs; i++) {
+		struct intel_dp_link_config config;
+
+		/* At least one config must remain enabled. */
+		if (expected_table->disabled_configs.size +
+		    config_set.size + 1 >= num_configs)
+			break;
+
+		if (!(BIT(i) & disabled_config_mask))
+			continue;
+
+		get_nth_rate_lane_config(expected_table, i, &config);
+		/* Don't disable a config twice. */
+		if (has_config(&expected_table->disabled_configs, &config))
+			continue;
+
+		add_config(test, &config_set, &config);
+	}
+
+	disable_configs_and_verify(test, link_caps, expected_table,
+				   &config_set);
+}
+
+static void get_params_shrink_step(struct test_ctx *ctx,
+				   int num_rates, int max_lane_count,
+				   int *rates_step, int *lanes_step)
+{
+	int shrink_mask;
+
+	*rates_step = 0;
+	*lanes_step = 0;
+
+	if (num_rates == 1)
+		shrink_mask = BIT(0);				/* shrink only lanes */
+	else if (max_lane_count == 1)
+		shrink_mask = BIT(1);				/* shrink only rates */
+	else
+		shrink_mask = rand_in_range(ctx,
+					    BIT(0),
+					    BIT(0) | BIT(1));	/* shrink one or both params */
+
+	if (shrink_mask & BIT(1))
+		*rates_step = rand_in_range(ctx, 1, num_rates - 1);
+
+	if (shrink_mask & BIT(0))
+		*lanes_step = rand_in_range(ctx, 1, ilog2(max_lane_count));
+}
+
+static void get_params_expand_step(struct test_ctx *ctx,
+				   int max_num_rates, int num_rates,
+				   int max_supported_lane_count, int max_lane_count,
+				   int *rates_step, int *lanes_step)
+{
+	int expand_mask;
+
+	*rates_step = 0;
+	*lanes_step = 0;
+
+	if (num_rates == max_num_rates)
+		expand_mask = BIT(0);				/* expand only lanes */
+	else if (max_lane_count == max_supported_lane_count)
+		expand_mask = BIT(1);				/* expand only rates */
+	else
+		expand_mask = rand_in_range(ctx,
+					    BIT(0),
+					    BIT(0) | BIT(1));	/* expand one or both params */
+
+	if (expand_mask & BIT(1))
+		*rates_step = rand_in_range(ctx, 1, max_num_rates - num_rates);
+
+	if (expand_mask & BIT(0))
+		*lanes_step = rand_in_range(ctx, 1, ilog2(max_supported_lane_count /
+							  max_lane_count));
+}
+
+static void test_update_params_shrink_random(struct kunit *test, bool disable_configs)
+{
+	struct test_ctx *ctx = test->priv;
+	struct intel_dp_link_caps *link_caps = ctx->dev.dp.link.caps;
+	struct test_config_table expected_table =
+		INIT_STANDARD_TABLE(test, LINK_TEST_NUM_STANDARD_RATES,
+						   LINK_TEST_MAX_LANE_COUNT);
+
+	update_link_caps_and_verify(&expected_table, link_caps,
+				    INTEL_DP_LINK_CAPS_UPDATE_RESET);
+
+	while (expected_table.rates.size > 1 || expected_table.max_lane_count > 1) {
+		int rates_step;
+		int lanes_step;
+
+		if (disable_configs)
+			disable_random_configs_and_verify(&expected_table, link_caps);
+
+		get_params_shrink_step(ctx,
+				       expected_table.rates.size,
+				       expected_table.max_lane_count,
+				       &rates_step, &lanes_step);
+
+		expected_table.rates.size -= rates_step;
+		expected_table.max_lane_count >>= lanes_step;
+
+		update_link_caps_and_verify(&expected_table, link_caps,
+					    INTEL_DP_LINK_CAPS_UPDATE_MERGE);
+	}
+}
+
+static void intel_dp_link_caps_test_update_params_shrink_random(struct kunit *test)
+{
+	int i;
+
+	for (i = 0; i < LINK_TEST_NUM_RANDOM_ITERATIONS; i++)
+		test_update_params_shrink_random(test, false);
+}
+
+static void intel_dp_link_caps_test_update_params_shrink_disable_random(struct kunit *test)
+{
+	int i;
+
+	for (i = 0; i < LINK_TEST_NUM_RANDOM_ITERATIONS; i++)
+		test_update_params_shrink_random(test, true);
+}
+
+static void test_update_params_expand_random(struct kunit *test, bool disable_configs)
+{
+	struct test_ctx *ctx = test->priv;
+	struct intel_dp_link_caps *link_caps = ctx->dev.dp.link.caps;
+	struct test_config_table expected_table =
+		INIT_STANDARD_TABLE(test, 1, 1);
+
+	update_link_caps_and_verify(&expected_table, link_caps,
+				    INTEL_DP_LINK_CAPS_UPDATE_RESET);
+
+	while (expected_table.rates.size < LINK_TEST_NUM_STANDARD_RATES ||
+	       expected_table.max_lane_count < LINK_TEST_MAX_LANE_COUNT) {
+		int rates_step;
+		int lanes_step;
+
+		if (disable_configs)
+			disable_random_configs_and_verify(&expected_table, link_caps);
+
+		get_params_expand_step(ctx,
+				       LINK_TEST_NUM_STANDARD_RATES,
+				       expected_table.rates.size,
+				       LINK_TEST_MAX_LANE_COUNT,
+				       expected_table.max_lane_count,
+				       &rates_step, &lanes_step);
+
+		expected_table.rates.size += rates_step;
+		expected_table.max_lane_count <<= lanes_step;
+
+		update_link_caps_and_verify(&expected_table, link_caps,
+					    INTEL_DP_LINK_CAPS_UPDATE_MERGE);
+	}
+}
+
+static void intel_dp_link_caps_test_update_params_expand_random(struct kunit *test)
+{
+	int i;
+
+	for (i = 0; i < LINK_TEST_NUM_RANDOM_ITERATIONS; i++)
+		test_update_params_expand_random(test, false);
+}
+
+static void intel_dp_link_caps_test_update_params_expand_disable_random(struct kunit *test)
+{
+	int i;
+
+	for (i = 0; i < LINK_TEST_NUM_RANDOM_ITERATIONS; i++)
+		test_update_params_expand_random(test, true);
+}
+
 static struct kunit_case intel_dp_link_test_cases[] = {
 	KUNIT_CASE(intel_dp_link_caps_test_baseline),
 
+	KUNIT_CASE(intel_dp_link_caps_test_update_reset),
+
+	KUNIT_CASE(intel_dp_link_caps_test_update_rates_shrink),
+	KUNIT_CASE(intel_dp_link_caps_test_update_rates_shrink_disable),
+	KUNIT_CASE(intel_dp_link_caps_test_update_rates_expand),
+	KUNIT_CASE(intel_dp_link_caps_test_update_rates_expand_disable),
+	KUNIT_CASE(intel_dp_link_caps_test_update_lanes_shrink),
+	KUNIT_CASE(intel_dp_link_caps_test_update_lanes_shrink_disable),
+	KUNIT_CASE(intel_dp_link_caps_test_update_lanes_expand),
+	KUNIT_CASE(intel_dp_link_caps_test_update_lanes_expand_disable),
+	KUNIT_CASE(intel_dp_link_caps_test_update_params_shrink_random),
+	KUNIT_CASE(intel_dp_link_caps_test_update_params_shrink_disable_random),
+	KUNIT_CASE(intel_dp_link_caps_test_update_params_expand_random),
+	KUNIT_CASE(intel_dp_link_caps_test_update_params_expand_disable_random),
+
 	{}
 };
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* [PATCH 108/108] drm/i915/kunit: DP link: add fallback tests
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (106 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 107/108] drm/i915/kunit: DP link: add update config tests Imre Deak
@ 2026-04-28 12:52 ` Imre Deak
  2026-04-28 14:38 ` ✗ Fi.CI.BUILD: failure for drm/i915/dp_link: Refactor DP link capability logic Patchwork
                   ` (2 subsequent siblings)
  110 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-28 12:52 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add KUnit tests for DP link fallback selection across eDP, SST, and MST.
Verify that the fallback logic properly selects the maximum allowed
configuration, iterates through allowed configurations, and disables
failed configs as expected.

These tests include UHBR vs. non-UHBR conditions, MST vs. SST mode,
and validate that subsequent fallback selections respect the updated
allowed configuration mask.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 .../i915/display/tests/intel_dp_link_test.c   | 316 ++++++++++++++++++
 1 file changed, 316 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
index 10c4679f31efd..c90281dedb3a0 100644
--- a/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
+++ b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
@@ -1022,6 +1022,317 @@ static void intel_dp_link_caps_test_update_params_expand_disable_random(struct k
 		test_update_params_expand_random(test, true);
 }
 
+/*
+ * TEST: Fallback sequence
+ * -----------------------
+ * Verify the eDP fallback logic to set the maximum supported configuration
+ * as a preference.
+ *
+ * For DP SST and MST verify fallback selection from the connector's
+ * maximum configuration and iteration of the resulting allowed
+ * configurations.
+ */
+static void intel_dp_link_test_fallback_for_edp(struct kunit *test)
+{
+	struct test_ctx *ctx = test->priv;
+	struct intel_dp_link_caps *link_caps = ctx->dev.dp.link.caps;
+	struct test_config_table expected_table =
+		INIT_STANDARD_TABLE(test, LINK_TEST_NUM_STANDARD_RATES,
+					  LINK_TEST_MAX_LANE_COUNT);
+	struct intel_digital_port *dig_port = dp_to_dig_port(&ctx->dev.dp);
+	const struct intel_dp_link_training_test_ops *lt_ops =
+		ctx->link_training_ops;
+	const struct intel_dp_link_caps_test_ops *lc_ops =
+		ctx->link_caps_ops;
+	struct intel_dp_link_config min_config = {
+		.rate = expected_table.rates.entries[0],
+		.lane_count = 1,
+	};
+	struct intel_dp_link_config max_config = {
+		.rate = expected_table.rates.entries[expected_table.rates.size - 1],
+		.lane_count = LINK_TEST_MAX_LANE_COUNT,
+	};
+	struct intel_dp_link_config iter_config;
+	int fallback_err;
+
+	dig_port->base.type = INTEL_OUTPUT_EDP;
+	ctx->dev.dp.use_max_params = false;
+
+	update_link_caps_and_verify(&expected_table, link_caps,
+				    INTEL_DP_LINK_CAPS_UPDATE_RESET);
+
+	test_for_each_dp_link_config(ctx,
+				     lc_ops->config_order_for_connector(&ctx->dev.connector),
+				     lc_ops->get_allowed_config_mask(link_caps),
+				     &iter_config)
+		break;
+
+	KUNIT_EXPECT_FALSE(test, ctx->dev.dp.use_max_params);
+	KUNIT_EXPECT_TRUE(test, link_configs_match(&iter_config, &min_config));
+
+	ctx->dev.crtc_state.output_types = BIT(dig_port->base.type);
+	ctx->dev.crtc_state.port_clock = min_config.rate;
+	ctx->dev.crtc_state.lane_count = min_config.lane_count;
+
+	fallback_err = lt_ops->get_fallback_values(&ctx->dev.dp, &ctx->dev.crtc_state);
+	KUNIT_EXPECT_EQ(test, fallback_err, 0);
+
+	/* The fallback should've changed the order. */
+	test_for_each_dp_link_config(ctx,
+				     lc_ops->config_order_for_connector(&ctx->dev.connector),
+				     lc_ops->get_allowed_config_mask(link_caps),
+				     &iter_config)
+		break;
+
+	KUNIT_EXPECT_TRUE(test, ctx->dev.dp.use_max_params);
+	KUNIT_EXPECT_TRUE(test, link_configs_match(&iter_config, &max_config));
+}
+
+static bool test_fallback_from_target(struct test_config_table *expected_table,
+				      enum intel_output_type output_type, int max_rate,
+				      const struct intel_dp_link_config *expected_target_config,
+				      const struct intel_dp_link_config *expected_fallback_config)
+{
+	struct kunit *test = expected_table->test;
+	struct test_ctx *ctx = test->priv;
+	struct intel_dp_link_caps *link_caps = ctx->dev.dp.link.caps;
+	struct intel_dp_link_config iter_config;
+	const struct intel_dp_link_training_test_ops *lt_ops =
+		ctx->link_training_ops;
+	const struct intel_dp_link_caps_test_ops *lc_ops =
+		ctx->link_caps_ops;
+	/* Modify default order direction for max config lookup. */
+	struct intel_dp_link_caps_config_order connector_desc_order = {
+		.key = lc_ops->config_order_for_connector(&ctx->dev.connector).key,
+		.dir = INTEL_DP_LINK_CAPS_CONFIG_ORDER_DIR_DESC,
+	};
+	int expected_fallback_err = 0;
+	int fallback_err;
+
+	/* Get the max connector config, optionally filtered to the max_rate limit. */
+	test_for_each_dp_link_config(ctx, connector_desc_order,
+				     lc_ops->get_allowed_config_mask(link_caps),
+				     &iter_config)
+		if (max_rate == 0 || iter_config.rate <= max_rate)
+			break;
+
+	KUNIT_EXPECT_TRUE(test, link_configs_match(&iter_config,
+						   expected_target_config));
+	KUNIT_EXPECT_FALSE(test, link_configs_match(&iter_config,
+						    &INTEL_DP_LINK_CONFIG_NULL));
+
+	ctx->dev.crtc_state.output_types = BIT(output_type);
+	ctx->dev.crtc_state.port_clock = expected_target_config->rate;
+	ctx->dev.crtc_state.lane_count = expected_target_config->lane_count;
+
+	if (link_configs_match(expected_fallback_config, &INTEL_DP_LINK_CONFIG_NULL))
+		expected_fallback_err = -1;
+
+	fallback_err = lt_ops->get_fallback_values(&ctx->dev.dp, &ctx->dev.crtc_state);
+	KUNIT_EXPECT_EQ(test, fallback_err, expected_fallback_err);
+
+	if (!fallback_err) {
+		/*
+		 * NOTE: This test does not verify any implied fallback
+		 * target selection.
+		 *
+		 * The current driver behavior may still select a fallback
+		 * configuration indirectly via max_limits, but that is an
+		 * implementation artifact rather than part of the intended
+		 * fallback API behavior, and is therefore not verified here.
+		 *
+		 * Instead, the effect of the fallback logic is verified by
+		 * checking that the failed target configuration is disabled.
+		 * Selecting the next target configuration from the remaining
+		 * allowed configurations belongs to the modeset link target
+		 * selection logic.
+		 */
+		add_config(test, &expected_table->disabled_configs,
+			   expected_target_config);
+	}
+
+	verify_link_caps(expected_table, link_caps);
+
+	return !fallback_err;
+}
+
+static const struct link_config_set *
+get_target_configs_for_output_type(struct kunit *test,
+				   enum intel_output_type output_type)
+{
+	switch (output_type) {
+	case INTEL_OUTPUT_DDI:
+	case INTEL_OUTPUT_DP:
+	case INTEL_OUTPUT_EDP:
+		return &standard_dp_link_configs[TEST_CONFIG_ORDER_KEY_RATE_LANE];
+	case INTEL_OUTPUT_DP_MST:
+		return &standard_dp_link_configs[TEST_CONFIG_ORDER_KEY_BW];
+	default:
+		KUNIT_FAIL_AND_ABORT(test, "Missing output type: %d", output_type);
+
+	}
+}
+
+static const struct link_config_set *
+get_fallback_configs_for_output_type(struct kunit *test,
+				     enum intel_output_type output_type)
+{
+	switch (output_type) {
+	case INTEL_OUTPUT_DDI:
+	case INTEL_OUTPUT_DP:
+	case INTEL_OUTPUT_EDP:
+		return &standard_dp_link_configs[TEST_CONFIG_ORDER_KEY_LANE_RATE];
+	case INTEL_OUTPUT_DP_MST:
+		return &standard_dp_link_configs[TEST_CONFIG_ORDER_KEY_BW];
+	default:
+		KUNIT_FAIL_AND_ABORT(test, "Missing output type: %d", output_type);
+
+	}
+}
+
+static bool output_type_allows_uhbr_fallback(enum intel_output_type output_type)
+{
+	return output_type == INTEL_OUTPUT_DP_MST;
+}
+
+static void assert_config_is_supported(const struct test_config_table *expected_table,
+				       const struct intel_dp_link_config *config)
+{
+	struct kunit *test = expected_table->test;
+
+	KUNIT_ASSERT_TRUE(test, has_rate(&expected_table->rates, config->rate));
+	KUNIT_ASSERT_LE(test, config->lane_count, expected_table->max_lane_count);
+}
+
+static bool get_fallback_config(const struct test_config_table *expected_table,
+				enum intel_output_type output_type,
+				const struct intel_dp_link_config *target_config,
+				struct intel_dp_link_config *fallback_config)
+{
+	struct kunit *test = expected_table->test;
+	const struct link_config_set *config_set =
+		get_fallback_configs_for_output_type(test, output_type);
+	int i;
+
+	i = lookup_config(config_set, target_config);
+	KUNIT_ASSERT_GE(test, i, 0);
+
+	for (i--; i >= 0; i--) {
+		const struct intel_dp_link_config *config =
+			&config_set->entries[i];
+
+		if (output_type_allows_uhbr_fallback(output_type) ||
+		    !drm_dp_is_uhbr_rate(target_config->rate) ||
+		    drm_dp_is_uhbr_rate(config->rate)) {
+			assert_config_is_supported(expected_table, config);
+			*fallback_config = *config;
+
+			return true;
+		}
+	}
+
+	return false;
+}
+
+static bool get_target_config(const struct test_config_table *expected_table,
+			      enum intel_output_type output_type,
+			      int max_rate,
+			      struct intel_dp_link_config *target)
+{
+	struct kunit *test = expected_table->test;
+	const struct link_config_set *config_set =
+		get_target_configs_for_output_type(test, output_type);
+	int i;
+
+	for (i = config_set->size - 1; i >= 0; i--) {
+		const struct intel_dp_link_config *config =
+			&config_set->entries[i];
+
+		if (config->rate <= max_rate) {
+			assert_config_is_supported(expected_table, config);
+			*target = *config;
+
+			return true;
+		}
+	}
+
+	return false;
+}
+
+static void test_fallback_seq(struct kunit *test,
+			      enum intel_output_type output_type,
+			      bool uhbr)
+{
+	struct test_ctx *ctx = test->priv;
+	struct intel_dp_link_caps *link_caps = ctx->dev.dp.link.caps;
+	struct test_config_table expected_table =
+		INIT_STANDARD_TABLE(test, LINK_TEST_NUM_STANDARD_RATES,
+					  LINK_TEST_MAX_LANE_COUNT);
+	struct intel_digital_port *dig_port = dp_to_dig_port(&ctx->dev.dp);
+	struct intel_dp_link_config fallback_config = {};
+	struct intel_dp_link_config target_config;
+	int fallback_count = 0;
+	bool target_found;
+	int max_rate;
+
+	if (uhbr)
+		max_rate = expected_table.rates.entries[expected_table.rates.size - 1];
+	else
+		max_rate = 810000;
+
+	dig_port->base.type = output_type;
+	ctx->dev.dp.use_max_params = false;
+
+	update_link_caps_and_verify(&expected_table, link_caps, INTEL_DP_LINK_CAPS_UPDATE_RESET);
+
+	/* Get the initial target config. */
+	target_found = get_target_config(&expected_table, output_type,
+					max_rate, &target_config);
+	KUNIT_ASSERT_TRUE(test, target_found);
+
+	for (;;) {
+		/* Also test the case where no fallback is available. */
+		if (!get_fallback_config(&expected_table, output_type,
+					 &target_config, &fallback_config))
+			fallback_config = INTEL_DP_LINK_CONFIG_NULL;
+
+		if (!test_fallback_from_target(&expected_table, output_type, max_rate,
+					       &target_config, &fallback_config))
+			break;
+
+		/*
+		 * The fallback changed the max rate allowed for the next
+		 * target.
+		 */
+		max_rate = fallback_config.rate;
+
+		/* Simply select the fallback config as the next target. */
+		target_config = fallback_config;
+
+		fallback_count++;
+		KUNIT_ASSERT_LT(test, fallback_count, LINK_TEST_MAX_CONFIGS);
+	}
+}
+
+static void intel_dp_link_test_fallback_for_sst_max_non_uhbr(struct kunit *test)
+{
+	test_fallback_seq(test, INTEL_OUTPUT_DP, false);
+}
+
+static void intel_dp_link_test_fallback_for_sst_max_uhbr(struct kunit *test)
+{
+	test_fallback_seq(test, INTEL_OUTPUT_DP, true);
+}
+
+static void intel_dp_link_test_fallback_for_mst(struct kunit *test)
+{
+	struct test_ctx *ctx = test->priv;
+
+	ctx->dev.connector.mst.dp = &ctx->dev.dp;
+
+	test_fallback_seq(test, INTEL_OUTPUT_DP_MST, true);
+}
+
 static struct kunit_case intel_dp_link_test_cases[] = {
 	KUNIT_CASE(intel_dp_link_caps_test_baseline),
 
@@ -1040,6 +1351,11 @@ static struct kunit_case intel_dp_link_test_cases[] = {
 	KUNIT_CASE(intel_dp_link_caps_test_update_params_expand_random),
 	KUNIT_CASE(intel_dp_link_caps_test_update_params_expand_disable_random),
 
+	KUNIT_CASE(intel_dp_link_test_fallback_for_edp),
+	KUNIT_CASE(intel_dp_link_test_fallback_for_sst_max_non_uhbr),
+	KUNIT_CASE(intel_dp_link_test_fallback_for_sst_max_uhbr),
+	KUNIT_CASE(intel_dp_link_test_fallback_for_mst),
+
 	{}
 };
 
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* ✗ Fi.CI.BUILD: failure for drm/i915/dp_link: Refactor DP link capability logic
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (107 preceding siblings ...)
  2026-04-28 12:52 ` [PATCH 108/108] drm/i915/kunit: DP link: add fallback tests Imre Deak
@ 2026-04-28 14:38 ` Patchwork
  2026-04-29  9:17 ` ✓ i915.CI.BAT: success for drm/i915/dp_link: Refactor DP link capability logic (rev2) Patchwork
  2026-04-29 15:35 ` ✗ i915.CI.Full: failure " Patchwork
  110 siblings, 0 replies; 113+ messages in thread
From: Patchwork @ 2026-04-28 14:38 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx

== Series Details ==

Series: drm/i915/dp_link: Refactor DP link capability logic
URL   : https://patchwork.freedesktop.org/series/165632/
State : failure

== Summary ==

Error: make failed
  DESCEND objtool
  INSTALL libsubcmd_headers
  HDRTEST drivers/gpu/drm/xe/generated/xe_wa_oob.h
  HDRTEST drivers/gpu/drm/xe/generated/xe_device_wa_oob.h
  MODPOST Module.symvers
ERROR: modpost: missing MODULE_LICENSE() in drivers/gpu/drm/xe/display/tests/xe_display_test.o
make[2]: *** [scripts/Makefile.modpost:147: Module.symvers] Error 1
make[1]: *** [/home/kbuild2/kernel/Makefile:2091: modpost] Error 2
make: *** [Makefile:248: __sub-make] Error 2
Build failed, no error log produced



^ permalink raw reply	[flat|nested] 113+ messages in thread

* [PATCH v2 101/108] drm/i915/kunit: Add DP link test stub
  2026-04-28 12:52 ` [PATCH 101/108] drm/i915/kunit: Add DP link test stub Imre Deak
@ 2026-04-29  7:36   ` Imre Deak
  0 siblings, 0 replies; 113+ messages in thread
From: Imre Deak @ 2026-04-29  7:36 UTC (permalink / raw)
  To: intel-gfx, intel-xe

Add a Kunit stub test module for DP link test cases.

v2: Add missing module license.

Signed-off-by: Imre Deak <imre.deak@intel.com>
---
 drivers/gpu/drm/i915/Makefile                 |  2 +
 drivers/gpu/drm/i915/display/tests/Makefile   |  7 +++
 .../i915/display/tests/intel_dp_link_test.c   | 47 +++++++++++++++++++
 3 files changed, 56 insertions(+)
 create mode 100644 drivers/gpu/drm/i915/display/tests/Makefile
 create mode 100644 drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 0c04c6d9bb13e..ff2b22271454b 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -385,6 +385,8 @@ i915-y += \
 i915-$(CONFIG_DRM_I915_DP_TUNNEL) += \
 	display/intel_dp_tunnel.o
 
+obj-$(CONFIG_DRM_I915_KUNIT_TEST) += display/tests/
+
 i915-$(CONFIG_DRM_I915_GVT) += \
 	display/intel_gvt_api.o
 
diff --git a/drivers/gpu/drm/i915/display/tests/Makefile b/drivers/gpu/drm/i915/display/tests/Makefile
new file mode 100644
index 0000000000000..ad250974160f6
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/tests/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+
+subdir-ccflags-y += -I$(srctree)/drivers/gpu/drm/i915/display/
+
+obj-$(CONFIG_DRM_I915_KUNIT_TEST) += i915_display_test.o
+i915_display_test-y = \
+	intel_dp_link_test.o
diff --git a/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
new file mode 100644
index 0000000000000..62e1844605ac5
--- /dev/null
+++ b/drivers/gpu/drm/i915/display/tests/intel_dp_link_test.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+#include <kunit/test.h>
+
+struct test_ctx {
+};
+
+static struct kunit_case intel_dp_link_test_cases[] = {
+	{}
+};
+
+static struct test_ctx test_ctx;
+
+static int intel_dp_link_test_init(struct kunit *test)
+{
+	test->priv = &test_ctx;
+
+	return 0;
+}
+
+static void intel_dp_link_test_exit(struct kunit *test)
+{
+}
+
+static int intel_dp_link_test_suite_init(struct kunit_suite *test_suite)
+{
+	return 0;
+}
+
+static struct kunit_suite intel_dp_link_test_suite = {
+	.name = "intel_dp_link",
+	.suite_init = intel_dp_link_test_suite_init,
+	.init = intel_dp_link_test_init,
+	.exit = intel_dp_link_test_exit,
+	.test_cases = intel_dp_link_test_cases,
+};
+
+kunit_test_suites(&intel_dp_link_test_suite);
+
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL and additional rights");
+MODULE_DESCRIPTION("Intel DP link KUnit tests");
-- 
2.49.1


^ permalink raw reply related	[flat|nested] 113+ messages in thread

* ✓ i915.CI.BAT: success for drm/i915/dp_link: Refactor DP link capability logic (rev2)
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (108 preceding siblings ...)
  2026-04-28 14:38 ` ✗ Fi.CI.BUILD: failure for drm/i915/dp_link: Refactor DP link capability logic Patchwork
@ 2026-04-29  9:17 ` Patchwork
  2026-04-29 15:35 ` ✗ i915.CI.Full: failure " Patchwork
  110 siblings, 0 replies; 113+ messages in thread
From: Patchwork @ 2026-04-29  9:17 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx

[-- Attachment #1: Type: text/plain, Size: 6629 bytes --]

== Series Details ==

Series: drm/i915/dp_link: Refactor DP link capability logic (rev2)
URL   : https://patchwork.freedesktop.org/series/165632/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_18377 -> Patchwork_165632v2
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/index.html

Participating hosts (40 -> 40)
------------------------------

  Additional (2): fi-glk-j4005 bat-adls-6 
  Missing    (2): bat-dg2-13 fi-snb-2520m 

Known issues
------------

  Here are the changes found in Patchwork_165632v2 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@dmabuf@all-tests:
    - bat-adls-6:         NOTRUN -> [SKIP][1] ([i915#15931])
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-adls-6/igt@dmabuf@all-tests.html

  * igt@gem_huc_copy@huc-copy:
    - fi-glk-j4005:       NOTRUN -> [SKIP][2] ([i915#2190])
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/fi-glk-j4005/igt@gem_huc_copy@huc-copy.html

  * igt@gem_lmem_swapping@parallel-random-engines:
    - bat-adls-6:         NOTRUN -> [SKIP][3] ([i915#4613]) +3 other tests skip
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-adls-6/igt@gem_lmem_swapping@parallel-random-engines.html
    - fi-glk-j4005:       NOTRUN -> [SKIP][4] ([i915#4613]) +3 other tests skip
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/fi-glk-j4005/igt@gem_lmem_swapping@parallel-random-engines.html

  * igt@gem_tiled_pread_basic@basic:
    - bat-adls-6:         NOTRUN -> [SKIP][5] ([i915#15656])
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-adls-6/igt@gem_tiled_pread_basic@basic.html

  * igt@intel_hwmon@hwmon-read:
    - bat-adls-6:         NOTRUN -> [SKIP][6] ([i915#7707]) +1 other test skip
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-adls-6/igt@intel_hwmon@hwmon-read.html

  * igt@kms_cursor_legacy@basic-busy-flip-before-cursor-legacy:
    - bat-adls-6:         NOTRUN -> [SKIP][7] ([i915#4103]) +1 other test skip
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-adls-6/igt@kms_cursor_legacy@basic-busy-flip-before-cursor-legacy.html

  * igt@kms_dsc@dsc-basic:
    - bat-adls-6:         NOTRUN -> [SKIP][8] ([i915#3555] / [i915#3840])
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-adls-6/igt@kms_dsc@dsc-basic.html

  * igt@kms_force_connector_basic@force-load-detect:
    - bat-adls-6:         NOTRUN -> [SKIP][9]
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-adls-6/igt@kms_force_connector_basic@force-load-detect.html

  * igt@kms_pm_backlight@basic-brightness:
    - bat-adls-6:         NOTRUN -> [SKIP][10] ([i915#5354])
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-adls-6/igt@kms_pm_backlight@basic-brightness.html

  * igt@kms_psr@psr-primary-mmap-gtt:
    - bat-adls-6:         NOTRUN -> [SKIP][11] ([i915#1072] / [i915#9732]) +3 other tests skip
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-adls-6/igt@kms_psr@psr-primary-mmap-gtt.html

  * igt@kms_psr@psr-primary-page-flip:
    - fi-glk-j4005:       NOTRUN -> [SKIP][12] +12 other tests skip
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/fi-glk-j4005/igt@kms_psr@psr-primary-page-flip.html

  * igt@kms_setmode@basic-clone-single-crtc:
    - bat-adls-6:         NOTRUN -> [SKIP][13] ([i915#3555])
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-adls-6/igt@kms_setmode@basic-clone-single-crtc.html

  * igt@prime_vgem@basic-fence-read:
    - bat-adls-6:         NOTRUN -> [SKIP][14] ([i915#3291]) +2 other tests skip
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-adls-6/igt@prime_vgem@basic-fence-read.html

  
#### Possible fixes ####

  * igt@i915_pm_rpm@module-reload:
    - bat-adlp-6:         [DMESG-WARN][15] ([i915#15673]) -> [PASS][16] +78 other tests pass
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/bat-adlp-6/igt@i915_pm_rpm@module-reload.html
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-adlp-6/igt@i915_pm_rpm@module-reload.html

  * igt@i915_selftest@live:
    - bat-dg2-8:          [DMESG-FAIL][17] ([i915#12061]) -> [PASS][18] +1 other test pass
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/bat-dg2-8/igt@i915_selftest@live.html
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-dg2-8/igt@i915_selftest@live.html

  * igt@i915_selftest@live@workarounds:
    - bat-arls-5:         [DMESG-FAIL][19] ([i915#12061]) -> [PASS][20] +1 other test pass
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/bat-arls-5/igt@i915_selftest@live@workarounds.html
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/bat-arls-5/igt@i915_selftest@live@workarounds.html

  
  [i915#1072]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/1072
  [i915#12061]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12061
  [i915#15656]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15656
  [i915#15673]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15673
  [i915#15931]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15931
  [i915#2190]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/2190
  [i915#3291]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3291
  [i915#3555]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3555
  [i915#3840]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3840
  [i915#4103]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/4103
  [i915#4613]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/4613
  [i915#5354]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/5354
  [i915#7707]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/7707
  [i915#9732]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9732


Build changes
-------------

  * Linux: CI_DRM_18377 -> Patchwork_165632v2

  CI-20190529: 20190529
  CI_DRM_18377: a53aafc879e9c52b2776089762591d2766a27f0a @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_8877: 1749e432cd72ef2c99f1b4e9d6f24411f1161901 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  Patchwork_165632v2: a53aafc879e9c52b2776089762591d2766a27f0a @ git://anongit.freedesktop.org/gfx-ci/linux

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/index.html

[-- Attachment #2: Type: text/html, Size: 7865 bytes --]

^ permalink raw reply	[flat|nested] 113+ messages in thread

* ✗ i915.CI.Full: failure for drm/i915/dp_link: Refactor DP link capability logic (rev2)
  2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
                   ` (109 preceding siblings ...)
  2026-04-29  9:17 ` ✓ i915.CI.BAT: success for drm/i915/dp_link: Refactor DP link capability logic (rev2) Patchwork
@ 2026-04-29 15:35 ` Patchwork
  110 siblings, 0 replies; 113+ messages in thread
From: Patchwork @ 2026-04-29 15:35 UTC (permalink / raw)
  To: Imre Deak; +Cc: intel-gfx

[-- Attachment #1: Type: text/plain, Size: 92152 bytes --]

== Series Details ==

Series: drm/i915/dp_link: Refactor DP link capability logic (rev2)
URL   : https://patchwork.freedesktop.org/series/165632/
State : failure

== Summary ==

CI Bug Log - changes from CI_DRM_18377_full -> Patchwork_165632v2_full
====================================================

Summary
-------

  **FAILURE**

  Serious unknown changes coming with Patchwork_165632v2_full absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_165632v2_full, please notify your bug team (I915-ci-infra@lists.freedesktop.org) to allow them
  to document this new failure mode, which will reduce false positives in CI.

  

Participating hosts (10 -> 10)
------------------------------

  No changes in participating hosts

Possible new issues
-------------------

  Here are the unknown changes that may have been introduced in Patchwork_165632v2_full:

### IGT changes ###

#### Possible regressions ####

  * igt@kms_cursor_legacy@flip-vs-cursor-crc-legacy:
    - shard-dg1:          [PASS][1] -> [FAIL][2]
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg1-18/igt@kms_cursor_legacy@flip-vs-cursor-crc-legacy.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-12/igt@kms_cursor_legacy@flip-vs-cursor-crc-legacy.html

  
Known issues
------------

  Here are the changes found in Patchwork_165632v2_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@api_intel_bb@blit-reloc-purge-cache:
    - shard-dg2:          NOTRUN -> [SKIP][3] ([i915#8411])
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@api_intel_bb@blit-reloc-purge-cache.html

  * igt@gem_ccs@block-copy-compressed:
    - shard-tglu-1:       NOTRUN -> [SKIP][4] ([i915#3555] / [i915#9323])
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@gem_ccs@block-copy-compressed.html

  * igt@gem_create@create-ext-set-pat:
    - shard-tglu-1:       NOTRUN -> [SKIP][5] ([i915#8562])
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@gem_create@create-ext-set-pat.html

  * igt@gem_exec_balancer@bonded-dual:
    - shard-dg2:          NOTRUN -> [SKIP][6] ([i915#4771])
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@gem_exec_balancer@bonded-dual.html

  * igt@gem_exec_balancer@parallel-dmabuf-import-out-fence:
    - shard-tglu-1:       NOTRUN -> [SKIP][7] ([i915#4525])
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@gem_exec_balancer@parallel-dmabuf-import-out-fence.html

  * igt@gem_exec_balancer@parallel-keep-in-fence:
    - shard-tglu:         NOTRUN -> [SKIP][8] ([i915#4525])
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@gem_exec_balancer@parallel-keep-in-fence.html

  * igt@gem_exec_capture@capture-recoverable:
    - shard-tglu:         NOTRUN -> [SKIP][9] ([i915#6344])
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@gem_exec_capture@capture-recoverable.html

  * igt@gem_exec_reloc@basic-gtt-wc:
    - shard-rkl:          NOTRUN -> [SKIP][10] ([i915#3281])
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@gem_exec_reloc@basic-gtt-wc.html

  * igt@gem_exec_reloc@basic-wc-cpu-active:
    - shard-dg1:          NOTRUN -> [SKIP][11] ([i915#3281])
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@gem_exec_reloc@basic-wc-cpu-active.html

  * igt@gem_fence_thrash@bo-write-verify-y:
    - shard-dg1:          NOTRUN -> [SKIP][12] ([i915#4860])
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@gem_fence_thrash@bo-write-verify-y.html

  * igt@gem_lmem_swapping@heavy-verify-multi-ccs:
    - shard-tglu-1:       NOTRUN -> [SKIP][13] ([i915#4613]) +1 other test skip
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@gem_lmem_swapping@heavy-verify-multi-ccs.html

  * igt@gem_lmem_swapping@massive-random:
    - shard-glk:          NOTRUN -> [SKIP][14] ([i915#4613]) +2 other tests skip
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk4/igt@gem_lmem_swapping@massive-random.html
    - shard-tglu:         NOTRUN -> [SKIP][15] ([i915#4613]) +1 other test skip
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@gem_lmem_swapping@massive-random.html

  * igt@gem_media_vme:
    - shard-tglu:         NOTRUN -> [SKIP][16] ([i915#284])
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@gem_media_vme.html

  * igt@gem_mmap_gtt@basic-read:
    - shard-mtlp:         NOTRUN -> [SKIP][17] ([i915#4077])
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-4/igt@gem_mmap_gtt@basic-read.html

  * igt@gem_mmap_gtt@coherency:
    - shard-glk11:        NOTRUN -> [SKIP][18] +112 other tests skip
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk11/igt@gem_mmap_gtt@coherency.html

  * igt@gem_partial_pwrite_pread@write-snoop:
    - shard-mtlp:         NOTRUN -> [SKIP][19] ([i915#3282])
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-4/igt@gem_partial_pwrite_pread@write-snoop.html

  * igt@gem_partial_pwrite_pread@writes-after-reads-snoop:
    - shard-rkl:          NOTRUN -> [SKIP][20] ([i915#3282]) +2 other tests skip
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@gem_partial_pwrite_pread@writes-after-reads-snoop.html

  * igt@gem_pread@exhaustion:
    - shard-tglu:         NOTRUN -> [WARN][21] ([i915#2658])
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@gem_pread@exhaustion.html

  * igt@gem_pread@snoop:
    - shard-dg2:          NOTRUN -> [SKIP][22] ([i915#3282])
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@gem_pread@snoop.html

  * igt@gem_pwrite@basic-exhaustion:
    - shard-glk:          NOTRUN -> [WARN][23] ([i915#14702] / [i915#2658])
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk3/igt@gem_pwrite@basic-exhaustion.html

  * igt@gem_pxp@hw-rejects-pxp-context:
    - shard-tglu:         NOTRUN -> [SKIP][24] ([i915#13398])
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@gem_pxp@hw-rejects-pxp-context.html

  * igt@gem_pxp@reject-modify-context-protection-off-1:
    - shard-dg1:          NOTRUN -> [SKIP][25] ([i915#4270])
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@gem_pxp@reject-modify-context-protection-off-1.html

  * igt@gem_softpin@evict-snoop:
    - shard-rkl:          NOTRUN -> [SKIP][26]
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@gem_softpin@evict-snoop.html

  * igt@gem_userptr_blits@coherency-unsync:
    - shard-rkl:          NOTRUN -> [SKIP][27] ([i915#3297])
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@gem_userptr_blits@coherency-unsync.html

  * igt@gem_userptr_blits@unsync-overlap:
    - shard-tglu:         NOTRUN -> [SKIP][28] ([i915#3297])
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@gem_userptr_blits@unsync-overlap.html

  * igt@gem_userptr_blits@unsync-unmap-after-close:
    - shard-tglu-1:       NOTRUN -> [SKIP][29] ([i915#3297])
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@gem_userptr_blits@unsync-unmap-after-close.html

  * igt@gen3_render_tiledx_blits:
    - shard-glk10:        NOTRUN -> [SKIP][30] +63 other tests skip
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk10/igt@gen3_render_tiledx_blits.html

  * igt@gen9_exec_parse@bb-start-far:
    - shard-tglu-1:       NOTRUN -> [SKIP][31] ([i915#2527] / [i915#2856]) +1 other test skip
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@gen9_exec_parse@bb-start-far.html

  * igt@gen9_exec_parse@cmd-crossing-page:
    - shard-tglu:         NOTRUN -> [SKIP][32] ([i915#2527] / [i915#2856])
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@gen9_exec_parse@cmd-crossing-page.html

  * igt@i915_drm_fdinfo@virtual-busy-hang-all:
    - shard-dg2:          NOTRUN -> [SKIP][33] ([i915#14118])
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@i915_drm_fdinfo@virtual-busy-hang-all.html

  * igt@i915_pm_freq_api@freq-reset:
    - shard-tglu-1:       NOTRUN -> [SKIP][34] ([i915#8399])
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@i915_pm_freq_api@freq-reset.html

  * igt@i915_pm_rc6_residency@rc6-idle:
    - shard-tglu-1:       NOTRUN -> [SKIP][35] ([i915#14498])
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@i915_pm_rc6_residency@rc6-idle.html

  * igt@i915_pm_rpm@gem-evict-pwrite:
    - shard-dg1:          NOTRUN -> [SKIP][36] ([i915#4077])
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@i915_pm_rpm@gem-evict-pwrite.html

  * igt@i915_pm_rps@min-max-config-loaded:
    - shard-mtlp:         NOTRUN -> [SKIP][37] ([i915#11681] / [i915#6621])
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-4/igt@i915_pm_rps@min-max-config-loaded.html

  * igt@i915_power@sanity:
    - shard-mtlp:         [PASS][38] -> [SKIP][39] ([i915#7984])
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-mtlp-5/igt@i915_power@sanity.html
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-2/igt@i915_power@sanity.html

  * igt@kms_atomic_transition@plane-all-modeset-transition-fencing-internal-panels:
    - shard-glk:          NOTRUN -> [SKIP][40] ([i915#1769])
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk2/igt@kms_atomic_transition@plane-all-modeset-transition-fencing-internal-panels.html

  * igt@kms_big_fb@4-tiled-16bpp-rotate-90:
    - shard-tglu:         NOTRUN -> [SKIP][41] ([i915#5286]) +2 other tests skip
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_big_fb@4-tiled-16bpp-rotate-90.html

  * igt@kms_big_fb@4-tiled-max-hw-stride-32bpp-rotate-180-hflip:
    - shard-tglu-1:       NOTRUN -> [SKIP][42] ([i915#5286]) +2 other tests skip
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_big_fb@4-tiled-max-hw-stride-32bpp-rotate-180-hflip.html

  * igt@kms_big_fb@linear-max-hw-stride-64bpp-rotate-180-hflip:
    - shard-tglu:         NOTRUN -> [SKIP][43] ([i915#3828])
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_big_fb@linear-max-hw-stride-64bpp-rotate-180-hflip.html

  * igt@kms_big_fb@x-tiled-64bpp-rotate-270:
    - shard-dg2:          NOTRUN -> [SKIP][44] +2 other tests skip
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_big_fb@x-tiled-64bpp-rotate-270.html

  * igt@kms_big_fb@yf-tiled-max-hw-stride-32bpp-rotate-0-hflip-async-flip:
    - shard-tglu:         NOTRUN -> [SKIP][45] +27 other tests skip
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_big_fb@yf-tiled-max-hw-stride-32bpp-rotate-0-hflip-async-flip.html

  * igt@kms_ccs@bad-rotation-90-4-tiled-bmg-ccs:
    - shard-mtlp:         NOTRUN -> [SKIP][46] ([i915#12313])
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-4/igt@kms_ccs@bad-rotation-90-4-tiled-bmg-ccs.html

  * igt@kms_ccs@crc-primary-basic-4-tiled-mtl-mc-ccs@pipe-b-hdmi-a-1:
    - shard-rkl:          NOTRUN -> [SKIP][47] ([i915#6095]) +65 other tests skip
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-8/igt@kms_ccs@crc-primary-basic-4-tiled-mtl-mc-ccs@pipe-b-hdmi-a-1.html

  * igt@kms_ccs@crc-primary-suspend-4-tiled-dg2-rc-ccs@pipe-c-hdmi-a-2:
    - shard-rkl:          NOTRUN -> [SKIP][48] ([i915#14098] / [i915#6095]) +34 other tests skip
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-7/igt@kms_ccs@crc-primary-suspend-4-tiled-dg2-rc-ccs@pipe-c-hdmi-a-2.html

  * igt@kms_ccs@crc-primary-suspend-4-tiled-lnl-ccs:
    - shard-rkl:          NOTRUN -> [SKIP][49] ([i915#12805])
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_ccs@crc-primary-suspend-4-tiled-lnl-ccs.html

  * igt@kms_ccs@crc-sprite-planes-basic-4-tiled-mtl-mc-ccs@pipe-a-hdmi-a-3:
    - shard-dg2:          NOTRUN -> [SKIP][50] ([i915#10307] / [i915#6095]) +79 other tests skip
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-6/igt@kms_ccs@crc-sprite-planes-basic-4-tiled-mtl-mc-ccs@pipe-a-hdmi-a-3.html

  * igt@kms_ccs@crc-sprite-planes-basic-y-tiled-gen12-rc-ccs@pipe-d-hdmi-a-1:
    - shard-dg2:          NOTRUN -> [SKIP][51] ([i915#10307] / [i915#10434] / [i915#6095]) +1 other test skip
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-4/igt@kms_ccs@crc-sprite-planes-basic-y-tiled-gen12-rc-ccs@pipe-d-hdmi-a-1.html

  * igt@kms_ccs@missing-ccs-buffer-yf-tiled-ccs@pipe-b-hdmi-a-1:
    - shard-dg1:          NOTRUN -> [SKIP][52] ([i915#6095]) +173 other tests skip
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@kms_ccs@missing-ccs-buffer-yf-tiled-ccs@pipe-b-hdmi-a-1.html

  * igt@kms_ccs@random-ccs-data-4-tiled-dg2-rc-ccs@pipe-c-hdmi-a-1:
    - shard-dg2:          NOTRUN -> [SKIP][53] ([i915#6095]) +23 other tests skip
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-4/igt@kms_ccs@random-ccs-data-4-tiled-dg2-rc-ccs@pipe-c-hdmi-a-1.html

  * igt@kms_ccs@random-ccs-data-4-tiled-mtl-rc-ccs-cc:
    - shard-tglu:         NOTRUN -> [SKIP][54] ([i915#6095]) +39 other tests skip
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_ccs@random-ccs-data-4-tiled-mtl-rc-ccs-cc.html

  * igt@kms_ccs@random-ccs-data-y-tiled-gen12-mc-ccs@pipe-b-hdmi-a-1:
    - shard-tglu-1:       NOTRUN -> [SKIP][55] ([i915#6095]) +24 other tests skip
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_ccs@random-ccs-data-y-tiled-gen12-mc-ccs@pipe-b-hdmi-a-1.html

  * igt@kms_chamelium_color@ctm-limited-range:
    - shard-mtlp:         NOTRUN -> [SKIP][56] +3 other tests skip
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-4/igt@kms_chamelium_color@ctm-limited-range.html

  * igt@kms_chamelium_frames@dp-crc-fast:
    - shard-tglu-1:       NOTRUN -> [SKIP][57] ([i915#11151] / [i915#7828]) +3 other tests skip
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_chamelium_frames@dp-crc-fast.html

  * igt@kms_chamelium_frames@hdmi-cmp-planar-formats:
    - shard-tglu:         NOTRUN -> [SKIP][58] ([i915#11151] / [i915#7828]) +4 other tests skip
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_chamelium_frames@hdmi-cmp-planar-formats.html

  * igt@kms_chamelium_hpd@common-hpd-after-suspend:
    - shard-rkl:          NOTRUN -> [SKIP][59] ([i915#11151] / [i915#7828]) +1 other test skip
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_chamelium_hpd@common-hpd-after-suspend.html

  * igt@kms_chamelium_hpd@dp-hpd-for-each-pipe:
    - shard-dg2:          NOTRUN -> [SKIP][60] ([i915#11151] / [i915#7828])
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_chamelium_hpd@dp-hpd-for-each-pipe.html

  * igt@kms_chamelium_hpd@hdmi-hpd-enable-disable-mode:
    - shard-dg1:          NOTRUN -> [SKIP][61] ([i915#11151] / [i915#7828])
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@kms_chamelium_hpd@hdmi-hpd-enable-disable-mode.html

  * igt@kms_content_protection@dp-mst-lic-type-1:
    - shard-tglu:         NOTRUN -> [SKIP][62] ([i915#15330] / [i915#3116] / [i915#3299])
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@kms_content_protection@dp-mst-lic-type-1.html

  * igt@kms_content_protection@dp-mst-type-1:
    - shard-dg2:          NOTRUN -> [SKIP][63] ([i915#15330] / [i915#3299])
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_content_protection@dp-mst-type-1.html

  * igt@kms_content_protection@legacy:
    - shard-tglu:         NOTRUN -> [SKIP][64] ([i915#15865])
   [64]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_content_protection@legacy.html

  * igt@kms_content_protection@lic-type-0-hdcp14:
    - shard-dg1:          NOTRUN -> [SKIP][65] ([i915#15865])
   [65]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@kms_content_protection@lic-type-0-hdcp14.html

  * igt@kms_content_protection@suspend-resume:
    - shard-rkl:          NOTRUN -> [SKIP][66] ([i915#15865])
   [66]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_content_protection@suspend-resume.html

  * igt@kms_content_protection@uevent:
    - shard-tglu-1:       NOTRUN -> [SKIP][67] ([i915#15865])
   [67]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_content_protection@uevent.html

  * igt@kms_cursor_crc@cursor-offscreen-512x512:
    - shard-dg2:          NOTRUN -> [SKIP][68] ([i915#13049])
   [68]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_cursor_crc@cursor-offscreen-512x512.html

  * igt@kms_cursor_crc@cursor-onscreen-128x42:
    - shard-tglu:         NOTRUN -> [FAIL][69] ([i915#13566]) +1 other test fail
   [69]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_cursor_crc@cursor-onscreen-128x42.html

  * igt@kms_cursor_crc@cursor-random-128x42:
    - shard-rkl:          NOTRUN -> [FAIL][70] ([i915#13566]) +4 other tests fail
   [70]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_cursor_crc@cursor-random-128x42.html

  * igt@kms_cursor_crc@cursor-sliding-128x42:
    - shard-rkl:          [PASS][71] -> [FAIL][72] ([i915#13566])
   [71]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-2/igt@kms_cursor_crc@cursor-sliding-128x42.html
   [72]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_cursor_crc@cursor-sliding-128x42.html

  * igt@kms_cursor_crc@cursor-sliding-32x10:
    - shard-tglu-1:       NOTRUN -> [SKIP][73] ([i915#3555]) +3 other tests skip
   [73]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_cursor_crc@cursor-sliding-32x10.html

  * igt@kms_cursor_crc@cursor-sliding-512x170:
    - shard-tglu:         NOTRUN -> [SKIP][74] ([i915#13049]) +1 other test skip
   [74]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_cursor_crc@cursor-sliding-512x170.html

  * igt@kms_cursor_crc@cursor-sliding-512x512:
    - shard-tglu-1:       NOTRUN -> [SKIP][75] ([i915#13049]) +1 other test skip
   [75]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_cursor_crc@cursor-sliding-512x512.html

  * igt@kms_cursor_crc@cursor-suspend:
    - shard-glk11:        NOTRUN -> [INCOMPLETE][76] ([i915#12358] / [i915#14152] / [i915#7882])
   [76]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk11/igt@kms_cursor_crc@cursor-suspend.html

  * igt@kms_cursor_crc@cursor-suspend@pipe-a-hdmi-a-1:
    - shard-glk11:        NOTRUN -> [INCOMPLETE][77] ([i915#12358] / [i915#14152])
   [77]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk11/igt@kms_cursor_crc@cursor-suspend@pipe-a-hdmi-a-1.html

  * igt@kms_cursor_legacy@cursorb-vs-flipa-legacy:
    - shard-tglu-1:       NOTRUN -> [SKIP][78] +27 other tests skip
   [78]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_cursor_legacy@cursorb-vs-flipa-legacy.html

  * igt@kms_cursor_legacy@cursorb-vs-flipa-varying-size:
    - shard-dg2:          NOTRUN -> [SKIP][79] ([i915#13046] / [i915#5354])
   [79]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_cursor_legacy@cursorb-vs-flipa-varying-size.html

  * igt@kms_cursor_legacy@cursorb-vs-flipb-atomic-transitions:
    - shard-mtlp:         NOTRUN -> [SKIP][80] ([i915#9809])
   [80]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-4/igt@kms_cursor_legacy@cursorb-vs-flipb-atomic-transitions.html

  * igt@kms_display_modes@extended-mode-basic:
    - shard-tglu:         NOTRUN -> [SKIP][81] ([i915#13691])
   [81]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@kms_display_modes@extended-mode-basic.html

  * igt@kms_dither@fb-8bpc-vs-panel-6bpc:
    - shard-dg2:          NOTRUN -> [SKIP][82] ([i915#3555])
   [82]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_dither@fb-8bpc-vs-panel-6bpc.html

  * igt@kms_dp_link_training@non-uhbr-mst:
    - shard-mtlp:         NOTRUN -> [SKIP][83] ([i915#13749])
   [83]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-4/igt@kms_dp_link_training@non-uhbr-mst.html

  * igt@kms_dp_link_training@uhbr-sst:
    - shard-tglu-1:       NOTRUN -> [SKIP][84] ([i915#13748])
   [84]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_dp_link_training@uhbr-sst.html

  * igt@kms_dsc@dsc-with-formats:
    - shard-mtlp:         NOTRUN -> [SKIP][85] ([i915#3555] / [i915#3840])
   [85]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-4/igt@kms_dsc@dsc-with-formats.html

  * igt@kms_feature_discovery@chamelium:
    - shard-rkl:          NOTRUN -> [SKIP][86] ([i915#4854])
   [86]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_feature_discovery@chamelium.html

  * igt@kms_feature_discovery@display-4x:
    - shard-tglu:         NOTRUN -> [SKIP][87] ([i915#1839])
   [87]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@kms_feature_discovery@display-4x.html

  * igt@kms_feature_discovery@psr2:
    - shard-tglu-1:       NOTRUN -> [SKIP][88] ([i915#658])
   [88]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_feature_discovery@psr2.html

  * igt@kms_flip@2x-modeset-vs-vblank-race:
    - shard-tglu:         NOTRUN -> [SKIP][89] ([i915#3637] / [i915#9934]) +3 other tests skip
   [89]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_flip@2x-modeset-vs-vblank-race.html

  * igt@kms_flip@2x-single-buffer-flip-vs-dpms-off-vs-modeset:
    - shard-tglu-1:       NOTRUN -> [SKIP][90] ([i915#3637] / [i915#9934]) +2 other tests skip
   [90]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_flip@2x-single-buffer-flip-vs-dpms-off-vs-modeset.html

  * igt@kms_flip@2x-single-buffer-flip-vs-dpms-off-vs-modeset-interruptible:
    - shard-dg2:          NOTRUN -> [SKIP][91] ([i915#9934])
   [91]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_flip@2x-single-buffer-flip-vs-dpms-off-vs-modeset-interruptible.html

  * igt@kms_flip@flip-vs-expired-vblank@a-hdmi-a3:
    - shard-dg2:          [PASS][92] -> [FAIL][93] ([i915#13027]) +1 other test fail
   [92]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg2-8/igt@kms_flip@flip-vs-expired-vblank@a-hdmi-a3.html
   [93]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-7/igt@kms_flip@flip-vs-expired-vblank@a-hdmi-a3.html

  * igt@kms_flip@flip-vs-fences-interruptible:
    - shard-dg2:          NOTRUN -> [SKIP][94] ([i915#8381])
   [94]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_flip@flip-vs-fences-interruptible.html

  * igt@kms_flip@flip-vs-suspend:
    - shard-glk10:        NOTRUN -> [INCOMPLETE][95] ([i915#12745] / [i915#4839])
   [95]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk10/igt@kms_flip@flip-vs-suspend.html

  * igt@kms_flip@flip-vs-suspend@a-hdmi-a1:
    - shard-glk10:        NOTRUN -> [INCOMPLETE][96] ([i915#12745])
   [96]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk10/igt@kms_flip@flip-vs-suspend@a-hdmi-a1.html

  * igt@kms_flip_scaled_crc@flip-32bpp-yftile-to-32bpp-yftileccs-upscaling:
    - shard-tglu:         NOTRUN -> [SKIP][97] ([i915#15643]) +2 other tests skip
   [97]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@kms_flip_scaled_crc@flip-32bpp-yftile-to-32bpp-yftileccs-upscaling.html

  * igt@kms_flip_scaled_crc@flip-32bpp-yftileccs-to-64bpp-yftile-upscaling:
    - shard-rkl:          NOTRUN -> [SKIP][98] ([i915#15643])
   [98]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_flip_scaled_crc@flip-32bpp-yftileccs-to-64bpp-yftile-upscaling.html

  * igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling:
    - shard-dg2:          NOTRUN -> [SKIP][99] ([i915#15643] / [i915#5190])
   [99]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-32bpp-ytilegen12rcccs-upscaling.html

  * igt@kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-upscaling:
    - shard-tglu-1:       NOTRUN -> [SKIP][100] ([i915#15643])
   [100]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_flip_scaled_crc@flip-32bpp-ytileccs-to-64bpp-ytile-upscaling.html

  * igt@kms_frontbuffer_tracking@fbc-1p-offscreen-pri-indfb-draw-mmap-wc:
    - shard-dg2:          NOTRUN -> [SKIP][101] ([i915#15104])
   [101]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_frontbuffer_tracking@fbc-1p-offscreen-pri-indfb-draw-mmap-wc.html

  * igt@kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-shrfb-draw-mmap-wc:
    - shard-dg1:          NOTRUN -> [SKIP][102] ([i915#8708]) +1 other test skip
   [102]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-shrfb-draw-mmap-wc.html

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-pri-indfb-multidraw:
    - shard-dg1:          NOTRUN -> [SKIP][103] ([i915#15102] / [i915#3458])
   [103]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@kms_frontbuffer_tracking@fbcpsr-1p-pri-indfb-multidraw.html

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-shrfb-draw-pwrite:
    - shard-dg2:          NOTRUN -> [SKIP][104] ([i915#15102] / [i915#3458]) +1 other test skip
   [104]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-pri-shrfb-draw-pwrite.html

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-shrfb-fliptrack-mmap-gtt:
    - shard-dg2:          NOTRUN -> [SKIP][105] ([i915#8708]) +1 other test skip
   [105]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_frontbuffer_tracking@fbcpsr-1p-shrfb-fliptrack-mmap-gtt.html

  * igt@kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-spr-indfb-draw-mmap-wc:
    - shard-glk:          NOTRUN -> [SKIP][106] +309 other tests skip
   [106]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk5/igt@kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-spr-indfb-draw-mmap-wc.html

  * igt@kms_frontbuffer_tracking@fbcpsr-farfromfence-mmap-gtt:
    - shard-mtlp:         NOTRUN -> [SKIP][107] ([i915#8708])
   [107]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-4/igt@kms_frontbuffer_tracking@fbcpsr-farfromfence-mmap-gtt.html

  * igt@kms_frontbuffer_tracking@fbcpsr-modesetfrombusy:
    - shard-tglu:         NOTRUN -> [SKIP][108] ([i915#15102]) +10 other tests skip
   [108]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@kms_frontbuffer_tracking@fbcpsr-modesetfrombusy.html

  * igt@kms_frontbuffer_tracking@fbcpsr-rgb565-draw-mmap-gtt:
    - shard-tglu-1:       NOTRUN -> [SKIP][109] ([i915#15102]) +11 other tests skip
   [109]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_frontbuffer_tracking@fbcpsr-rgb565-draw-mmap-gtt.html

  * igt@kms_frontbuffer_tracking@pipe-fbc-rte:
    - shard-dg1:          NOTRUN -> [SKIP][110] ([i915#9766])
   [110]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@kms_frontbuffer_tracking@pipe-fbc-rte.html

  * igt@kms_frontbuffer_tracking@psr-1p-offscreen-pri-shrfb-draw-mmap-wc:
    - shard-rkl:          NOTRUN -> [SKIP][111] ([i915#15102]) +1 other test skip
   [111]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_frontbuffer_tracking@psr-1p-offscreen-pri-shrfb-draw-mmap-wc.html

  * igt@kms_frontbuffer_tracking@psr-1p-primscrn-shrfb-pgflip-blt:
    - shard-rkl:          NOTRUN -> [SKIP][112] ([i915#15102] / [i915#3023]) +3 other tests skip
   [112]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_frontbuffer_tracking@psr-1p-primscrn-shrfb-pgflip-blt.html

  * igt@kms_frontbuffer_tracking@psr-2p-scndscrn-indfb-pgflip-blt:
    - shard-dg2:          NOTRUN -> [SKIP][113] ([i915#5354]) +4 other tests skip
   [113]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_frontbuffer_tracking@psr-2p-scndscrn-indfb-pgflip-blt.html

  * igt@kms_frontbuffer_tracking@psr-2p-scndscrn-indfb-plflip-blt:
    - shard-dg1:          NOTRUN -> [SKIP][114] +1 other test skip
   [114]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@kms_frontbuffer_tracking@psr-2p-scndscrn-indfb-plflip-blt.html

  * igt@kms_frontbuffer_tracking@psr-2p-scndscrn-pri-shrfb-draw-mmap-cpu:
    - shard-mtlp:         NOTRUN -> [SKIP][115] ([i915#1825]) +4 other tests skip
   [115]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-4/igt@kms_frontbuffer_tracking@psr-2p-scndscrn-pri-shrfb-draw-mmap-cpu.html

  * igt@kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-draw-mmap-cpu:
    - shard-rkl:          NOTRUN -> [SKIP][116] ([i915#1825]) +3 other tests skip
   [116]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_frontbuffer_tracking@psr-2p-scndscrn-spr-indfb-draw-mmap-cpu.html

  * igt@kms_hdr@bpc-switch:
    - shard-tglu:         NOTRUN -> [SKIP][117] ([i915#3555] / [i915#8228])
   [117]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_hdr@bpc-switch.html

  * igt@kms_hdr@brightness-with-hdr:
    - shard-tglu-1:       NOTRUN -> [SKIP][118] ([i915#12713])
   [118]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_hdr@brightness-with-hdr.html

  * igt@kms_hdr@static-toggle:
    - shard-tglu-1:       NOTRUN -> [SKIP][119] ([i915#3555] / [i915#8228])
   [119]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_hdr@static-toggle.html

  * igt@kms_joiner@basic-big-joiner:
    - shard-tglu:         NOTRUN -> [SKIP][120] ([i915#15460])
   [120]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_joiner@basic-big-joiner.html

  * igt@kms_joiner@basic-force-ultra-joiner:
    - shard-rkl:          NOTRUN -> [SKIP][121] ([i915#15458])
   [121]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_joiner@basic-force-ultra-joiner.html

  * igt@kms_plane@pixel-format-4-tiled-dg2-rc-ccs-cc-modifier:
    - shard-tglu:         NOTRUN -> [SKIP][122] ([i915#15709]) +2 other tests skip
   [122]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_plane@pixel-format-4-tiled-dg2-rc-ccs-cc-modifier.html

  * igt@kms_plane@pixel-format-4-tiled-dg2-rc-ccs-cc-modifier-source-clamping:
    - shard-tglu-1:       NOTRUN -> [SKIP][123] ([i915#15709]) +2 other tests skip
   [123]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_plane@pixel-format-4-tiled-dg2-rc-ccs-cc-modifier-source-clamping.html

  * igt@kms_plane@pixel-format-4-tiled-mtl-rc-ccs-modifier:
    - shard-rkl:          NOTRUN -> [SKIP][124] ([i915#15709])
   [124]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_plane@pixel-format-4-tiled-mtl-rc-ccs-modifier.html

  * igt@kms_plane_alpha_blend@alpha-opaque-fb:
    - shard-glk10:        NOTRUN -> [FAIL][125] ([i915#10647] / [i915#12169])
   [125]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk10/igt@kms_plane_alpha_blend@alpha-opaque-fb.html

  * igt@kms_plane_alpha_blend@alpha-opaque-fb@pipe-c-hdmi-a-1:
    - shard-glk10:        NOTRUN -> [FAIL][126] ([i915#10647]) +1 other test fail
   [126]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk10/igt@kms_plane_alpha_blend@alpha-opaque-fb@pipe-c-hdmi-a-1.html

  * igt@kms_plane_alpha_blend@alpha-transparent-fb:
    - shard-glk:          NOTRUN -> [FAIL][127] ([i915#10647] / [i915#12177])
   [127]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk2/igt@kms_plane_alpha_blend@alpha-transparent-fb.html

  * igt@kms_plane_alpha_blend@alpha-transparent-fb@pipe-a-hdmi-a-1:
    - shard-glk:          NOTRUN -> [FAIL][128] ([i915#10647]) +1 other test fail
   [128]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk2/igt@kms_plane_alpha_blend@alpha-transparent-fb@pipe-a-hdmi-a-1.html

  * igt@kms_plane_alpha_blend@constant-alpha-max:
    - shard-glk11:        NOTRUN -> [FAIL][129] ([i915#10647] / [i915#12169])
   [129]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk11/igt@kms_plane_alpha_blend@constant-alpha-max.html

  * igt@kms_plane_alpha_blend@constant-alpha-max@pipe-a-hdmi-a-1:
    - shard-glk11:        NOTRUN -> [FAIL][130] ([i915#10647]) +1 other test fail
   [130]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk11/igt@kms_plane_alpha_blend@constant-alpha-max@pipe-a-hdmi-a-1.html

  * igt@kms_pm_backlight@fade:
    - shard-tglu:         NOTRUN -> [SKIP][131] ([i915#9812])
   [131]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@kms_pm_backlight@fade.html

  * igt@kms_pm_dc@dc5-psr:
    - shard-rkl:          NOTRUN -> [SKIP][132] ([i915#15948])
   [132]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_pm_dc@dc5-psr.html

  * igt@kms_pm_dc@dc5-retention-flops:
    - shard-tglu-1:       NOTRUN -> [SKIP][133] ([i915#3828]) +1 other test skip
   [133]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_pm_dc@dc5-retention-flops.html

  * igt@kms_pm_lpsp@screens-disabled:
    - shard-dg2:          NOTRUN -> [SKIP][134] ([i915#8430])
   [134]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_pm_lpsp@screens-disabled.html

  * igt@kms_pm_rpm@dpms-lpsp:
    - shard-dg1:          [PASS][135] -> [SKIP][136] ([i915#15073])
   [135]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg1-15/igt@kms_pm_rpm@dpms-lpsp.html
   [136]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-18/igt@kms_pm_rpm@dpms-lpsp.html

  * igt@kms_pm_rpm@i2c:
    - shard-dg1:          [PASS][137] -> [DMESG-WARN][138] ([i915#4423]) +1 other test dmesg-warn
   [137]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg1-18/igt@kms_pm_rpm@i2c.html
   [138]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-16/igt@kms_pm_rpm@i2c.html

  * igt@kms_pm_rpm@modeset-lpsp-stress-no-wait:
    - shard-dg2:          [PASS][139] -> [SKIP][140] ([i915#15073])
   [139]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg2-4/igt@kms_pm_rpm@modeset-lpsp-stress-no-wait.html
   [140]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-7/igt@kms_pm_rpm@modeset-lpsp-stress-no-wait.html

  * igt@kms_pm_rpm@modeset-non-lpsp-stress-no-wait:
    - shard-rkl:          [PASS][141] -> [SKIP][142] ([i915#15073]) +1 other test skip
   [141]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-3/igt@kms_pm_rpm@modeset-non-lpsp-stress-no-wait.html
   [142]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-5/igt@kms_pm_rpm@modeset-non-lpsp-stress-no-wait.html

  * igt@kms_pm_rpm@package-g7:
    - shard-tglu-1:       NOTRUN -> [SKIP][143] ([i915#15403])
   [143]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_pm_rpm@package-g7.html

  * igt@kms_prime@d3hot:
    - shard-tglu:         NOTRUN -> [SKIP][144] ([i915#6524])
   [144]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_prime@d3hot.html

  * igt@kms_psr2_sf@fbc-pr-cursor-plane-update-sf:
    - shard-tglu:         NOTRUN -> [SKIP][145] ([i915#11520]) +5 other tests skip
   [145]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@kms_psr2_sf@fbc-pr-cursor-plane-update-sf.html

  * igt@kms_psr2_sf@fbc-pr-overlay-primary-update-sf-dmg-area:
    - shard-tglu-1:       NOTRUN -> [SKIP][146] ([i915#11520]) +3 other tests skip
   [146]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_psr2_sf@fbc-pr-overlay-primary-update-sf-dmg-area.html

  * igt@kms_psr2_sf@fbc-psr2-overlay-plane-move-continuous-exceed-sf:
    - shard-dg1:          NOTRUN -> [SKIP][147] ([i915#11520])
   [147]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@kms_psr2_sf@fbc-psr2-overlay-plane-move-continuous-exceed-sf.html

  * igt@kms_psr2_sf@fbc-psr2-overlay-plane-update-sf-dmg-area:
    - shard-glk11:        NOTRUN -> [SKIP][148] ([i915#11520]) +2 other tests skip
   [148]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk11/igt@kms_psr2_sf@fbc-psr2-overlay-plane-update-sf-dmg-area.html

  * igt@kms_psr2_sf@pr-cursor-plane-move-continuous-sf:
    - shard-glk:          NOTRUN -> [SKIP][149] ([i915#11520]) +9 other tests skip
   [149]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk6/igt@kms_psr2_sf@pr-cursor-plane-move-continuous-sf.html

  * igt@kms_psr2_sf@pr-primary-plane-update-sf-dmg-area-big-fb:
    - shard-glk10:        NOTRUN -> [SKIP][150] ([i915#11520]) +1 other test skip
   [150]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk10/igt@kms_psr2_sf@pr-primary-plane-update-sf-dmg-area-big-fb.html

  * igt@kms_psr2_sf@psr2-overlay-plane-update-sf-dmg-area:
    - shard-dg2:          NOTRUN -> [SKIP][151] ([i915#11520]) +1 other test skip
   [151]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_psr2_sf@psr2-overlay-plane-update-sf-dmg-area.html

  * igt@kms_psr2_su@page_flip-nv12:
    - shard-tglu-1:       NOTRUN -> [SKIP][152] ([i915#9683])
   [152]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_psr2_su@page_flip-nv12.html

  * igt@kms_psr@fbc-pr-cursor-plane-move:
    - shard-dg1:          NOTRUN -> [SKIP][153] ([i915#1072] / [i915#9732]) +1 other test skip
   [153]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@kms_psr@fbc-pr-cursor-plane-move.html

  * igt@kms_psr@pr-cursor-plane-onoff:
    - shard-tglu-1:       NOTRUN -> [SKIP][154] ([i915#9732]) +8 other tests skip
   [154]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_psr@pr-cursor-plane-onoff.html

  * igt@kms_psr@pr-primary-mmap-cpu:
    - shard-mtlp:         NOTRUN -> [SKIP][155] ([i915#9688]) +2 other tests skip
   [155]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-4/igt@kms_psr@pr-primary-mmap-cpu.html

  * igt@kms_psr@pr-primary-page-flip:
    - shard-tglu:         NOTRUN -> [SKIP][156] ([i915#9732]) +7 other tests skip
   [156]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@kms_psr@pr-primary-page-flip.html

  * igt@kms_psr@pr-sprite-blt:
    - shard-rkl:          NOTRUN -> [SKIP][157] ([i915#1072] / [i915#9732]) +2 other tests skip
   [157]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_psr@pr-sprite-blt.html

  * igt@kms_psr@psr-sprite-render:
    - shard-dg2:          NOTRUN -> [SKIP][158] ([i915#1072] / [i915#9732]) +2 other tests skip
   [158]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_psr@psr-sprite-render.html

  * igt@kms_psr_stress_test@flip-primary-invalidate-overlay:
    - shard-tglu:         NOTRUN -> [SKIP][159] ([i915#15949])
   [159]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@kms_psr_stress_test@flip-primary-invalidate-overlay.html

  * igt@kms_rotation_crc@multiplane-rotation:
    - shard-glk:          NOTRUN -> [INCOMPLETE][160] ([i915#15492])
   [160]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk2/igt@kms_rotation_crc@multiplane-rotation.html

  * igt@kms_rotation_crc@primary-4-tiled-reflect-x-0:
    - shard-tglu-1:       NOTRUN -> [SKIP][161] ([i915#5289])
   [161]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_rotation_crc@primary-4-tiled-reflect-x-0.html

  * igt@kms_rotation_crc@primary-yf-tiled-reflect-x-180:
    - shard-dg2:          NOTRUN -> [SKIP][162] ([i915#5190])
   [162]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_rotation_crc@primary-yf-tiled-reflect-x-180.html

  * igt@kms_scaling_modes@scaling-mode-center:
    - shard-tglu:         NOTRUN -> [SKIP][163] ([i915#3555])
   [163]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_scaling_modes@scaling-mode-center.html

  * igt@kms_scaling_modes@scaling-mode-full-aspect:
    - shard-rkl:          NOTRUN -> [SKIP][164] ([i915#3555])
   [164]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_scaling_modes@scaling-mode-full-aspect.html

  * igt@kms_tiled_display@basic-test-pattern-with-chamelium:
    - shard-tglu-1:       NOTRUN -> [SKIP][165] ([i915#8623])
   [165]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-1/igt@kms_tiled_display@basic-test-pattern-with-chamelium.html

  * igt@kms_vblank@ts-continuation-suspend:
    - shard-glk:          NOTRUN -> [INCOMPLETE][166] ([i915#12276]) +1 other test incomplete
   [166]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk3/igt@kms_vblank@ts-continuation-suspend.html

  * igt@kms_vrr@flip-basic-fastset:
    - shard-tglu:         NOTRUN -> [SKIP][167] ([i915#9906])
   [167]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@kms_vrr@flip-basic-fastset.html

  * igt@kms_vrr@flipline:
    - shard-mtlp:         NOTRUN -> [SKIP][168] ([i915#3555] / [i915#8808])
   [168]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-4/igt@kms_vrr@flipline.html

  * igt@kms_vrr@lobf:
    - shard-tglu:         NOTRUN -> [SKIP][169] ([i915#11920])
   [169]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-5/igt@kms_vrr@lobf.html

  * igt@perf_pmu@rc6-all-gts:
    - shard-tglu:         NOTRUN -> [SKIP][170] ([i915#8516])
   [170]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-10/igt@perf_pmu@rc6-all-gts.html

  * igt@perf_pmu@rc6-suspend:
    - shard-rkl:          [PASS][171] -> [INCOMPLETE][172] ([i915#13520])
   [171]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-8/igt@perf_pmu@rc6-suspend.html
   [172]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@perf_pmu@rc6-suspend.html

  * igt@prime_vgem@basic-fence-mmap:
    - shard-dg2:          NOTRUN -> [SKIP][173] ([i915#3708] / [i915#4077])
   [173]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@prime_vgem@basic-fence-mmap.html

  * igt@prime_vgem@coherency-gtt:
    - shard-rkl:          NOTRUN -> [SKIP][174] ([i915#3708])
   [174]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@prime_vgem@coherency-gtt.html

  * igt@sriov_basic@enable-vfs-autoprobe-off:
    - shard-dg2:          NOTRUN -> [SKIP][175] ([i915#9917])
   [175]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@sriov_basic@enable-vfs-autoprobe-off.html

  
#### Possible fixes ####

  * igt@gem_ccs@suspend-resume:
    - shard-dg2:          [INCOMPLETE][176] ([i915#13356]) -> [PASS][177]
   [176]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg2-5/igt@gem_ccs@suspend-resume.html
   [177]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@gem_ccs@suspend-resume.html

  * igt@gem_ccs@suspend-resume@xmajor-compressed-compfmt0-smem-lmem0:
    - shard-dg2:          [INCOMPLETE][178] ([i915#12392] / [i915#13356]) -> [PASS][179]
   [178]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg2-5/igt@gem_ccs@suspend-resume@xmajor-compressed-compfmt0-smem-lmem0.html
   [179]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@gem_ccs@suspend-resume@xmajor-compressed-compfmt0-smem-lmem0.html

  * igt@gem_ctx_persistence@legacy-engines-mixed-process:
    - shard-mtlp:         [ABORT][180] -> [PASS][181] +1 other test pass
   [180]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-mtlp-2/igt@gem_ctx_persistence@legacy-engines-mixed-process.html
   [181]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-4/igt@gem_ctx_persistence@legacy-engines-mixed-process.html

  * igt@i915_pm_rc6_residency@rc6-fence:
    - shard-tglu:         [WARN][182] ([i915#13790] / [i915#2681]) -> [PASS][183] +1 other test pass
   [182]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-tglu-5/igt@i915_pm_rc6_residency@rc6-fence.html
   [183]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-6/igt@i915_pm_rc6_residency@rc6-fence.html

  * igt@i915_selftest@live:
    - shard-dg1:          [ABORT][184] -> [PASS][185]
   [184]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg1-13/igt@i915_selftest@live.html
   [185]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@i915_selftest@live.html
    - shard-mtlp:         [DMESG-FAIL][186] ([i915#12061] / [i915#15560]) -> [PASS][187]
   [186]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-mtlp-4/igt@i915_selftest@live.html
   [187]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-3/igt@i915_selftest@live.html

  * igt@i915_selftest@live@gem_contexts:
    - shard-dg1:          [ABORT][188] ([i915#15433]) -> [PASS][189]
   [188]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg1-13/igt@i915_selftest@live@gem_contexts.html
   [189]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@i915_selftest@live@gem_contexts.html

  * igt@i915_selftest@live@workarounds:
    - shard-mtlp:         [DMESG-FAIL][190] ([i915#12061]) -> [PASS][191]
   [190]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-mtlp-4/igt@i915_selftest@live@workarounds.html
   [191]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-3/igt@i915_selftest@live@workarounds.html

  * igt@kms_atomic_transition@plane-all-modeset-transition-fencing:
    - shard-tglu:         [FAIL][192] ([i915#15662]) -> [PASS][193] +1 other test pass
   [192]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-tglu-9/igt@kms_atomic_transition@plane-all-modeset-transition-fencing.html
   [193]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-tglu-3/igt@kms_atomic_transition@plane-all-modeset-transition-fencing.html

  * igt@kms_atomic_transition@plane-toggle-modeset-transition@pipe-a-edp-1:
    - shard-mtlp:         [FAIL][194] ([i915#5956]) -> [PASS][195] +1 other test pass
   [194]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-mtlp-7/igt@kms_atomic_transition@plane-toggle-modeset-transition@pipe-a-edp-1.html
   [195]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-8/igt@kms_atomic_transition@plane-toggle-modeset-transition@pipe-a-edp-1.html

  * igt@kms_cursor_crc@cursor-sliding-256x85:
    - shard-rkl:          [FAIL][196] ([i915#13566]) -> [PASS][197]
   [196]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_cursor_crc@cursor-sliding-256x85.html
   [197]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-8/igt@kms_cursor_crc@cursor-sliding-256x85.html

  * igt@kms_flip@flip-vs-absolute-wf_vblank-interruptible:
    - shard-dg2:          [FAIL][198] ([i915#14600]) -> [PASS][199] +1 other test pass
   [198]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg2-7/igt@kms_flip@flip-vs-absolute-wf_vblank-interruptible.html
   [199]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-8/igt@kms_flip@flip-vs-absolute-wf_vblank-interruptible.html

  * igt@kms_frontbuffer_tracking@fbc-1p-primscrn-shrfb-pgflip-blt:
    - shard-dg2:          [FAIL][200] ([i915#15389] / [i915#6880]) -> [PASS][201]
   [200]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg2-6/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-shrfb-pgflip-blt.html
   [201]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-6/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-shrfb-pgflip-blt.html

  * igt@kms_plane_cursor@viewport:
    - shard-mtlp:         [DMESG-WARN][202] -> [PASS][203] +1 other test pass
   [202]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-mtlp-4/igt@kms_plane_cursor@viewport.html
   [203]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-mtlp-3/igt@kms_plane_cursor@viewport.html

  * igt@kms_pm_rpm@modeset-lpsp-stress-no-wait:
    - shard-rkl:          [SKIP][204] ([i915#15073]) -> [PASS][205] +1 other test pass
   [204]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-7/igt@kms_pm_rpm@modeset-lpsp-stress-no-wait.html
   [205]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-2/igt@kms_pm_rpm@modeset-lpsp-stress-no-wait.html

  * igt@kms_pm_rpm@modeset-non-lpsp:
    - shard-dg1:          [SKIP][206] ([i915#15073]) -> [PASS][207]
   [206]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg1-14/igt@kms_pm_rpm@modeset-non-lpsp.html
   [207]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-19/igt@kms_pm_rpm@modeset-non-lpsp.html

  * igt@kms_vblank@ts-continuation-suspend@pipe-a-hdmi-a-2:
    - shard-rkl:          [INCOMPLETE][208] ([i915#12276]) -> [PASS][209] +1 other test pass
   [208]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_vblank@ts-continuation-suspend@pipe-a-hdmi-a-2.html
   [209]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_vblank@ts-continuation-suspend@pipe-a-hdmi-a-2.html

  
#### Warnings ####

  * igt@gem_bad_reloc@negative-reloc-lut:
    - shard-rkl:          [SKIP][210] ([i915#3281]) -> [SKIP][211] ([i915#14544] / [i915#3281]) +6 other tests skip
   [210]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-1/igt@gem_bad_reloc@negative-reloc-lut.html
   [211]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@gem_bad_reloc@negative-reloc-lut.html

  * igt@gem_ccs@block-multicopy-compressed:
    - shard-rkl:          [SKIP][212] ([i915#14544] / [i915#9323]) -> [SKIP][213] ([i915#9323])
   [212]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@gem_ccs@block-multicopy-compressed.html
   [213]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@gem_ccs@block-multicopy-compressed.html

  * igt@gem_close_race@multigpu-basic-process:
    - shard-rkl:          [SKIP][214] ([i915#14544] / [i915#7697]) -> [SKIP][215] ([i915#7697])
   [214]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@gem_close_race@multigpu-basic-process.html
   [215]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@gem_close_race@multigpu-basic-process.html

  * igt@gem_exec_balancer@parallel-contexts:
    - shard-rkl:          [SKIP][216] ([i915#4525]) -> [SKIP][217] ([i915#14544] / [i915#4525])
   [216]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@gem_exec_balancer@parallel-contexts.html
   [217]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@gem_exec_balancer@parallel-contexts.html

  * igt@gem_exec_reloc@basic-write-read-active:
    - shard-rkl:          [SKIP][218] ([i915#14544] / [i915#3281]) -> [SKIP][219] ([i915#3281]) +3 other tests skip
   [218]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@gem_exec_reloc@basic-write-read-active.html
   [219]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@gem_exec_reloc@basic-write-read-active.html

  * igt@gem_exec_suspend@basic-s3:
    - shard-rkl:          [ABORT][220] ([i915#15131] / [i915#15542]) -> [INCOMPLETE][221] ([i915#13356]) +1 other test incomplete
   [220]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-1/igt@gem_exec_suspend@basic-s3.html
   [221]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@gem_exec_suspend@basic-s3.html

  * igt@gem_lmem_swapping@random-engines:
    - shard-rkl:          [SKIP][222] ([i915#4613]) -> [SKIP][223] ([i915#14544] / [i915#4613]) +1 other test skip
   [222]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@gem_lmem_swapping@random-engines.html
   [223]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@gem_lmem_swapping@random-engines.html

  * igt@gem_lmem_swapping@verify-random-ccs:
    - shard-rkl:          [SKIP][224] ([i915#14544] / [i915#4613]) -> [SKIP][225] ([i915#4613])
   [224]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@gem_lmem_swapping@verify-random-ccs.html
   [225]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@gem_lmem_swapping@verify-random-ccs.html

  * igt@gem_pread@bench:
    - shard-rkl:          [SKIP][226] ([i915#3282]) -> [SKIP][227] ([i915#14544] / [i915#3282])
   [226]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@gem_pread@bench.html
   [227]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@gem_pread@bench.html

  * igt@gem_pwrite@basic-exhaustion:
    - shard-rkl:          [SKIP][228] ([i915#14544] / [i915#3282]) -> [SKIP][229] ([i915#3282])
   [228]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@gem_pwrite@basic-exhaustion.html
   [229]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@gem_pwrite@basic-exhaustion.html

  * igt@gem_userptr_blits@unsync-unmap:
    - shard-rkl:          [SKIP][230] ([i915#14544] / [i915#3297]) -> [SKIP][231] ([i915#3297])
   [230]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@gem_userptr_blits@unsync-unmap.html
   [231]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@gem_userptr_blits@unsync-unmap.html

  * igt@gen9_exec_parse@allowed-single:
    - shard-rkl:          [SKIP][232] ([i915#2527]) -> [SKIP][233] ([i915#14544] / [i915#2527])
   [232]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@gen9_exec_parse@allowed-single.html
   [233]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@gen9_exec_parse@allowed-single.html

  * igt@gen9_exec_parse@bb-start-param:
    - shard-rkl:          [SKIP][234] ([i915#14544] / [i915#2527]) -> [SKIP][235] ([i915#2527])
   [234]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@gen9_exec_parse@bb-start-param.html
   [235]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@gen9_exec_parse@bb-start-param.html

  * igt@i915_pm_freq_api@freq-basic-api:
    - shard-rkl:          [SKIP][236] ([i915#14544] / [i915#8399]) -> [SKIP][237] ([i915#8399])
   [236]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@i915_pm_freq_api@freq-basic-api.html
   [237]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@i915_pm_freq_api@freq-basic-api.html

  * igt@intel_hwmon@hwmon-write:
    - shard-rkl:          [SKIP][238] ([i915#14544] / [i915#7707]) -> [SKIP][239] ([i915#7707])
   [238]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@intel_hwmon@hwmon-write.html
   [239]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@intel_hwmon@hwmon-write.html

  * igt@kms_big_fb@4-tiled-32bpp-rotate-270:
    - shard-rkl:          [SKIP][240] ([i915#5286]) -> [SKIP][241] ([i915#14544] / [i915#5286]) +2 other tests skip
   [240]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-1/igt@kms_big_fb@4-tiled-32bpp-rotate-270.html
   [241]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_big_fb@4-tiled-32bpp-rotate-270.html

  * igt@kms_big_fb@4-tiled-addfb-size-overflow:
    - shard-rkl:          [SKIP][242] ([i915#14544] / [i915#5286]) -> [SKIP][243] ([i915#5286]) +1 other test skip
   [242]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_big_fb@4-tiled-addfb-size-overflow.html
   [243]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_big_fb@4-tiled-addfb-size-overflow.html

  * igt@kms_big_fb@linear-8bpp-rotate-90:
    - shard-rkl:          [SKIP][244] ([i915#3638]) -> [SKIP][245] ([i915#14544] / [i915#3638])
   [244]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_big_fb@linear-8bpp-rotate-90.html
   [245]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_big_fb@linear-8bpp-rotate-90.html

  * igt@kms_big_fb@yf-tiled-64bpp-rotate-90:
    - shard-rkl:          [SKIP][246] -> [SKIP][247] ([i915#14544]) +7 other tests skip
   [246]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_big_fb@yf-tiled-64bpp-rotate-90.html
   [247]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_big_fb@yf-tiled-64bpp-rotate-90.html

  * igt@kms_ccs@bad-aux-stride-yf-tiled-ccs@pipe-b-hdmi-a-2:
    - shard-rkl:          [SKIP][248] ([i915#6095]) -> [SKIP][249] ([i915#14544] / [i915#6095]) +14 other tests skip
   [248]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_ccs@bad-aux-stride-yf-tiled-ccs@pipe-b-hdmi-a-2.html
   [249]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_ccs@bad-aux-stride-yf-tiled-ccs@pipe-b-hdmi-a-2.html

  * igt@kms_ccs@bad-pixel-format-4-tiled-mtl-mc-ccs:
    - shard-rkl:          [SKIP][250] ([i915#14098] / [i915#6095]) -> [SKIP][251] ([i915#14098] / [i915#14544] / [i915#6095]) +15 other tests skip
   [250]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-1/igt@kms_ccs@bad-pixel-format-4-tiled-mtl-mc-ccs.html
   [251]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_ccs@bad-pixel-format-4-tiled-mtl-mc-ccs.html

  * igt@kms_ccs@crc-primary-rotation-180-4-tiled-lnl-ccs:
    - shard-rkl:          [SKIP][252] ([i915#12313]) -> [SKIP][253] ([i915#12313] / [i915#14544])
   [252]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-1/igt@kms_ccs@crc-primary-rotation-180-4-tiled-lnl-ccs.html
   [253]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_ccs@crc-primary-rotation-180-4-tiled-lnl-ccs.html

  * igt@kms_ccs@crc-primary-rotation-180-4-tiled-mtl-rc-ccs@pipe-b-hdmi-a-2:
    - shard-rkl:          [SKIP][254] ([i915#14544] / [i915#6095]) -> [SKIP][255] ([i915#6095]) +8 other tests skip
   [254]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_ccs@crc-primary-rotation-180-4-tiled-mtl-rc-ccs@pipe-b-hdmi-a-2.html
   [255]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_ccs@crc-primary-rotation-180-4-tiled-mtl-rc-ccs@pipe-b-hdmi-a-2.html

  * igt@kms_ccs@crc-primary-suspend-y-tiled-ccs@pipe-a-hdmi-a-1:
    - shard-glk:          [INCOMPLETE][256] ([i915#15582]) -> [INCOMPLETE][257] ([i915#14694] / [i915#15582]) +1 other test incomplete
   [256]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-glk5/igt@kms_ccs@crc-primary-suspend-y-tiled-ccs@pipe-a-hdmi-a-1.html
   [257]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk1/igt@kms_ccs@crc-primary-suspend-y-tiled-ccs@pipe-a-hdmi-a-1.html

  * igt@kms_ccs@crc-sprite-planes-basic-4-tiled-dg2-rc-ccs-cc@pipe-c-hdmi-a-2:
    - shard-rkl:          [SKIP][258] ([i915#14098] / [i915#14544] / [i915#6095]) -> [SKIP][259] ([i915#14098] / [i915#6095]) +9 other tests skip
   [258]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_ccs@crc-sprite-planes-basic-4-tiled-dg2-rc-ccs-cc@pipe-c-hdmi-a-2.html
   [259]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_ccs@crc-sprite-planes-basic-4-tiled-dg2-rc-ccs-cc@pipe-c-hdmi-a-2.html

  * igt@kms_chamelium_edid@dp-mode-timings:
    - shard-rkl:          [SKIP][260] ([i915#11151] / [i915#7828]) -> [SKIP][261] ([i915#11151] / [i915#14544] / [i915#7828])
   [260]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-1/igt@kms_chamelium_edid@dp-mode-timings.html
   [261]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_chamelium_edid@dp-mode-timings.html

  * igt@kms_chamelium_frames@hdmi-frame-dump:
    - shard-rkl:          [SKIP][262] ([i915#11151] / [i915#14544] / [i915#7828]) -> [SKIP][263] ([i915#11151] / [i915#7828]) +2 other tests skip
   [262]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_chamelium_frames@hdmi-frame-dump.html
   [263]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_chamelium_frames@hdmi-frame-dump.html

  * igt@kms_content_protection@dp-mst-lic-type-0:
    - shard-rkl:          [SKIP][264] ([i915#14544] / [i915#15330] / [i915#3116]) -> [SKIP][265] ([i915#15330] / [i915#3116])
   [264]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_content_protection@dp-mst-lic-type-0.html
   [265]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_content_protection@dp-mst-lic-type-0.html

  * igt@kms_content_protection@dp-mst-lic-type-0-hdcp14:
    - shard-rkl:          [SKIP][266] ([i915#14544] / [i915#15330]) -> [SKIP][267] ([i915#15330])
   [266]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_content_protection@dp-mst-lic-type-0-hdcp14.html
   [267]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_content_protection@dp-mst-lic-type-0-hdcp14.html

  * igt@kms_content_protection@mei-interface:
    - shard-dg1:          [SKIP][268] ([i915#15865]) -> [SKIP][269] ([i915#9433])
   [268]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg1-16/igt@kms_content_protection@mei-interface.html
   [269]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-12/igt@kms_content_protection@mei-interface.html

  * igt@kms_content_protection@uevent-hdcp14:
    - shard-rkl:          [SKIP][270] ([i915#15865]) -> [SKIP][271] ([i915#14544] / [i915#15865]) +1 other test skip
   [270]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-1/igt@kms_content_protection@uevent-hdcp14.html
   [271]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_content_protection@uevent-hdcp14.html

  * igt@kms_cursor_crc@cursor-offscreen-32x10:
    - shard-rkl:          [SKIP][272] ([i915#14544] / [i915#3555]) -> [SKIP][273] ([i915#3555])
   [272]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_cursor_crc@cursor-offscreen-32x10.html
   [273]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_cursor_crc@cursor-offscreen-32x10.html

  * igt@kms_cursor_crc@cursor-rapid-movement-32x32:
    - shard-rkl:          [SKIP][274] ([i915#3555]) -> [SKIP][275] ([i915#14544] / [i915#3555])
   [274]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-1/igt@kms_cursor_crc@cursor-rapid-movement-32x32.html
   [275]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_cursor_crc@cursor-rapid-movement-32x32.html

  * igt@kms_cursor_legacy@cursora-vs-flipb-varying-size:
    - shard-rkl:          [SKIP][276] ([i915#14544]) -> [SKIP][277] +11 other tests skip
   [276]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_cursor_legacy@cursora-vs-flipb-varying-size.html
   [277]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_cursor_legacy@cursora-vs-flipb-varying-size.html

  * igt@kms_cursor_legacy@modeset-atomic-cursor-hotspot:
    - shard-rkl:          [SKIP][278] ([i915#9067]) -> [SKIP][279] ([i915#14544] / [i915#9067])
   [278]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_cursor_legacy@modeset-atomic-cursor-hotspot.html
   [279]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_cursor_legacy@modeset-atomic-cursor-hotspot.html

  * igt@kms_dirtyfb@drrs-dirtyfb-ioctl:
    - shard-rkl:          [SKIP][280] ([i915#9723]) -> [SKIP][281] ([i915#14544] / [i915#9723])
   [280]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-1/igt@kms_dirtyfb@drrs-dirtyfb-ioctl.html
   [281]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_dirtyfb@drrs-dirtyfb-ioctl.html

  * igt@kms_dsc@dsc-with-bpc:
    - shard-rkl:          [SKIP][282] ([i915#3555] / [i915#3840]) -> [SKIP][283] ([i915#14544] / [i915#3555] / [i915#3840])
   [282]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-1/igt@kms_dsc@dsc-with-bpc.html
   [283]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_dsc@dsc-with-bpc.html

  * igt@kms_fbcon_fbt@psr:
    - shard-rkl:          [SKIP][284] ([i915#14544] / [i915#3955]) -> [SKIP][285] ([i915#3955])
   [284]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_fbcon_fbt@psr.html
   [285]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_fbcon_fbt@psr.html

  * igt@kms_feature_discovery@display-2x:
    - shard-rkl:          [SKIP][286] ([i915#14544] / [i915#1839]) -> [SKIP][287] ([i915#1839])
   [286]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_feature_discovery@display-2x.html
   [287]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_feature_discovery@display-2x.html

  * igt@kms_feature_discovery@psr1:
    - shard-rkl:          [SKIP][288] ([i915#658]) -> [SKIP][289] ([i915#14544] / [i915#658])
   [288]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_feature_discovery@psr1.html
   [289]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_feature_discovery@psr1.html

  * igt@kms_flip@2x-flip-vs-rmfb:
    - shard-rkl:          [SKIP][290] ([i915#14544] / [i915#9934]) -> [SKIP][291] ([i915#9934])
   [290]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_flip@2x-flip-vs-rmfb.html
   [291]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_flip@2x-flip-vs-rmfb.html

  * igt@kms_flip@2x-flip-vs-suspend:
    - shard-rkl:          [SKIP][292] ([i915#9934]) -> [SKIP][293] ([i915#14544] / [i915#9934])
   [292]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_flip@2x-flip-vs-suspend.html
   [293]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_flip@2x-flip-vs-suspend.html

  * igt@kms_flip@flip-vs-suspend-interruptible:
    - shard-glk:          [INCOMPLETE][294] ([i915#12745] / [i915#4839]) -> [INCOMPLETE][295] ([i915#12314] / [i915#12745] / [i915#4839])
   [294]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-glk4/igt@kms_flip@flip-vs-suspend-interruptible.html
   [295]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk8/igt@kms_flip@flip-vs-suspend-interruptible.html

  * igt@kms_flip@flip-vs-suspend-interruptible@a-hdmi-a1:
    - shard-glk:          [INCOMPLETE][296] ([i915#12745]) -> [INCOMPLETE][297] ([i915#12314] / [i915#12745])
   [296]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-glk4/igt@kms_flip@flip-vs-suspend-interruptible@a-hdmi-a1.html
   [297]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-glk8/igt@kms_flip@flip-vs-suspend-interruptible@a-hdmi-a1.html

  * igt@kms_flip_scaled_crc@flip-64bpp-yftile-to-32bpp-yftile-upscaling:
    - shard-rkl:          [SKIP][298] ([i915#14544] / [i915#15643]) -> [SKIP][299] ([i915#15643]) +2 other tests skip
   [298]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_flip_scaled_crc@flip-64bpp-yftile-to-32bpp-yftile-upscaling.html
   [299]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_flip_scaled_crc@flip-64bpp-yftile-to-32bpp-yftile-upscaling.html

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-offscreen-pri-indfb-draw-blt:
    - shard-rkl:          [SKIP][300] ([i915#15102]) -> [SKIP][301] ([i915#14544] / [i915#15102]) +1 other test skip
   [300]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_frontbuffer_tracking@fbcpsr-1p-offscreen-pri-indfb-draw-blt.html
   [301]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_frontbuffer_tracking@fbcpsr-1p-offscreen-pri-indfb-draw-blt.html

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-cur-indfb-draw-mmap-cpu:
    - shard-rkl:          [SKIP][302] ([i915#14544] / [i915#15102] / [i915#3023]) -> [SKIP][303] ([i915#15102] / [i915#3023]) +5 other tests skip
   [302]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-cur-indfb-draw-mmap-cpu.html
   [303]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-cur-indfb-draw-mmap-cpu.html

  * igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-pwrite:
    - shard-dg2:          [SKIP][304] ([i915#10433] / [i915#15102] / [i915#3458]) -> [SKIP][305] ([i915#15102] / [i915#3458]) +3 other tests skip
   [304]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg2-4/igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-pwrite.html
   [305]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-1/igt@kms_frontbuffer_tracking@fbcpsr-1p-primscrn-spr-indfb-draw-pwrite.html

  * igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-shrfb-draw-mmap-wc:
    - shard-rkl:          [SKIP][306] ([i915#1825]) -> [SKIP][307] ([i915#14544] / [i915#1825]) +15 other tests skip
   [306]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-shrfb-draw-mmap-wc.html
   [307]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-pri-shrfb-draw-mmap-wc.html

  * igt@kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-indfb-msflip-blt:
    - shard-rkl:          [SKIP][308] ([i915#14544] / [i915#1825]) -> [SKIP][309] ([i915#1825]) +9 other tests skip
   [308]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-indfb-msflip-blt.html
   [309]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_frontbuffer_tracking@fbcpsr-2p-scndscrn-indfb-msflip-blt.html

  * igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-blt:
    - shard-dg2:          [SKIP][310] ([i915#15102] / [i915#3458]) -> [SKIP][311] ([i915#10433] / [i915#15102] / [i915#3458]) +2 other tests skip
   [310]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg2-7/igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-blt.html
   [311]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg2-4/igt@kms_frontbuffer_tracking@psr-1p-primscrn-pri-shrfb-draw-blt.html

  * igt@kms_frontbuffer_tracking@psr-rgb101010-draw-mmap-gtt:
    - shard-rkl:          [SKIP][312] ([i915#15102] / [i915#3023]) -> [SKIP][313] ([i915#14544] / [i915#15102] / [i915#3023]) +7 other tests skip
   [312]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_frontbuffer_tracking@psr-rgb101010-draw-mmap-gtt.html
   [313]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_frontbuffer_tracking@psr-rgb101010-draw-mmap-gtt.html

  * igt@kms_joiner@invalid-modeset-ultra-joiner:
    - shard-rkl:          [SKIP][314] ([i915#14544] / [i915#15458]) -> [SKIP][315] ([i915#15458])
   [314]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_joiner@invalid-modeset-ultra-joiner.html
   [315]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_joiner@invalid-modeset-ultra-joiner.html

  * igt@kms_panel_fitting@atomic-fastset:
    - shard-rkl:          [SKIP][316] ([i915#14544] / [i915#6301]) -> [SKIP][317] ([i915#6301])
   [316]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_panel_fitting@atomic-fastset.html
   [317]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_panel_fitting@atomic-fastset.html

  * igt@kms_plane@pixel-format-4-tiled-bmg-ccs-modifier-source-clamping:
    - shard-rkl:          [SKIP][318] ([i915#15709]) -> [SKIP][319] ([i915#14544] / [i915#15709]) +1 other test skip
   [318]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_plane@pixel-format-4-tiled-bmg-ccs-modifier-source-clamping.html
   [319]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_plane@pixel-format-4-tiled-bmg-ccs-modifier-source-clamping.html

  * igt@kms_plane@pixel-format-4-tiled-dg2-rc-ccs-modifier-source-clamping:
    - shard-rkl:          [SKIP][320] ([i915#14544] / [i915#15709]) -> [SKIP][321] ([i915#15709])
   [320]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_plane@pixel-format-4-tiled-dg2-rc-ccs-modifier-source-clamping.html
   [321]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_plane@pixel-format-4-tiled-dg2-rc-ccs-modifier-source-clamping.html

  * igt@kms_plane@pixel-format-y-tiled-gen12-mc-ccs-modifier-source-clamping:
    - shard-dg1:          [SKIP][322] ([i915#15709] / [i915#4423]) -> [SKIP][323] ([i915#15709])
   [322]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-dg1-13/igt@kms_plane@pixel-format-y-tiled-gen12-mc-ccs-modifier-source-clamping.html
   [323]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-dg1-15/igt@kms_plane@pixel-format-y-tiled-gen12-mc-ccs-modifier-source-clamping.html

  * igt@kms_plane_scaling@plane-scaler-unity-scaling-with-rotation@pipe-b:
    - shard-rkl:          [SKIP][324] ([i915#14544] / [i915#15329]) -> [SKIP][325] ([i915#15329]) +3 other tests skip
   [324]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_plane_scaling@plane-scaler-unity-scaling-with-rotation@pipe-b.html
   [325]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_plane_scaling@plane-scaler-unity-scaling-with-rotation@pipe-b.html

  * igt@kms_pm_backlight@brightness-with-dpms:
    - shard-rkl:          [SKIP][326] ([i915#12343]) -> [SKIP][327] ([i915#12343] / [i915#14544])
   [326]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_pm_backlight@brightness-with-dpms.html
   [327]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_pm_backlight@brightness-with-dpms.html

  * igt@kms_pm_dc@dc6-psr:
    - shard-rkl:          [SKIP][328] ([i915#15948]) -> [SKIP][329] ([i915#14544] / [i915#15948])
   [328]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-1/igt@kms_pm_dc@dc6-psr.html
   [329]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_pm_dc@dc6-psr.html

  * igt@kms_prime@basic-crc-hybrid:
    - shard-rkl:          [SKIP][330] ([i915#6524]) -> [SKIP][331] ([i915#14544] / [i915#6524])
   [330]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_prime@basic-crc-hybrid.html
   [331]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_prime@basic-crc-hybrid.html

  * igt@kms_prime@basic-modeset-hybrid:
    - shard-rkl:          [SKIP][332] ([i915#14544] / [i915#6524]) -> [SKIP][333] ([i915#6524])
   [332]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_prime@basic-modeset-hybrid.html
   [333]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_prime@basic-modeset-hybrid.html

  * igt@kms_psr2_sf@fbc-pr-overlay-plane-move-continuous-exceed-sf:
    - shard-rkl:          [SKIP][334] ([i915#11520] / [i915#14544]) -> [SKIP][335] ([i915#11520]) +2 other tests skip
   [334]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_psr2_sf@fbc-pr-overlay-plane-move-continuous-exceed-sf.html
   [335]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_psr2_sf@fbc-pr-overlay-plane-move-continuous-exceed-sf.html

  * igt@kms_psr2_sf@fbc-pr-primary-plane-update-sf-dmg-area:
    - shard-rkl:          [SKIP][336] ([i915#11520]) -> [SKIP][337] ([i915#11520] / [i915#14544]) +1 other test skip
   [336]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_psr2_sf@fbc-pr-primary-plane-update-sf-dmg-area.html
   [337]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_psr2_sf@fbc-pr-primary-plane-update-sf-dmg-area.html

  * igt@kms_psr2_su@page_flip-p010:
    - shard-rkl:          [SKIP][338] ([i915#14544] / [i915#9683]) -> [SKIP][339] ([i915#9683])
   [338]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_psr2_su@page_flip-p010.html
   [339]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_psr2_su@page_flip-p010.html

  * igt@kms_psr@fbc-pr-cursor-render:
    - shard-rkl:          [SKIP][340] ([i915#1072] / [i915#9732]) -> [SKIP][341] ([i915#1072] / [i915#14544] / [i915#9732]) +9 other tests skip
   [340]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-1/igt@kms_psr@fbc-pr-cursor-render.html
   [341]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_psr@fbc-pr-cursor-render.html

  * igt@kms_psr@psr-cursor-mmap-cpu:
    - shard-rkl:          [SKIP][342] ([i915#1072] / [i915#14544] / [i915#9732]) -> [SKIP][343] ([i915#1072] / [i915#9732]) +6 other tests skip
   [342]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_psr@psr-cursor-mmap-cpu.html
   [343]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-3/igt@kms_psr@psr-cursor-mmap-cpu.html

  * igt@kms_vrr@flip-suspend:
    - shard-rkl:          [SKIP][344] ([i915#15243] / [i915#3555]) -> [SKIP][345] ([i915#14544] / [i915#15243] / [i915#3555])
   [344]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-4/igt@kms_vrr@flip-suspend.html
   [345]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@kms_vrr@flip-suspend.html

  * igt@kms_vrr@seamless-rr-switch-drrs:
    - shard-rkl:          [SKIP][346] ([i915#14544] / [i915#9906]) -> [SKIP][347] ([i915#9906])
   [346]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@kms_vrr@seamless-rr-switch-drrs.html
   [347]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@kms_vrr@seamless-rr-switch-drrs.html

  * igt@perf@gen8-unprivileged-single-ctx-counters:
    - shard-rkl:          [SKIP][348] ([i915#14544] / [i915#2436]) -> [SKIP][349] ([i915#2436])
   [348]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@perf@gen8-unprivileged-single-ctx-counters.html
   [349]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@perf@gen8-unprivileged-single-ctx-counters.html

  * igt@prime_vgem@fence-read-hang:
    - shard-rkl:          [SKIP][350] ([i915#14544] / [i915#3708]) -> [SKIP][351] ([i915#3708])
   [350]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-6/igt@prime_vgem@fence-read-hang.html
   [351]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-4/igt@prime_vgem@fence-read-hang.html

  * igt@prime_vgem@fence-write-hang:
    - shard-rkl:          [SKIP][352] ([i915#3708]) -> [SKIP][353] ([i915#14544] / [i915#3708])
   [352]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_18377/shard-rkl-1/igt@prime_vgem@fence-write-hang.html
   [353]: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/shard-rkl-6/igt@prime_vgem@fence-write-hang.html

  
  [i915#10307]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/10307
  [i915#10433]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/10433
  [i915#10434]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/10434
  [i915#10647]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/10647
  [i915#1072]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/1072
  [i915#11151]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/11151
  [i915#11520]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/11520
  [i915#11681]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/11681
  [i915#11920]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/11920
  [i915#12061]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12061
  [i915#12169]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12169
  [i915#12177]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12177
  [i915#12276]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12276
  [i915#12313]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12313
  [i915#12314]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12314
  [i915#12343]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12343
  [i915#12358]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12358
  [i915#12392]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12392
  [i915#12713]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12713
  [i915#12745]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12745
  [i915#12805]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/12805
  [i915#13027]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/13027
  [i915#13046]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/13046
  [i915#13049]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/13049
  [i915#13356]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/13356
  [i915#13398]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/13398
  [i915#13520]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/13520
  [i915#13566]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/13566
  [i915#13691]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/13691
  [i915#13748]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/13748
  [i915#13749]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/13749
  [i915#13790]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/13790
  [i915#14098]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14098
  [i915#14118]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14118
  [i915#14152]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14152
  [i915#14498]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14498
  [i915#14544]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14544
  [i915#14600]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14600
  [i915#14694]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14694
  [i915#14702]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/14702
  [i915#15073]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15073
  [i915#15102]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15102
  [i915#15104]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15104
  [i915#15131]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15131
  [i915#15243]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15243
  [i915#15329]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15329
  [i915#15330]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15330
  [i915#15389]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15389
  [i915#15403]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15403
  [i915#15433]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15433
  [i915#15458]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15458
  [i915#15460]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15460
  [i915#15492]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15492
  [i915#15542]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15542
  [i915#15560]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15560
  [i915#15582]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15582
  [i915#15643]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15643
  [i915#15662]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15662
  [i915#15709]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15709
  [i915#15865]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15865
  [i915#15948]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15948
  [i915#15949]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/15949
  [i915#1769]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/1769
  [i915#1825]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/1825
  [i915#1839]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/1839
  [i915#2436]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/2436
  [i915#2527]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/2527
  [i915#2658]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/2658
  [i915#2681]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/2681
  [i915#284]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/284
  [i915#2856]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/2856
  [i915#3023]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3023
  [i915#3116]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3116
  [i915#3281]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3281
  [i915#3282]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3282
  [i915#3297]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3297
  [i915#3299]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3299
  [i915#3458]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3458
  [i915#3555]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3555
  [i915#3637]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3637
  [i915#3638]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3638
  [i915#3708]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3708
  [i915#3828]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3828
  [i915#3840]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3840
  [i915#3955]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/3955
  [i915#4077]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/4077
  [i915#4270]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/4270
  [i915#4423]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/4423
  [i915#4525]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/4525
  [i915#4613]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/4613
  [i915#4771]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/4771
  [i915#4839]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/4839
  [i915#4854]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/4854
  [i915#4860]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/4860
  [i915#5190]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/5190
  [i915#5286]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/5286
  [i915#5289]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/5289
  [i915#5354]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/5354
  [i915#5956]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/5956
  [i915#6095]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/6095
  [i915#6301]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/6301
  [i915#6344]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/6344
  [i915#6524]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/6524
  [i915#658]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/658
  [i915#6621]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/6621
  [i915#6880]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/6880
  [i915#7697]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/7697
  [i915#7707]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/7707
  [i915#7828]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/7828
  [i915#7882]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/7882
  [i915#7984]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/7984
  [i915#8228]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/8228
  [i915#8381]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/8381
  [i915#8399]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/8399
  [i915#8411]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/8411
  [i915#8430]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/8430
  [i915#8516]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/8516
  [i915#8562]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/8562
  [i915#8623]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/8623
  [i915#8708]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/8708
  [i915#8808]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/8808
  [i915#9067]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9067
  [i915#9323]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9323
  [i915#9433]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9433
  [i915#9683]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9683
  [i915#9688]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9688
  [i915#9723]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9723
  [i915#9732]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9732
  [i915#9766]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9766
  [i915#9809]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9809
  [i915#9812]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9812
  [i915#9906]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9906
  [i915#9917]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9917
  [i915#9934]: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/9934


Build changes
-------------

  * Linux: CI_DRM_18377 -> Patchwork_165632v2

  CI-20190529: 20190529
  CI_DRM_18377: a53aafc879e9c52b2776089762591d2766a27f0a @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_8877: 1749e432cd72ef2c99f1b4e9d6f24411f1161901 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  Patchwork_165632v2: a53aafc879e9c52b2776089762591d2766a27f0a @ git://anongit.freedesktop.org/gfx-ci/linux
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_165632v2/index.html

[-- Attachment #2: Type: text/html, Size: 122410 bytes --]

^ permalink raw reply	[flat|nested] 113+ messages in thread

end of thread, other threads:[~2026-04-29 15:35 UTC | newest]

Thread overview: 113+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-28 12:50 [PATCH 000/108] drm/i915/dp_link: Refactor DP link capability logic Imre Deak
2026-04-28 12:50 ` [PATCH 001/108] drm/i915/dp: Move clamping max link rate to common rates setup Imre Deak
2026-04-28 12:50 ` [PATCH 002/108] drm/i915/dp: Clamp max lane count to max common lane count Imre Deak
2026-04-28 12:50 ` [PATCH 003/108] drm/i915/dp: Bump connector epoch on link capability changes Imre Deak
2026-04-28 12:50 ` [PATCH 004/108] drm/i915/dp_link_training: Introduce link training state struct Imre Deak
2026-04-28 12:50 ` [PATCH 005/108] drm/i915/dp_link_training: Factor out link training state reset helper Imre Deak
2026-04-28 12:50 ` [PATCH 006/108] drm/i915/dp_link_training: Reset link training state on link capability change Imre Deak
2026-04-28 12:50 ` [PATCH 007/108] drm/i915/dp_link_training: Flush commits in debugfs entries Imre Deak
2026-04-28 12:50 ` [PATCH 008/108] drm/i915/dp_link_training: Move link training helpers to link training code Imre Deak
2026-04-28 12:50 ` [PATCH 009/108] drm/i915/dp_link_training: Use link_training as base pointer in debugfs Imre Deak
2026-04-28 12:50 ` [PATCH 010/108] drm/i915/dp_link_training: Add helpers to access force retrain state Imre Deak
2026-04-28 12:50 ` [PATCH 011/108] drm/i915/dp_link_training: Move link recovery/debug state to link_training Imre Deak
2026-04-28 12:50 ` [PATCH 012/108] drm/i915/dp_link_training: Prevent repeated autoretrain attempts Imre Deak
2026-04-28 12:50 ` [PATCH 013/108] drm/i915/dp_link_training: Clamp sequential link training failure counter Imre Deak
2026-04-28 12:50 ` [PATCH 014/108] drm/i915/dp_link_training: Check for pending autoretrain explicitly Imre Deak
2026-04-28 12:50 ` [PATCH 015/108] drm/i915/dp_link_training: Add helper to query pending autoretrain Imre Deak
2026-04-28 12:50 ` [PATCH 016/108] drm/i915/dp_link_training: Add helper to query allowed autoretrain Imre Deak
2026-04-28 12:50 ` [PATCH 017/108] drm/i915/dp_link_training: Add helper to mark link training failure Imre Deak
2026-04-28 12:50 ` [PATCH 018/108] drm/i915/dp_link_training: Add helper to reset link recovery state Imre Deak
2026-04-28 12:51 ` [PATCH 019/108] drm/i915/dp_link_training: Track link recovery state with an enum Imre Deak
2026-04-28 12:51 ` [PATCH 020/108] drm/i915/dp_link_training: Add no-fallback link recovery state Imre Deak
2026-04-28 12:51 ` [PATCH 021/108] drm/i915/display: Factor out a helper to modeset a pipe with atomic state Imre Deak
2026-04-28 12:51 ` [PATCH 022/108] drm/i915/display: Simplify intel_modeset_commit_pipes_for_atomic_state() Imre Deak
2026-04-28 12:51 ` [PATCH 023/108] drm/i915/dp_link_training: Allocate atomic state for autoretrain modeset Imre Deak
2026-04-28 12:51 ` [PATCH 024/108] drm/i915/dp_link_training: Disallow autoretrains after failed modeset Imre Deak
2026-04-28 12:51 ` [PATCH 025/108] drm/i915/dp_link_training: Fix kernel-doc of intel_dp_init_lttpr_and_dprx_caps() Imre Deak
2026-04-28 12:51 ` [PATCH 026/108] drm/i915/dp_link_training: Document DP link recovery logic Imre Deak
2026-04-28 12:51 ` [PATCH 027/108] drm/i915/dp: Rename intel_dp_link_config to intel_dp_link_config_entry Imre Deak
2026-04-28 12:51 ` [PATCH 028/108] drm/i915/dp: Add struct intel_dp_link_config Imre Deak
2026-04-28 12:51 ` [PATCH 029/108] drm/i915/dp_link_caps: Introduce DP link capability module Imre Deak
2026-04-28 12:51 ` [PATCH 030/108] drm/i915/dp_link_caps: Move common rate helpers to link caps Imre Deak
2026-04-28 12:51 ` [PATCH 031/108] drm/i915/dp_link_caps: Move forced link param " Imre Deak
2026-04-28 12:51 ` [PATCH 032/108] drm/i915/dp: Simplify querying of forced link parameters Imre Deak
2026-04-28 12:51 ` [PATCH 033/108] drm/i915/dp_link_caps: Move forced and max link debugfs entries to link caps Imre Deak
2026-04-28 12:51 ` [PATCH 034/108] drm/i915/dp_link_training: Use helpers to get forced link params Imre Deak
2026-04-28 12:51 ` [PATCH 035/108] drm/i915/dp_link_caps: Move forced link params to link_caps Imre Deak
2026-04-28 12:51 ` [PATCH 036/108] drm/i915/dp_link_caps: Move link config helpers to link caps Imre Deak
2026-04-28 12:51 ` [PATCH 037/108] drm/i915/dp_link_caps: Move link config tracking to link_caps Imre Deak
2026-04-28 12:51 ` [PATCH 038/108] drm/i915/dp_link_caps: Rename helper updating the link configurations Imre Deak
2026-04-28 12:51 ` [PATCH 039/108] drm/i915/dp: Factor out helper to get link rate capabilities Imre Deak
2026-04-28 12:51 ` [PATCH 040/108] drm/i915/dp_link_caps: Pass supported link rates to link caps update Imre Deak
2026-04-28 12:51 ` [PATCH 041/108] drm/i915/dp_link_caps: Add helper to get all supported link rates Imre Deak
2026-04-28 12:51 ` [PATCH 042/108] drm/i915/dp_link_caps: Add helper to get the number of " Imre Deak
2026-04-28 12:51 ` [PATCH 043/108] drm/i915/dp_link_caps: Add helper to get common rate index Imre Deak
2026-04-28 12:51 ` [PATCH 044/108] drm/i915/dp_link_caps: Move tracking of common rates to link_caps struct Imre Deak
2026-04-28 12:51 ` [PATCH 045/108] drm/i915/dp_link_caps: Track max common lane count in link_caps Imre Deak
2026-04-28 12:51 ` [PATCH 046/108] drm/i915/dp_link_caps: Move max lane count change detection to link_caps Imre Deak
2026-04-28 12:51 ` [PATCH 047/108] drm/i915/dp_link_caps: Use max common lane count from link_caps Imre Deak
2026-04-28 12:51 ` [PATCH 048/108] drm/i915/dp_link_caps: Move updating max link limits to link_caps update Imre Deak
2026-04-28 12:51 ` [PATCH 049/108] drm/i915/dp_link_caps: Add helpers to get max link limits Imre Deak
2026-04-28 12:51 ` [PATCH 050/108] drm/i915/dp_link_caps: Add helpers to set " Imre Deak
2026-04-28 12:51 ` [PATCH 051/108] drm/i915/dp_link_caps: Validate " Imre Deak
2026-04-28 12:51 ` [PATCH 052/108] drm/i915/dp_link_caps: Add helper to reset " Imre Deak
2026-04-28 12:51 ` [PATCH 053/108] drm/i915/dp_link_caps: Add helper to reset link_caps state Imre Deak
2026-04-28 12:51 ` [PATCH 054/108] drm/i915/dp_link_caps: Move max link limits to link_caps Imre Deak
2026-04-28 12:51 ` [PATCH 055/108] drm/i915/dp_link_caps: Pass link_caps to static functions Imre Deak
2026-04-28 12:51 ` [PATCH 056/108] drm/i915/dp_link_caps: Pass link_caps to config update/lookup helpers Imre Deak
2026-04-28 12:51 ` [PATCH 057/108] drm/i915/dp_link_caps: Pass link_caps to common rate helpers Imre Deak
2026-04-28 12:51 ` [PATCH 058/108] drm/i915/dp_link_caps: Add link_caps prefix " Imre Deak
2026-04-28 12:51 ` [PATCH 059/108] drm/i915/dp_link_caps: Add missing documentation to exported functions Imre Deak
2026-04-28 12:51 ` [PATCH 060/108] drm/i915/dp_link_caps: Set forced link params before resetting link params Imre Deak
2026-04-28 12:51 ` [PATCH 061/108] drm/i915/dp_link_caps: Adjust max_limits during link config update Imre Deak
2026-04-28 12:51 ` [PATCH 062/108] drm/i915/dp_link_caps: Adjust max_limits when setting or resetting it Imre Deak
2026-04-28 12:51 ` [PATCH 063/108] drm/i915/dp: Simplify the modeset max link rate limit computation Imre Deak
2026-04-28 12:51 ` [PATCH 064/108] drm/i915/dp: Query max limits via link_caps during mode validation Imre Deak
2026-04-28 12:51 ` [PATCH 065/108] drm/i915/dp_tunnel: Query max link limits via link_caps for BW computation Imre Deak
2026-04-28 12:51 ` [PATCH 066/108] drm/i915/doc: Document DP link capabilities Imre Deak
2026-04-28 12:51 ` [PATCH 067/108] drm/i915/dp_link_caps: Move config table members to a substruct Imre Deak
2026-04-28 12:51 ` [PATCH 068/108] drm/i915/dp_link_caps: Factor out a helper to look up a config table rate Imre Deak
2026-04-28 12:51 ` [PATCH 069/108] drm/i915/dp_link_caps: Pass config table pointer to rate lookup helper Imre Deak
2026-04-28 12:51 ` [PATCH 070/108] drm/i915/dp_link_caps: Factor out helper to get link config from table by index Imre Deak
2026-04-28 12:51 ` [PATCH 071/108] drm/i915/dp_link_caps: Add helper to get config at iterator position Imre Deak
2026-04-28 12:51 ` [PATCH 072/108] drm/i915/dp_link_caps: Add helper to find position of matching config Imre Deak
2026-04-28 12:51 ` [PATCH 073/108] drm/i915/dp_link_training: Reset the max link limits in the fallback code Imre Deak
2026-04-28 12:51 ` [PATCH 074/108] drm/i915/dp_link_training: Use config iterator for BW-order fallback Imre Deak
2026-04-28 12:51 ` [PATCH 075/108] drm/i915/dp_link_training: Look up configurations using fuzzy rate matching Imre Deak
2026-04-28 12:51 ` [PATCH 076/108] drm/i915/dp_link_caps: Pass table pointer to the sort compare function Imre Deak
2026-04-28 12:51 ` [PATCH 077/108] drm/i915/dp_link_caps: Compare config tables instead of link parameters Imre Deak
2026-04-28 12:51 ` [PATCH 078/108] drm/i915/dp_link_caps: Precompute config table before update Imre Deak
2026-04-28 12:52 ` [PATCH 079/108] drm/i915/dp_link_caps: Compare internal config entries during table matching Imre Deak
2026-04-28 12:52 ` [PATCH 080/108] drm/i915/dp_link_caps: Use virtual config indexing in config table Imre Deak
2026-04-28 12:52 ` [PATCH 081/108] drm/i915/dp_link_caps: Simplify idx->link rate/lane count lookup Imre Deak
2026-04-28 12:52 ` [PATCH 082/108] drm/i915/dp_link_caps: Simplify BW order pos->config index array Imre Deak
2026-04-28 12:52 ` [PATCH 083/108] drm/i915/dp_link_caps: Add helper to get iteration order for a connector Imre Deak
2026-04-28 12:52 ` [PATCH 084/108] drm/i915/dp_link_caps: Add reset and merge update modes Imre Deak
2026-04-28 12:52 ` [PATCH 085/108] drm/i915/dp_link_caps: Add mask for disabled link configurations Imre Deak
2026-04-28 12:52 ` [PATCH 086/108] drm/i915/dp_link_caps: Add link configuration iterators Imre Deak
2026-04-28 12:52 ` [PATCH 087/108] drm/i915/dp_link_caps: Preserve disabled config mask during merge update Imre Deak
2026-04-28 12:52 ` [PATCH 088/108] drm/i915/dp_link_caps: Account for disabled configs during max link info update Imre Deak
2026-04-28 12:52 ` [PATCH 089/108] drm/i915/dp_link_caps: Add debugfs entry showing allowed configurations Imre Deak
2026-04-28 12:52 ` [PATCH 090/108] drm/i915/dp: Add a mask of valid configurations for modeset computation Imre Deak
2026-04-28 12:52 ` [PATCH 091/108] drm/i915/dp: Iterate configurations via link_caps for SST non-DSC Imre Deak
2026-04-28 12:52 ` [PATCH 092/108] drm/i915/dp: Iterate configurations via link_caps for SST DSC Imre Deak
2026-04-28 12:52 ` [PATCH 093/108] drm/i915/dp: Use link caps for eDP DSC config selection Imre Deak
2026-04-28 12:52 ` [PATCH 094/108] drm/i915/dp_mst: Use link caps for non-DSC " Imre Deak
2026-04-28 12:52 ` [PATCH 095/108] drm/i915/dp_mst: Use link caps for MST DSC " Imre Deak
2026-04-28 12:52 ` [PATCH 096/108] drm/i915/dp_test: Use link caps for compliance link configs Imre Deak
2026-04-28 12:52 ` [PATCH 097/108] drm/i915/dp: Remove min/max link config limits Imre Deak
2026-04-28 12:52 ` [PATCH 098/108] drm/i915/dp_link_training: Account for disabled configs during SST fallback Imre Deak
2026-04-28 12:52 ` [PATCH 099/108] drm/i915/dp_link_training: Disable failed config during fallback Imre Deak
2026-04-28 12:52 ` [PATCH 100/108] drm/i915/kunit: Enable KUnit tests Imre Deak
2026-04-28 12:52 ` [PATCH 101/108] drm/i915/kunit: Add DP link test stub Imre Deak
2026-04-29  7:36   ` [PATCH v2 " Imre Deak
2026-04-28 12:52 ` [PATCH 102/108] drm/xe/kunit: Add display test config Imre Deak
2026-04-28 12:52 ` [PATCH 103/108] drm/xe/kunit: Build DP link display tests Imre Deak
2026-04-28 12:52 ` [PATCH 104/108] drm/i915/kunit: setup DP link test context Imre Deak
2026-04-28 12:52 ` [PATCH 105/108] drm/i915/kunit: Export link training and caps funcs for testing Imre Deak
2026-04-28 12:52 ` [PATCH 106/108] drm/i915/kunit: DP link: add baseline fixed table reference test Imre Deak
2026-04-28 12:52 ` [PATCH 107/108] drm/i915/kunit: DP link: add update config tests Imre Deak
2026-04-28 12:52 ` [PATCH 108/108] drm/i915/kunit: DP link: add fallback tests Imre Deak
2026-04-28 14:38 ` ✗ Fi.CI.BUILD: failure for drm/i915/dp_link: Refactor DP link capability logic Patchwork
2026-04-29  9:17 ` ✓ i915.CI.BAT: success for drm/i915/dp_link: Refactor DP link capability logic (rev2) Patchwork
2026-04-29 15:35 ` ✗ i915.CI.Full: failure " Patchwork

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox