[PATCH 086/108] drm/i915/dp_link_caps: Add link configuration iterators

Imre Deak
2026-04-28T12:55:29Z

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