Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v9 7/8] drm/i915: override Combo's VS/PE when requested
From: Michał Grzelak @ 2026-06-26 23:42 UTC (permalink / raw)
  To: intel-gfx, intel-xe; +Cc: Jani Nikula, Suraj Kandpal, Michał Grzelak
In-Reply-To: <20260626234246.2446451-1-michal.grzelak@intel.com>

Add accessor function for Combo to read requested table from VBT #57.
Parse the requested table and transform data into port's buffer.

For EHL, in cases when eDP encoder uses low vswing, choose 3rd table if
encoder supports HBR3. Otherwise use 2nd table for eDP using low vswing.

In cases when eDP encoder does not use low vswing, choose 2nd table if
encoder supports mode higher or including HBR2. Otherwise use 3rd table
for eDP not using low vswing.

For external DP use 2nd table if encoder supports modes higher than or
including HBR2. Use 1st table if external DP encoder supports modes
lower than HBR2.

For JSL, always use 1st table for external DP. For eDPs not using low
vswing use 1st table as well.

In cases when eDP encoder uses low vswing, choose 1st table if encoder
supports HBR3. When encoder supports HBR2 choose 3rd table. When
encoder supports modes lower than HBR2 choose 2nd table.

There are no changes to intel_ddi_dp_level() since selection of correct
row of intel_ddi_buf_trans_entry is same as when no override request has
been done.

Looking from other OSes, in case when encoder does not support DP we
could theoretically use 1st table. However, as of now, use default
tables.

v8->v9
- deconstify intel_ddi_buf_trans_entry

v6->v7
- handle VS/PE-O's VBT details in intel_bios_* functions (Jani)
- remove vspeo's cast to (void *) (Jani)
- call encoder->get_buf_trans() once (Jani)
- return NULL from intel_bios_get_* when using default (Jani)
- validate VS/PE-O in intel_bios.c (Jani)
- check devdata->vspeo if VS/PE-O was requested
- inline {jsl,ehl}_combo_get_vspeo_buf_trans()
- remove temporarily LT

v4->v5
- blend index computation with table parsing
- remove enums entirely
- add spaces around operators (Suraj)
- remove spaces after type casting (Suraj)
- remove INTEL_DISPLAY_STATE_WARN (Suraj)

Signed-off-by: Michał Grzelak <michal.grzelak@intel.com>
Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com> # v7
---
 drivers/gpu/drm/i915/display/intel_bios.c     | 98 +++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_bios.h     |  6 ++
 .../drm/i915/display/intel_ddi_buf_trans.c    |  6 ++
 3 files changed, 110 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 0da87ff9a905a..c5265a532dfd6 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -3960,6 +3960,104 @@ intel_bios_get_c10_vspeo(const struct intel_bios_encoder_data *devdata,
 	return vspeo;
 }
 
+const struct intel_ddi_buf_trans *
+intel_bios_get_ehl_combo_vspeo(const struct intel_bios_encoder_data *devdata,
+			       bool has_dp, int port_clock, bool has_edp)
+{
+	struct intel_display *display;
+	union intel_ddi_buf_trans_entry *entries;
+	int num_columns, num_rows, level, idx;
+	struct intel_ddi_buf_trans *vspeo;
+	const u32 *tables;
+	size_t offset = 0;
+
+	if (!validate_vspeo(devdata, has_dp))
+		return NULL;
+
+	display = devdata->display;
+	vspeo = devdata->vspeo;
+	entries = vspeo->entries;
+	tables = display->vbt.vspeo.tables;
+	num_columns = display->vbt.vspeo.num_columns;
+	num_rows = display->vbt.vspeo.num_rows;
+
+	idx = port_clock > 270000 ? 1 : 0;
+	if (has_edp)
+		idx = port_clock > 540000 ? 2 : 1;
+
+	offset += idx * num_rows * num_columns;
+
+	for (level = 0; level < num_rows; level++) {
+		u32 dw2_swing_sel = tables[offset];
+		u32 dw7_n_scalar = tables[offset + 1];
+		u32 dw4_cursor_coeff = tables[offset + 2];
+		u32 dw4_post_cursor_2 = tables[offset + 3];
+		u32 dw4_post_cursor_1 = tables[offset + 4];
+
+		entries[level].icl.dw2_swing_sel = dw2_swing_sel;
+		entries[level].icl.dw7_n_scalar = dw7_n_scalar;
+		entries[level].icl.dw4_cursor_coeff = dw4_cursor_coeff;
+		entries[level].icl.dw4_post_cursor_2 = dw4_post_cursor_2;
+		entries[level].icl.dw4_post_cursor_1 = dw4_post_cursor_1;
+
+		offset += num_columns;
+	}
+
+	return vspeo;
+}
+
+const struct intel_ddi_buf_trans *
+intel_bios_get_jsl_combo_vspeo(const struct intel_bios_encoder_data *devdata,
+			       bool has_dp, int port_clock, bool low_vswing_edp)
+{
+	struct intel_display *display;
+	union intel_ddi_buf_trans_entry *entries;
+	int num_columns, num_rows, level, idx;
+	struct intel_ddi_buf_trans *vspeo;
+	const u32 *tables;
+	size_t offset = 0;
+
+	if (!validate_vspeo(devdata, has_dp))
+		return NULL;
+
+	display = devdata->display;
+	vspeo = devdata->vspeo;
+	entries = vspeo->entries;
+	tables = display->vbt.vspeo.tables;
+	num_columns = display->vbt.vspeo.num_columns;
+	num_rows = display->vbt.vspeo.num_rows;
+
+	idx = 0;
+	if (low_vswing_edp) {
+		if (port_clock > 540000)
+			idx = 0;
+		else if (port_clock > 270000)
+			idx = 1;
+		else
+			idx = 2;
+	}
+
+	offset += idx * num_rows * num_columns;
+
+	for (level = 0; level < num_rows; level++) {
+		u32 dw2_swing_sel = tables[offset];
+		u32 dw7_n_scalar = tables[offset + 1];
+		u32 dw4_cursor_coeff = tables[offset + 2];
+		u32 dw4_post_cursor_2 = tables[offset + 3];
+		u32 dw4_post_cursor_1 = tables[offset + 4];
+
+		entries[level].icl.dw2_swing_sel = dw2_swing_sel;
+		entries[level].icl.dw7_n_scalar = dw7_n_scalar;
+		entries[level].icl.dw4_cursor_coeff = dw4_cursor_coeff;
+		entries[level].icl.dw4_post_cursor_2 = dw4_post_cursor_2;
+		entries[level].icl.dw4_post_cursor_1 = dw4_post_cursor_1;
+
+		offset += num_columns;
+	}
+
+	return vspeo;
+}
+
 bool intel_bios_encoder_is_dedicated_external(const struct intel_bios_encoder_data *devdata)
 {
 	return devdata->display->vbt.version >= 264 &&
diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h
index 49acf8c405e2b..c55765a945949 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.h
+++ b/drivers/gpu/drm/i915/display/intel_bios.h
@@ -79,6 +79,12 @@ intel_bios_get_c20_vspeo(const struct intel_bios_encoder_data *devdata,
 const struct intel_ddi_buf_trans *
 intel_bios_get_c10_vspeo(const struct intel_bios_encoder_data *devdata,
 			 bool has_dp, int port_clock, bool has_edp);
+const struct intel_ddi_buf_trans *
+intel_bios_get_ehl_combo_vspeo(const struct intel_bios_encoder_data *devdata,
+			       bool has_dp, int port_clock, bool has_edp);
+const struct intel_ddi_buf_trans *
+intel_bios_get_jsl_combo_vspeo(const struct intel_bios_encoder_data *devdata,
+			       bool has_dp, int port_clock, bool low_vswing_edp);
 
 bool intel_bios_encoder_requests_vspeo(const struct intel_bios_encoder_data *devdata);
 bool intel_bios_encoder_supports_dvi(const struct intel_bios_encoder_data *devdata);
diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c
index 9a294011ea4fa..22fd7ce005826 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c
@@ -1873,6 +1873,12 @@ const struct intel_ddi_buf_trans *intel_ddi_buf_trans_get(struct intel_encoder *
 			buf_trans = intel_bios_get_c10_vspeo(devdata, has_dp, port_clock, has_edp);
 		else
 			buf_trans = intel_bios_get_c20_vspeo(devdata, has_dp, is_uhbr);
+	} else if (DISPLAY_VER(display) == 11) {
+		if (display->platform.jasperlake)
+			buf_trans = intel_bios_get_jsl_combo_vspeo(devdata, has_dp, port_clock,
+								   has_edp && use_edp_low_vswing(encoder));
+		else if (display->platform.elkhartlake)
+			buf_trans = intel_bios_get_ehl_combo_vspeo(devdata, has_dp, port_clock, has_edp);
 	}
 
 	if (buf_trans)
-- 
2.45.2


^ permalink raw reply related

* [PATCH v9 8/8] drm/i915/bios: remove VS/PE-O warning
From: Michał Grzelak @ 2026-06-26 23:42 UTC (permalink / raw)
  To: intel-gfx, intel-xe; +Cc: Jani Nikula, Suraj Kandpal, Michał Grzelak
In-Reply-To: <20260626234246.2446451-1-michal.grzelak@intel.com>

There is not much use of warning when port asks to override default
VS/PE since it is already logged. Remove drm_WARN() and child_device
from print_ddi_port() since drm_WARN() was the only user of it.

Signed-off-by: Michał Grzelak <michal.grzelak@intel.com>
Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com> # v4
---
 drivers/gpu/drm/i915/display/intel_bios.c | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index c5265a532dfd6..9738a2c7f49f7 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -2770,7 +2770,6 @@ static bool is_port_valid(struct intel_display *display, enum port port)
 static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
 {
 	struct intel_display *display = devdata->display;
-	const struct child_device_config *child = &devdata->child;
 	bool is_dvi, is_hdmi, is_dp, is_edp, is_dsi, is_crt, supports_typec_usb, supports_tbt;
 	int dp_boost_level, dp_max_link_rate, hdmi_boost_level, hdmi_level_shift, max_tmds_clock;
 	enum port port;
@@ -2843,14 +2842,6 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
 		drm_dbg_kms(display->drm,
 			    "Port %c VBT DP max link rate: %d\n",
 			    port_name(port), dp_max_link_rate);
-
-	/*
-	 * FIXME need to implement support for VBT
-	 * vswing/preemph tables should this ever trigger.
-	 */
-	drm_WARN(display->drm, child->use_vbt_vswing,
-		 "Port %c asks to use VBT vswing/preemph tables\n",
-		 port_name(port));
 }
 
 static void parse_ddi_port(struct intel_bios_encoder_data *devdata)
-- 
2.45.2


^ permalink raw reply related

* [PATCH v9 6/8] drm/i915: override Snps's VS/PE when requested
From: Michał Grzelak @ 2026-06-26 23:42 UTC (permalink / raw)
  To: intel-gfx, intel-xe; +Cc: Jani Nikula, Suraj Kandpal, Michał Grzelak
In-Reply-To: <20260626234246.2446451-1-michal.grzelak@intel.com>

Add accessor function for Snps to read requested table from VBT #57.
Parse the requested table and transform data into port's buffer.

Choose appropriate accessor function in intel_ddi_buf_trans_get() based
on display version and PHY type.

For C20, use 6th table if encoder supports DP 2.0 or higher. Otherwise
use 5th table for DP.

For C20, tables 1-4 are not used at all and are most likely to be
zeroed. 5th table is used for any mode below DP 2.0 (exclusive). 6th
table is used for any mode above DP 2.0 (inclusive).

For C10, use 2nd table for external DP if encoder supports any mode
beyond or including HBR2. Use 1st table if external DP encoder supports
anything lower than HBR2. For eDP, use 4th table if encoder supports
HBR3. Otherwise use 3rd table for eDP.

For C10, 1st table is used for external DP with modes below HBR2
(exclusive). 1st table is also used as a fallback for non-DPs. 2nd
table is used for external DP with modes higher than HBR2 (inclusive).
3rd table is used for eDP with modes lower than HBR3 (exclusive). 4th
table is used for eDP with modes higher than HBR3 (inclusive).

Indices for other tables have not yet been observed to be used as of
now.

There are no changes to intel_ddi_dp_level() since selection of correct
row of intel_ddi_buf_trans_entry is same as when no override request has
been done.

v8->v9
- init vspeo before using it
- deconstify intel_ddi_buf_trans_entry

v7->v8
- remove comments (Suraj)
- add check for LT (Suraj)

v6->v7
- handle VS/PE-O's VBT details in intel_bios_* functions (Jani)
- remove vspeo's cast to (void *) (Jani)
- check devdata->vspeo if VS/PE-O was requested
- call encoder->get_buf_trans() once (Jani)
- return NULL from intel_bios_get_* when using default (Jani)
- validate VS/PE-O in intel_bios.c (Jani)
- inline mtl_{c10,c20}_get_vspeo_buf_trans()
- remove temporarily LT

v4->v5
- blend index computation with table parsing
- remove enums entirely
- change funcs prefix from snps_ to mtl_ (Suraj)
- add spaces around operators (Suraj)
- remove spaces after type casting (Suraj)
- remove INTEL_DISPLAY_STATE_WARN (Suraj)

v3->v4
- stick to solely changing VBT data into current structures (Jani)
- move iterator declaration to declaration block (Suraj)

v2->v3
- remove unnecessary braces from if block (Suraj)
- return -EINVAL instead of -1 (Suraj)

Signed-off-by: Michał Grzelak <michal.grzelak@intel.com>
Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com> # v7
---
 drivers/gpu/drm/i915/display/intel_bios.c     | 99 +++++++++++++++++++
 drivers/gpu/drm/i915/display/intel_bios.h     |  7 ++
 .../drm/i915/display/intel_ddi_buf_trans.c    | 21 ++++
 3 files changed, 127 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 83cc0b388ed3d..0da87ff9a905a 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -3861,6 +3861,105 @@ bool intel_bios_encoder_supports_tbt(const struct intel_bios_encoder_data *devda
 	return devdata->display->vbt.version >= 209 && devdata->child.tbt;
 }
 
+static bool
+validate_vspeo(const struct intel_bios_encoder_data *devdata, bool has_dp)
+{
+	struct intel_ddi_buf_trans *vspeo;
+
+	if (!devdata)
+		return false;
+
+	vspeo = devdata->vspeo;
+	if (!vspeo)
+		return false;
+
+	if (!has_dp)
+		return false;
+
+	return true;
+}
+
+const struct intel_ddi_buf_trans *
+intel_bios_get_c20_vspeo(const struct intel_bios_encoder_data *devdata,
+			 bool has_dp, bool is_uhbr)
+{
+	struct intel_display *display;
+	union intel_ddi_buf_trans_entry *entries;
+	int num_columns, num_rows, level, idx;
+	struct intel_ddi_buf_trans *vspeo;
+	const u32 *tables;
+	size_t offset = 0;
+
+	if (!validate_vspeo(devdata, has_dp))
+		return NULL;
+
+	display = devdata->display;
+	vspeo = devdata->vspeo;
+	entries = vspeo->entries;
+	tables = display->vbt.vspeo.tables;
+	num_columns = display->vbt.vspeo.num_columns;
+	num_rows = display->vbt.vspeo.num_rows;
+	idx = is_uhbr ? 5 : 4;
+
+	offset += idx * num_rows * num_columns;
+
+	for (level = 0; level < num_rows; level++) {
+		u32 vswing = tables[offset];
+		u32 pre_cursor = tables[offset + 1];
+		u32 post_cursor = tables[offset + 2];
+
+		entries[level].snps.vswing = vswing;
+		entries[level].snps.pre_cursor = pre_cursor;
+		entries[level].snps.post_cursor = post_cursor;
+
+		offset += num_columns;
+	}
+
+	return vspeo;
+}
+
+const struct intel_ddi_buf_trans *
+intel_bios_get_c10_vspeo(const struct intel_bios_encoder_data *devdata,
+			 bool has_dp, int port_clock, bool has_edp)
+{
+	struct intel_display *display;
+	union intel_ddi_buf_trans_entry *entries;
+	int num_columns, num_rows, level, idx;
+	struct intel_ddi_buf_trans *vspeo;
+	const u32 *tables;
+	size_t offset = 0;
+
+	if (!validate_vspeo(devdata, has_dp))
+		return NULL;
+
+	display = devdata->display;
+	vspeo = devdata->vspeo;
+	entries = vspeo->entries;
+	tables = display->vbt.vspeo.tables;
+	num_columns = display->vbt.vspeo.num_columns;
+	num_rows = display->vbt.vspeo.num_rows;
+
+	idx = port_clock > 270000 ? 1 : 0;
+	if (has_edp)
+		idx = port_clock > 540000 ? 3 : 2;
+
+	offset += idx * num_rows * num_columns;
+
+	for (level = 0; level < num_rows; level++) {
+		u32 vswing = tables[offset];
+		u32 pre_cursor = tables[offset + 1];
+		u32 post_cursor = tables[offset + 2];
+
+		entries[level].snps.vswing = vswing;
+		entries[level].snps.pre_cursor = pre_cursor;
+		entries[level].snps.post_cursor = post_cursor;
+
+		offset += num_columns;
+	}
+
+	return vspeo;
+}
+
 bool intel_bios_encoder_is_dedicated_external(const struct intel_bios_encoder_data *devdata)
 {
 	return devdata->display->vbt.version >= 264 &&
diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h
index 7a50a272cd27d..49acf8c405e2b 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.h
+++ b/drivers/gpu/drm/i915/display/intel_bios.h
@@ -73,6 +73,13 @@ bool intel_bios_get_dsc_params(struct intel_encoder *encoder,
 const struct intel_bios_encoder_data *
 intel_bios_encoder_data_lookup(struct intel_display *display, enum port port);
 
+const struct intel_ddi_buf_trans *
+intel_bios_get_c20_vspeo(const struct intel_bios_encoder_data *devdata,
+			 bool has_dp, bool is_uhbr);
+const struct intel_ddi_buf_trans *
+intel_bios_get_c10_vspeo(const struct intel_bios_encoder_data *devdata,
+			 bool has_dp, int port_clock, bool has_edp);
+
 bool intel_bios_encoder_requests_vspeo(const struct intel_bios_encoder_data *devdata);
 bool intel_bios_encoder_supports_dvi(const struct intel_bios_encoder_data *devdata);
 bool intel_bios_encoder_supports_hdmi(const struct intel_bios_encoder_data *devdata);
diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c
index 2fad9909c78bd..9a294011ea4fa 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c
@@ -1857,5 +1857,26 @@ const struct intel_ddi_buf_trans *intel_ddi_buf_trans_get(struct intel_encoder *
 							  const struct intel_crtc_state *crtc_state,
 							  int *n_entries)
 {
+	struct intel_display *display = to_intel_display(encoder);
+	const struct intel_bios_encoder_data *devdata = encoder->devdata;
+	const struct intel_ddi_buf_trans *buf_trans = NULL;
+	bool has_edp, has_dp, is_uhbr;
+	int port_clock;
+
+	has_edp = intel_crtc_has_type(crtc_state, INTEL_OUTPUT_EDP);
+	has_dp = intel_crtc_has_dp_encoder(crtc_state);
+	is_uhbr = intel_dp_is_uhbr(crtc_state);
+	port_clock = crtc_state->port_clock;
+
+	if (!HAS_LT_PHY(display) && DISPLAY_VER(display) >= 14) {
+		if (intel_encoder_is_c10phy(encoder))
+			buf_trans = intel_bios_get_c10_vspeo(devdata, has_dp, port_clock, has_edp);
+		else
+			buf_trans = intel_bios_get_c20_vspeo(devdata, has_dp, is_uhbr);
+	}
+
+	if (buf_trans)
+		return intel_get_buf_trans(buf_trans, n_entries);
+
 	return encoder->get_buf_trans(encoder, crtc_state, n_entries);
 }
-- 
2.45.2


^ permalink raw reply related

* [PATCH v9 5/8] drm/i915/buf_trans: deconstify intel_ddi_buf_trans_entry
From: Michał Grzelak @ 2026-06-26 23:42 UTC (permalink / raw)
  To: intel-gfx, intel-xe; +Cc: Jani Nikula, Suraj Kandpal, Michał Grzelak
In-Reply-To: <20260626234246.2446451-1-michal.grzelak@intel.com>

Current implementation of Vswing / Pre-emphasis Override allocates
ddi_buf_trans_entry on intel_bios_init() and overwrites it with deparsed
data from VBT#57 on each encoder->get_buf_trans() call. Remove const
qualifier from definition of struct intel_ddi_buf_trans_entry in order
to avoid discarding const qualifier by casting to (void *). Doing so
requires deconstifying DDI tables as well.

Signed-off-by: Michał Grzelak <michal.grzelak@intel.com>
---
 .../drm/i915/display/intel_ddi_buf_trans.c    | 120 +++++++++---------
 .../drm/i915/display/intel_ddi_buf_trans.h    |   2 +-
 2 files changed, 61 insertions(+), 61 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c
index 4cd1e4d76c7af..2fad9909c78bd 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c
+++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.c
@@ -16,7 +16,7 @@
  * them for both DP and FDI transports, allowing those ports to
  * automatically adapt to HDMI connections as well
  */
-static const union intel_ddi_buf_trans_entry _hsw_trans_dp[] = {
+static union intel_ddi_buf_trans_entry _hsw_trans_dp[] = {
 	{ .hsw = { 0x00FFFFFF, 0x0006000E, 0x0 } },
 	{ .hsw = { 0x00D75FFF, 0x0005000A, 0x0 } },
 	{ .hsw = { 0x00C30FFF, 0x00040006, 0x0 } },
@@ -33,7 +33,7 @@ static const struct intel_ddi_buf_trans hsw_trans_dp = {
 	.num_entries = ARRAY_SIZE(_hsw_trans_dp),
 };
 
-static const union intel_ddi_buf_trans_entry _hsw_trans_fdi[] = {
+static union intel_ddi_buf_trans_entry _hsw_trans_fdi[] = {
 	{ .hsw = { 0x00FFFFFF, 0x0007000E, 0x0 } },
 	{ .hsw = { 0x00D75FFF, 0x000F000A, 0x0 } },
 	{ .hsw = { 0x00C30FFF, 0x00060006, 0x0 } },
@@ -50,7 +50,7 @@ static const struct intel_ddi_buf_trans hsw_trans_fdi = {
 	.num_entries = ARRAY_SIZE(_hsw_trans_fdi),
 };
 
-static const union intel_ddi_buf_trans_entry _hsw_trans_hdmi[] = {
+static union intel_ddi_buf_trans_entry _hsw_trans_hdmi[] = {
 							/* Idx	NT mV d	T mV d	db	*/
 	{ .hsw = { 0x00FFFFFF, 0x0006000E, 0x0 } },	/* 0:	400	400	0	*/
 	{ .hsw = { 0x00E79FFF, 0x000E000C, 0x0 } },	/* 1:	400	500	2	*/
@@ -72,7 +72,7 @@ static const struct intel_ddi_buf_trans hsw_trans_hdmi = {
 	.hdmi_default_entry = 6,
 };
 
-static const union intel_ddi_buf_trans_entry _bdw_trans_edp[] = {
+static union intel_ddi_buf_trans_entry _bdw_trans_edp[] = {
 	{ .hsw = { 0x00FFFFFF, 0x00000012, 0x0 } },
 	{ .hsw = { 0x00EBAFFF, 0x00020011, 0x0 } },
 	{ .hsw = { 0x00C71FFF, 0x0006000F, 0x0 } },
@@ -89,7 +89,7 @@ static const struct intel_ddi_buf_trans bdw_trans_edp = {
 	.num_entries = ARRAY_SIZE(_bdw_trans_edp),
 };
 
-static const union intel_ddi_buf_trans_entry _bdw_trans_dp[] = {
+static union intel_ddi_buf_trans_entry _bdw_trans_dp[] = {
 	{ .hsw = { 0x00FFFFFF, 0x0007000E, 0x0 } },
 	{ .hsw = { 0x00D75FFF, 0x000E000A, 0x0 } },
 	{ .hsw = { 0x00BEFFFF, 0x00140006, 0x0 } },
@@ -106,7 +106,7 @@ static const struct intel_ddi_buf_trans bdw_trans_dp = {
 	.num_entries = ARRAY_SIZE(_bdw_trans_dp),
 };
 
-static const union intel_ddi_buf_trans_entry _bdw_trans_fdi[] = {
+static union intel_ddi_buf_trans_entry _bdw_trans_fdi[] = {
 	{ .hsw = { 0x00FFFFFF, 0x0001000E, 0x0 } },
 	{ .hsw = { 0x00D75FFF, 0x0004000A, 0x0 } },
 	{ .hsw = { 0x00C30FFF, 0x00070006, 0x0 } },
@@ -123,7 +123,7 @@ static const struct intel_ddi_buf_trans bdw_trans_fdi = {
 	.num_entries = ARRAY_SIZE(_bdw_trans_fdi),
 };
 
-static const union intel_ddi_buf_trans_entry _bdw_trans_hdmi[] = {
+static union intel_ddi_buf_trans_entry _bdw_trans_hdmi[] = {
 							/* Idx	NT mV d	T mV df	db	*/
 	{ .hsw = { 0x00FFFFFF, 0x0007000E, 0x0 } },	/* 0:	400	400	0	*/
 	{ .hsw = { 0x00D75FFF, 0x000E000A, 0x0 } },	/* 1:	400	600	3.5	*/
@@ -144,7 +144,7 @@ static const struct intel_ddi_buf_trans bdw_trans_hdmi = {
 };
 
 /* Skylake H and S */
-static const union intel_ddi_buf_trans_entry _skl_trans_dp[] = {
+static union intel_ddi_buf_trans_entry _skl_trans_dp[] = {
 	{ .hsw = { 0x00002016, 0x000000A0, 0x0 } },
 	{ .hsw = { 0x00005012, 0x0000009B, 0x0 } },
 	{ .hsw = { 0x00007011, 0x00000088, 0x0 } },
@@ -162,7 +162,7 @@ static const struct intel_ddi_buf_trans skl_trans_dp = {
 };
 
 /* Skylake U */
-static const union intel_ddi_buf_trans_entry _skl_u_trans_dp[] = {
+static union intel_ddi_buf_trans_entry _skl_u_trans_dp[] = {
 	{ .hsw = { 0x0000201B, 0x000000A2, 0x0 } },
 	{ .hsw = { 0x00005012, 0x00000088, 0x0 } },
 	{ .hsw = { 0x80007011, 0x000000CD, 0x1 } },
@@ -180,7 +180,7 @@ static const struct intel_ddi_buf_trans skl_u_trans_dp = {
 };
 
 /* Skylake Y */
-static const union intel_ddi_buf_trans_entry _skl_y_trans_dp[] = {
+static union intel_ddi_buf_trans_entry _skl_y_trans_dp[] = {
 	{ .hsw = { 0x00000018, 0x000000A2, 0x0 } },
 	{ .hsw = { 0x00005012, 0x00000088, 0x0 } },
 	{ .hsw = { 0x80007011, 0x000000CD, 0x3 } },
@@ -198,7 +198,7 @@ static const struct intel_ddi_buf_trans skl_y_trans_dp = {
 };
 
 /* Kabylake H and S */
-static const union intel_ddi_buf_trans_entry _kbl_trans_dp[] = {
+static union intel_ddi_buf_trans_entry _kbl_trans_dp[] = {
 	{ .hsw = { 0x00002016, 0x000000A0, 0x0 } },
 	{ .hsw = { 0x00005012, 0x0000009B, 0x0 } },
 	{ .hsw = { 0x00007011, 0x00000088, 0x0 } },
@@ -216,7 +216,7 @@ static const struct intel_ddi_buf_trans kbl_trans_dp = {
 };
 
 /* Kabylake U */
-static const union intel_ddi_buf_trans_entry _kbl_u_trans_dp[] = {
+static union intel_ddi_buf_trans_entry _kbl_u_trans_dp[] = {
 	{ .hsw = { 0x0000201B, 0x000000A1, 0x0 } },
 	{ .hsw = { 0x00005012, 0x00000088, 0x0 } },
 	{ .hsw = { 0x80007011, 0x000000CD, 0x3 } },
@@ -234,7 +234,7 @@ static const struct intel_ddi_buf_trans kbl_u_trans_dp = {
 };
 
 /* Kabylake Y */
-static const union intel_ddi_buf_trans_entry _kbl_y_trans_dp[] = {
+static union intel_ddi_buf_trans_entry _kbl_y_trans_dp[] = {
 	{ .hsw = { 0x00001017, 0x000000A1, 0x0 } },
 	{ .hsw = { 0x00005012, 0x00000088, 0x0 } },
 	{ .hsw = { 0x80007011, 0x000000CD, 0x3 } },
@@ -255,7 +255,7 @@ static const struct intel_ddi_buf_trans kbl_y_trans_dp = {
  * Skylake/Kabylake H and S
  * eDP 1.4 low vswing translation parameters
  */
-static const union intel_ddi_buf_trans_entry _skl_trans_edp[] = {
+static union intel_ddi_buf_trans_entry _skl_trans_edp[] = {
 	{ .hsw = { 0x00000018, 0x000000A8, 0x0 } },
 	{ .hsw = { 0x00004013, 0x000000A9, 0x0 } },
 	{ .hsw = { 0x00007011, 0x000000A2, 0x0 } },
@@ -277,7 +277,7 @@ static const struct intel_ddi_buf_trans skl_trans_edp = {
  * Skylake/Kabylake U
  * eDP 1.4 low vswing translation parameters
  */
-static const union intel_ddi_buf_trans_entry _skl_u_trans_edp[] = {
+static union intel_ddi_buf_trans_entry _skl_u_trans_edp[] = {
 	{ .hsw = { 0x00000018, 0x000000A8, 0x0 } },
 	{ .hsw = { 0x00004013, 0x000000A9, 0x0 } },
 	{ .hsw = { 0x00007011, 0x000000A2, 0x0 } },
@@ -299,7 +299,7 @@ static const struct intel_ddi_buf_trans skl_u_trans_edp = {
  * Skylake/Kabylake Y
  * eDP 1.4 low vswing translation parameters
  */
-static const union intel_ddi_buf_trans_entry _skl_y_trans_edp[] = {
+static union intel_ddi_buf_trans_entry _skl_y_trans_edp[] = {
 	{ .hsw = { 0x00000018, 0x000000A8, 0x0 } },
 	{ .hsw = { 0x00004013, 0x000000AB, 0x0 } },
 	{ .hsw = { 0x00007011, 0x000000A4, 0x0 } },
@@ -318,7 +318,7 @@ static const struct intel_ddi_buf_trans skl_y_trans_edp = {
 };
 
 /* Skylake/Kabylake U, H and S */
-static const union intel_ddi_buf_trans_entry _skl_trans_hdmi[] = {
+static union intel_ddi_buf_trans_entry _skl_trans_hdmi[] = {
 	{ .hsw = { 0x00000018, 0x000000AC, 0x0 } },
 	{ .hsw = { 0x00005012, 0x0000009D, 0x0 } },
 	{ .hsw = { 0x00007011, 0x00000088, 0x0 } },
@@ -339,7 +339,7 @@ static const struct intel_ddi_buf_trans skl_trans_hdmi = {
 };
 
 /* Skylake/Kabylake Y */
-static const union intel_ddi_buf_trans_entry _skl_y_trans_hdmi[] = {
+static union intel_ddi_buf_trans_entry _skl_y_trans_hdmi[] = {
 	{ .hsw = { 0x00000018, 0x000000A1, 0x0 } },
 	{ .hsw = { 0x00005012, 0x000000DF, 0x0 } },
 	{ .hsw = { 0x80007011, 0x000000CB, 0x3 } },
@@ -359,7 +359,7 @@ static const struct intel_ddi_buf_trans skl_y_trans_hdmi = {
 	.hdmi_default_entry = 8,
 };
 
-static const union intel_ddi_buf_trans_entry _bxt_trans_dp[] = {
+static union intel_ddi_buf_trans_entry _bxt_trans_dp[] = {
 						/* Idx	NT mV diff	db  */
 	{ .bxt = { 52,  0x9A, 0, 128, } },	/* 0:	400		0   */
 	{ .bxt = { 78,  0x9A, 0, 85,  } },	/* 1:	400		3.5 */
@@ -378,7 +378,7 @@ static const struct intel_ddi_buf_trans bxt_trans_dp = {
 	.num_entries = ARRAY_SIZE(_bxt_trans_dp),
 };
 
-static const union intel_ddi_buf_trans_entry _bxt_trans_edp[] = {
+static union intel_ddi_buf_trans_entry _bxt_trans_edp[] = {
 					/* Idx	NT mV diff	db  */
 	{ .bxt = { 26, 0, 0, 128, } },	/* 0:	200		0   */
 	{ .bxt = { 38, 0, 0, 112, } },	/* 1:	200		1.5 */
@@ -400,7 +400,7 @@ static const struct intel_ddi_buf_trans bxt_trans_edp = {
 /* BSpec has 2 recommended values - entries 0 and 8.
  * Using the entry with higher vswing.
  */
-static const union intel_ddi_buf_trans_entry _bxt_trans_hdmi[] = {
+static union intel_ddi_buf_trans_entry _bxt_trans_hdmi[] = {
 						/* Idx	NT mV diff	db  */
 	{ .bxt = { 52,  0x9A, 0, 128, } },	/* 0:	400		0   */
 	{ .bxt = { 52,  0x9A, 0, 85,  } },	/* 1:	400		3.5 */
@@ -421,7 +421,7 @@ static const struct intel_ddi_buf_trans bxt_trans_hdmi = {
 };
 
 /* icl_combo_phy_trans */
-static const union intel_ddi_buf_trans_entry _icl_combo_phy_trans_dp_hbr2_edp_hbr3[] = {
+static union intel_ddi_buf_trans_entry _icl_combo_phy_trans_dp_hbr2_edp_hbr3[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } },	/* 350   500      3.1   */
@@ -440,7 +440,7 @@ static const struct intel_ddi_buf_trans icl_combo_phy_trans_dp_hbr2_edp_hbr3 = {
 	.num_entries = ARRAY_SIZE(_icl_combo_phy_trans_dp_hbr2_edp_hbr3),
 };
 
-static const union intel_ddi_buf_trans_entry _icl_combo_phy_trans_edp_hbr2[] = {
+static union intel_ddi_buf_trans_entry _icl_combo_phy_trans_edp_hbr2[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0x0, 0x7F, 0x3F, 0x00, 0x00 } },	/* 200   200      0.0   */
 	{ .icl = { 0x8, 0x7F, 0x38, 0x00, 0x07 } },	/* 200   250      1.9   */
@@ -459,7 +459,7 @@ static const struct intel_ddi_buf_trans icl_combo_phy_trans_edp_hbr2 = {
 	.num_entries = ARRAY_SIZE(_icl_combo_phy_trans_edp_hbr2),
 };
 
-static const union intel_ddi_buf_trans_entry _icl_combo_phy_trans_hdmi[] = {
+static union intel_ddi_buf_trans_entry _icl_combo_phy_trans_hdmi[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x60, 0x3F, 0x00, 0x00 } },	/* 450   450      0.0   */
 	{ .icl = { 0xB, 0x73, 0x36, 0x00, 0x09 } },	/* 450   650      3.2   */
@@ -476,7 +476,7 @@ static const struct intel_ddi_buf_trans icl_combo_phy_trans_hdmi = {
 	.hdmi_default_entry = ARRAY_SIZE(_icl_combo_phy_trans_hdmi) - 1,
 };
 
-static const union intel_ddi_buf_trans_entry _ehl_combo_phy_trans_dp[] = {
+static union intel_ddi_buf_trans_entry _ehl_combo_phy_trans_dp[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x33, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x47, 0x38, 0x00, 0x07 } },	/* 350   500      3.1   */
@@ -495,7 +495,7 @@ static const struct intel_ddi_buf_trans ehl_combo_phy_trans_dp = {
 	.num_entries = ARRAY_SIZE(_ehl_combo_phy_trans_dp),
 };
 
-static const union intel_ddi_buf_trans_entry _ehl_combo_phy_trans_edp_hbr2[] = {
+static union intel_ddi_buf_trans_entry _ehl_combo_phy_trans_edp_hbr2[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0x8, 0x7F, 0x3F, 0x00, 0x00 } },	/* 200   200      0.0   */
 	{ .icl = { 0x8, 0x7F, 0x3F, 0x00, 0x00 } },	/* 200   250      1.9   */
@@ -514,7 +514,7 @@ static const struct intel_ddi_buf_trans ehl_combo_phy_trans_edp_hbr2 = {
 	.num_entries = ARRAY_SIZE(_ehl_combo_phy_trans_edp_hbr2),
 };
 
-static const union intel_ddi_buf_trans_entry _jsl_combo_phy_trans_edp_hbr[] = {
+static union intel_ddi_buf_trans_entry _jsl_combo_phy_trans_edp_hbr[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0x8, 0x7F, 0x3F, 0x00, 0x00 } },	/* 200   200      0.0   */
 	{ .icl = { 0x8, 0x7F, 0x38, 0x00, 0x07 } },	/* 200   250      1.9   */
@@ -533,7 +533,7 @@ static const struct intel_ddi_buf_trans jsl_combo_phy_trans_edp_hbr = {
 	.num_entries = ARRAY_SIZE(_jsl_combo_phy_trans_edp_hbr),
 };
 
-static const union intel_ddi_buf_trans_entry _jsl_combo_phy_trans_edp_hbr2[] = {
+static union intel_ddi_buf_trans_entry _jsl_combo_phy_trans_edp_hbr2[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0x8, 0x7F, 0x3F, 0x00, 0x00 } },	/* 200   200      0.0   */
 	{ .icl = { 0x8, 0x7F, 0x3F, 0x00, 0x00 } },	/* 200   250      1.9   */
@@ -552,7 +552,7 @@ static const struct intel_ddi_buf_trans jsl_combo_phy_trans_edp_hbr2 = {
 	.num_entries = ARRAY_SIZE(_jsl_combo_phy_trans_edp_hbr2),
 };
 
-static const union intel_ddi_buf_trans_entry _dg1_combo_phy_trans_dp_rbr_hbr[] = {
+static union intel_ddi_buf_trans_entry _dg1_combo_phy_trans_dp_rbr_hbr[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x32, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x48, 0x35, 0x00, 0x0A } },	/* 350   500      3.1   */
@@ -571,7 +571,7 @@ static const struct intel_ddi_buf_trans dg1_combo_phy_trans_dp_rbr_hbr = {
 	.num_entries = ARRAY_SIZE(_dg1_combo_phy_trans_dp_rbr_hbr),
 };
 
-static const union intel_ddi_buf_trans_entry _dg1_combo_phy_trans_dp_hbr2_hbr3[] = {
+static union intel_ddi_buf_trans_entry _dg1_combo_phy_trans_dp_hbr2_hbr3[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x32, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x48, 0x35, 0x00, 0x0A } },	/* 350   500      3.1   */
@@ -590,7 +590,7 @@ static const struct intel_ddi_buf_trans dg1_combo_phy_trans_dp_hbr2_hbr3 = {
 	.num_entries = ARRAY_SIZE(_dg1_combo_phy_trans_dp_hbr2_hbr3),
 };
 
-static const union intel_ddi_buf_trans_entry _icl_mg_phy_trans_rbr_hbr[] = {
+static union intel_ddi_buf_trans_entry _icl_mg_phy_trans_rbr_hbr[] = {
 					/* Voltage swing  pre-emphasis */
 	{ .mg = { 0x18, 0x00, 0x00 } },	/* 0              0   */
 	{ .mg = { 0x1D, 0x00, 0x05 } },	/* 0              1   */
@@ -609,7 +609,7 @@ static const struct intel_ddi_buf_trans icl_mg_phy_trans_rbr_hbr = {
 	.num_entries = ARRAY_SIZE(_icl_mg_phy_trans_rbr_hbr),
 };
 
-static const union intel_ddi_buf_trans_entry _icl_mg_phy_trans_hbr2_hbr3[] = {
+static union intel_ddi_buf_trans_entry _icl_mg_phy_trans_hbr2_hbr3[] = {
 					/* Voltage swing  pre-emphasis */
 	{ .mg = { 0x18, 0x00, 0x00 } },	/* 0              0   */
 	{ .mg = { 0x1D, 0x00, 0x05 } },	/* 0              1   */
@@ -628,7 +628,7 @@ static const struct intel_ddi_buf_trans icl_mg_phy_trans_hbr2_hbr3 = {
 	.num_entries = ARRAY_SIZE(_icl_mg_phy_trans_hbr2_hbr3),
 };
 
-static const union intel_ddi_buf_trans_entry _icl_mg_phy_trans_hdmi[] = {
+static union intel_ddi_buf_trans_entry _icl_mg_phy_trans_hdmi[] = {
 					/* HDMI Preset	VS	Pre-emph */
 	{ .mg = { 0x1A, 0x0, 0x0 } },	/* 1		400mV	0dB */
 	{ .mg = { 0x20, 0x0, 0x0 } },	/* 2		500mV	0dB */
@@ -648,7 +648,7 @@ static const struct intel_ddi_buf_trans icl_mg_phy_trans_hdmi = {
 	.hdmi_default_entry = ARRAY_SIZE(_icl_mg_phy_trans_hdmi) - 1,
 };
 
-static const union intel_ddi_buf_trans_entry _tgl_dkl_phy_trans_dp_hbr[] = {
+static union intel_ddi_buf_trans_entry _tgl_dkl_phy_trans_dp_hbr[] = {
 					/* VS	pre-emp	Non-trans mV	Pre-emph dB */
 	{ .dkl = { 0x7, 0x0, 0x00 } },	/* 0	0	400mV		0 dB */
 	{ .dkl = { 0x5, 0x0, 0x05 } },	/* 0	1	400mV		3.5 dB */
@@ -667,7 +667,7 @@ static const struct intel_ddi_buf_trans tgl_dkl_phy_trans_dp_hbr = {
 	.num_entries = ARRAY_SIZE(_tgl_dkl_phy_trans_dp_hbr),
 };
 
-static const union intel_ddi_buf_trans_entry _tgl_dkl_phy_trans_dp_hbr2[] = {
+static union intel_ddi_buf_trans_entry _tgl_dkl_phy_trans_dp_hbr2[] = {
 					/* VS	pre-emp	Non-trans mV	Pre-emph dB */
 	{ .dkl = { 0x7, 0x0, 0x00 } },	/* 0	0	400mV		0 dB */
 	{ .dkl = { 0x5, 0x0, 0x05 } },	/* 0	1	400mV		3.5 dB */
@@ -686,7 +686,7 @@ static const struct intel_ddi_buf_trans tgl_dkl_phy_trans_dp_hbr2 = {
 	.num_entries = ARRAY_SIZE(_tgl_dkl_phy_trans_dp_hbr2),
 };
 
-static const union intel_ddi_buf_trans_entry _tgl_dkl_phy_trans_hdmi[] = {
+static union intel_ddi_buf_trans_entry _tgl_dkl_phy_trans_hdmi[] = {
 					/* HDMI Preset	VS	Pre-emph */
 	{ .dkl = { 0x7, 0x0, 0x0 } },	/* 1		400mV	0dB */
 	{ .dkl = { 0x6, 0x0, 0x0 } },	/* 2		500mV	0dB */
@@ -706,7 +706,7 @@ static const struct intel_ddi_buf_trans tgl_dkl_phy_trans_hdmi = {
 	.hdmi_default_entry = ARRAY_SIZE(_tgl_dkl_phy_trans_hdmi) - 1,
 };
 
-static const union intel_ddi_buf_trans_entry _tgl_combo_phy_trans_dp_hbr[] = {
+static union intel_ddi_buf_trans_entry _tgl_combo_phy_trans_dp_hbr[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x32, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } },	/* 350   500      3.1   */
@@ -725,7 +725,7 @@ static const struct intel_ddi_buf_trans tgl_combo_phy_trans_dp_hbr = {
 	.num_entries = ARRAY_SIZE(_tgl_combo_phy_trans_dp_hbr),
 };
 
-static const union intel_ddi_buf_trans_entry _tgl_combo_phy_trans_dp_hbr2[] = {
+static union intel_ddi_buf_trans_entry _tgl_combo_phy_trans_dp_hbr2[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } },	/* 350   500      3.1   */
@@ -744,7 +744,7 @@ static const struct intel_ddi_buf_trans tgl_combo_phy_trans_dp_hbr2 = {
 	.num_entries = ARRAY_SIZE(_tgl_combo_phy_trans_dp_hbr2),
 };
 
-static const union intel_ddi_buf_trans_entry _tgl_uy_combo_phy_trans_dp_hbr2[] = {
+static union intel_ddi_buf_trans_entry _tgl_uy_combo_phy_trans_dp_hbr2[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x4F, 0x36, 0x00, 0x09 } },	/* 350   500      3.1   */
@@ -767,7 +767,7 @@ static const struct intel_ddi_buf_trans tgl_uy_combo_phy_trans_dp_hbr2 = {
  * Cloned the HOBL entry to comply with the voltage and pre-emphasis entries
  * that DisplayPort specification requires
  */
-static const union intel_ddi_buf_trans_entry _tgl_combo_phy_trans_edp_hbr2_hobl[] = {
+static union intel_ddi_buf_trans_entry _tgl_combo_phy_trans_edp_hbr2_hobl[] = {
 							/* VS	pre-emp	*/
 	{ .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } },	/* 0	0	*/
 	{ .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } },	/* 0	1	*/
@@ -785,7 +785,7 @@ static const struct intel_ddi_buf_trans tgl_combo_phy_trans_edp_hbr2_hobl = {
 	.num_entries = ARRAY_SIZE(_tgl_combo_phy_trans_edp_hbr2_hobl),
 };
 
-static const union intel_ddi_buf_trans_entry _rkl_combo_phy_trans_dp_hbr[] = {
+static union intel_ddi_buf_trans_entry _rkl_combo_phy_trans_dp_hbr[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x2F, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } },	/* 350   500      3.1   */
@@ -804,7 +804,7 @@ static const struct intel_ddi_buf_trans rkl_combo_phy_trans_dp_hbr = {
 	.num_entries = ARRAY_SIZE(_rkl_combo_phy_trans_dp_hbr),
 };
 
-static const union intel_ddi_buf_trans_entry _rkl_combo_phy_trans_dp_hbr2_hbr3[] = {
+static union intel_ddi_buf_trans_entry _rkl_combo_phy_trans_dp_hbr2_hbr3[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x50, 0x38, 0x00, 0x07 } },	/* 350   500      3.1   */
@@ -823,7 +823,7 @@ static const struct intel_ddi_buf_trans rkl_combo_phy_trans_dp_hbr2_hbr3 = {
 	.num_entries = ARRAY_SIZE(_rkl_combo_phy_trans_dp_hbr2_hbr3),
 };
 
-static const union intel_ddi_buf_trans_entry _adls_combo_phy_trans_dp_hbr2_hbr3[] = {
+static union intel_ddi_buf_trans_entry _adls_combo_phy_trans_dp_hbr2_hbr3[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } },	/* 350   500      3.1   */
@@ -842,7 +842,7 @@ static const struct intel_ddi_buf_trans adls_combo_phy_trans_dp_hbr2_hbr3 = {
 	.num_entries = ARRAY_SIZE(_adls_combo_phy_trans_dp_hbr2_hbr3),
 };
 
-static const union intel_ddi_buf_trans_entry _adls_combo_phy_trans_edp_hbr2[] = {
+static union intel_ddi_buf_trans_entry _adls_combo_phy_trans_edp_hbr2[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0x9, 0x73, 0x3D, 0x00, 0x02 } },	/* 200   200      0.0   */
 	{ .icl = { 0x9, 0x7A, 0x3C, 0x00, 0x03 } },	/* 200   250      1.9   */
@@ -861,7 +861,7 @@ static const struct intel_ddi_buf_trans adls_combo_phy_trans_edp_hbr2 = {
 	.num_entries = ARRAY_SIZE(_adls_combo_phy_trans_edp_hbr2),
 };
 
-static const union intel_ddi_buf_trans_entry _adls_combo_phy_trans_edp_hbr3[] = {
+static union intel_ddi_buf_trans_entry _adls_combo_phy_trans_edp_hbr3[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } },	/* 350   500      3.1   */
@@ -880,7 +880,7 @@ static const struct intel_ddi_buf_trans adls_combo_phy_trans_edp_hbr3 = {
 	.num_entries = ARRAY_SIZE(_adls_combo_phy_trans_edp_hbr3),
 };
 
-static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr[] = {
+static union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } },	/* 350   500      3.1   */
@@ -899,7 +899,7 @@ static const struct intel_ddi_buf_trans adlp_combo_phy_trans_dp_hbr = {
 	.num_entries = ARRAY_SIZE(_adlp_combo_phy_trans_dp_hbr),
 };
 
-static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr2_hbr3[] = {
+static union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr2_hbr3[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } },	/* 350   500      3.1   */
@@ -913,7 +913,7 @@ static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr2_hbr3[
 	{ .icl = { 0x6, 0x7F, 0x3F, 0x00, 0x00 } },	/* 900   900      0.0   */
 };
 
-static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_edp_hbr2[] = {
+static union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_edp_hbr2[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0x4, 0x50, 0x38, 0x00, 0x07 } },	/* 200   200      0.0   */
 	{ .icl = { 0x4, 0x58, 0x35, 0x00, 0x0A } },	/* 200   250      1.9   */
@@ -927,7 +927,7 @@ static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_edp_hbr2[] =
 	{ .icl = { 0x4, 0x7A, 0x38, 0x00, 0x07 } },	/* 350   350      0.0   */
 };
 
-static const union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr2_edp_hbr3[] = {
+static union intel_ddi_buf_trans_entry _adlp_combo_phy_trans_dp_hbr2_edp_hbr3[] = {
 							/* NT mV Trans mV db    */
 	{ .icl = { 0xA, 0x35, 0x3F, 0x00, 0x00 } },	/* 350   350      0.0   */
 	{ .icl = { 0xA, 0x4F, 0x37, 0x00, 0x08 } },	/* 350   500      3.1   */
@@ -956,7 +956,7 @@ static const struct intel_ddi_buf_trans adlp_combo_phy_trans_edp_up_to_hbr2 = {
 	.num_entries = ARRAY_SIZE(_adlp_combo_phy_trans_edp_hbr2),
 };
 
-static const union intel_ddi_buf_trans_entry _adlp_dkl_phy_trans_dp_hbr[] = {
+static union intel_ddi_buf_trans_entry _adlp_dkl_phy_trans_dp_hbr[] = {
 					/* VS	pre-emp	Non-trans mV	Pre-emph dB */
 	{ .dkl = { 0x7, 0x0, 0x01 } },	/* 0	0	400mV		0 dB */
 	{ .dkl = { 0x5, 0x0, 0x06 } },	/* 0	1	400mV		3.5 dB */
@@ -975,7 +975,7 @@ static const struct intel_ddi_buf_trans adlp_dkl_phy_trans_dp_hbr = {
 	.num_entries = ARRAY_SIZE(_adlp_dkl_phy_trans_dp_hbr),
 };
 
-static const union intel_ddi_buf_trans_entry _adlp_dkl_phy_trans_dp_hbr2_hbr3[] = {
+static union intel_ddi_buf_trans_entry _adlp_dkl_phy_trans_dp_hbr2_hbr3[] = {
 					/* VS	pre-emp	Non-trans mV	Pre-emph dB */
 	{ .dkl = { 0x7, 0x0, 0x00 } },	/* 0	0	400mV		0 dB */
 	{ .dkl = { 0x5, 0x0, 0x04 } },	/* 0	1	400mV		3.5 dB */
@@ -994,7 +994,7 @@ static const struct intel_ddi_buf_trans adlp_dkl_phy_trans_dp_hbr2_hbr3 = {
 	.num_entries = ARRAY_SIZE(_adlp_dkl_phy_trans_dp_hbr2_hbr3),
 };
 
-static const union intel_ddi_buf_trans_entry _dg2_snps_trans[] = {
+static union intel_ddi_buf_trans_entry _dg2_snps_trans[] = {
 	{ .snps = { 25, 0, 0 } },	/* VS 0, pre-emph 0 */
 	{ .snps = { 32, 0, 6 } },	/* VS 0, pre-emph 1 */
 	{ .snps = { 35, 0, 10 } },	/* VS 0, pre-emph 2 */
@@ -1013,7 +1013,7 @@ static const struct intel_ddi_buf_trans dg2_snps_trans = {
 	.hdmi_default_entry = ARRAY_SIZE(_dg2_snps_trans) - 1,
 };
 
-static const union intel_ddi_buf_trans_entry _dg2_snps_trans_uhbr[] = {
+static union intel_ddi_buf_trans_entry _dg2_snps_trans_uhbr[] = {
 	{ .snps = { 62, 0, 0 } },	/* preset 0 */
 	{ .snps = { 55, 0, 7 } },	/* preset 1 */
 	{ .snps = { 50, 0, 12 } },	/* preset 2 */
@@ -1037,7 +1037,7 @@ static const struct intel_ddi_buf_trans dg2_snps_trans_uhbr = {
 	.num_entries = ARRAY_SIZE(_dg2_snps_trans_uhbr),
 };
 
-static const union intel_ddi_buf_trans_entry _mtl_c10_trans_dp14[] = {
+static union intel_ddi_buf_trans_entry _mtl_c10_trans_dp14[] = {
 	{ .snps = { 26, 0, 0  } },      /* preset 0 */
 	{ .snps = { 33, 0, 6  } },      /* preset 1 */
 	{ .snps = { 38, 0, 11 } },      /* preset 2 */
@@ -1057,7 +1057,7 @@ static const struct intel_ddi_buf_trans mtl_c10_trans_dp14 = {
 };
 
 /* DP1.4 */
-static const union intel_ddi_buf_trans_entry _mtl_c20_trans_dp14[] = {
+static union intel_ddi_buf_trans_entry _mtl_c20_trans_dp14[] = {
 	{ .snps = { 20, 0, 0  } },      /* preset 0 */
 	{ .snps = { 24, 0, 4  } },      /* preset 1 */
 	{ .snps = { 30, 0, 9  } },      /* preset 2 */
@@ -1071,7 +1071,7 @@ static const union intel_ddi_buf_trans_entry _mtl_c20_trans_dp14[] = {
 };
 
 /* DP2.0 */
-static const union intel_ddi_buf_trans_entry _mtl_c20_trans_uhbr[] = {
+static union intel_ddi_buf_trans_entry _mtl_c20_trans_uhbr[] = {
 	{ .snps = { 48, 0, 0 } },       /* preset 0 */
 	{ .snps = { 43, 0, 5 } },       /* preset 1 */
 	{ .snps = { 40, 0, 8 } },       /* preset 2 */
@@ -1091,7 +1091,7 @@ static const union intel_ddi_buf_trans_entry _mtl_c20_trans_uhbr[] = {
 };
 
 /* HDMI2.0 */
-static const union intel_ddi_buf_trans_entry _mtl_c20_trans_hdmi[] = {
+static union intel_ddi_buf_trans_entry _mtl_c20_trans_hdmi[] = {
 	{ .snps = { 48, 0, 0 } },       /* preset 0 */
 	{ .snps = { 38, 4, 6 } },       /* preset 1 */
 	{ .snps = { 36, 4, 8 } },       /* preset 2 */
@@ -1117,7 +1117,7 @@ static const struct intel_ddi_buf_trans mtl_c20_trans_uhbr = {
 };
 
 /* DP1.4 */
-static const union intel_ddi_buf_trans_entry _xe3plpd_lt_trans_dp14[] = {
+static union intel_ddi_buf_trans_entry _xe3plpd_lt_trans_dp14[] = {
 	{ .lt = { 1, 0, 0, 21, 0  } },
 	{ .lt = { 1, 1, 0, 24, 3  } },
 	{ .lt = { 1, 2, 0, 28, 7  } },
@@ -1131,7 +1131,7 @@ static const union intel_ddi_buf_trans_entry _xe3plpd_lt_trans_dp14[] = {
 };
 
 /* DP2.1 */
-static const union intel_ddi_buf_trans_entry _xe3plpd_lt_trans_uhbr[] = {
+static union intel_ddi_buf_trans_entry _xe3plpd_lt_trans_uhbr[] = {
 	{ .lt = { 0, 0, 0, 48, 0  } },
 	{ .lt = { 0, 0, 0, 43, 5  } },
 	{ .lt = { 0, 0, 0, 40, 8  } },
@@ -1151,7 +1151,7 @@ static const union intel_ddi_buf_trans_entry _xe3plpd_lt_trans_uhbr[] = {
 };
 
 /* eDp */
-static const union intel_ddi_buf_trans_entry _xe3plpd_lt_trans_edp[] = {
+static union intel_ddi_buf_trans_entry _xe3plpd_lt_trans_edp[] = {
 	{ .lt = { 1, 0, 0, 12, 0 } },
 	{ .lt = { 1, 1, 0, 13, 1 } },
 	{ .lt = { 1, 2, 0, 15, 3 } },
diff --git a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h
index 9698697f39177..ca2ae2ac3a44c 100644
--- a/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h
+++ b/drivers/gpu/drm/i915/display/intel_ddi_buf_trans.h
@@ -69,7 +69,7 @@ union intel_ddi_buf_trans_entry {
 };
 
 struct intel_ddi_buf_trans {
-	const union intel_ddi_buf_trans_entry *entries;
+	union intel_ddi_buf_trans_entry *entries;
 	u8 num_entries;
 	u8 hdmi_default_entry;
 };
-- 
2.45.2


^ permalink raw reply related

* [PATCH v9 4/8] drm/i915/bios: de/allocate VS/PE-O buffer for each port
From: Michał Grzelak @ 2026-06-26 23:42 UTC (permalink / raw)
  To: intel-gfx, intel-xe; +Cc: Jani Nikula, Suraj Kandpal, Michał Grzelak
In-Reply-To: <20260626234246.2446451-1-michal.grzelak@intel.com>

Every devdata needs a separate intel_ddi_buf_trans since each port can
request an override. Add buffer's pointer into intel_bios_encoder_data.

Allocate struct intel_ddi_buf_trans for the port if VS/PE-O was
requested and is supported. At the same time, allocate struct
intel_ddi_buf_trans_entry and store it inside struct
intel_ddi_buf_trans. Keep NULL in vspeo if any allocation failed or
VS/PE-O was not requested. It will be used later for checking if
override should actually take place.

Deallocate the buffer as well as entries if requested.

v4->v5
- set devdata->vspeo->num_entries in intel_bios.c

Signed-off-by: Michał Grzelak <michal.grzelak@intel.com>
Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com> # v7
---
 drivers/gpu/drm/i915/display/intel_bios.c | 32 +++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index fed86a2a6553e..83cc0b388ed3d 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -34,6 +34,7 @@
 #include <drm/drm_fixed.h>
 #include <drm/drm_print.h>
 
+#include "intel_ddi_buf_trans.h"
 #include "intel_display.h"
 #include "intel_display_core.h"
 #include "intel_display_rpm.h"
@@ -72,6 +73,7 @@
 struct intel_bios_encoder_data {
 	struct intel_display *display;
 
+	struct intel_ddi_buf_trans *vspeo;
 	struct child_device_config child;
 	struct dsc_compression_parameters_entry *dsc;
 	struct list_head node;
@@ -2628,6 +2630,30 @@ static void sanitize_device_type(struct intel_bios_encoder_data *devdata,
 	devdata->child.device_type |= DEVICE_TYPE_NOT_HDMI_OUTPUT;
 }
 
+static void allocate_vswing_preemph_override(struct intel_bios_encoder_data *devdata)
+{
+	int num_rows = devdata->display->vbt.vspeo.num_rows;
+	union intel_ddi_buf_trans_entry *entries;
+	struct intel_ddi_buf_trans *vspeo;
+
+	if (!intel_bios_encoder_requests_vspeo(devdata))
+		return;
+
+	vspeo = kzalloc_obj(*vspeo);
+	if (!vspeo)
+		return;
+
+	entries = kzalloc_objs(*entries, num_rows);
+	if (!entries) {
+		kfree(vspeo);
+		return;
+	}
+
+	devdata->vspeo = vspeo;
+	devdata->vspeo->entries = entries;
+	devdata->vspeo->num_entries = num_rows;
+}
+
 static void sanitize_hdmi_level_shift(struct intel_bios_encoder_data *devdata,
 				      enum port port)
 {
@@ -2846,6 +2872,7 @@ static void parse_ddi_port(struct intel_bios_encoder_data *devdata)
 	sanitize_dedicated_external(devdata, port);
 	sanitize_device_type(devdata, port);
 	sanitize_hdmi_level_shift(devdata, port);
+	allocate_vswing_preemph_override(devdata);
 }
 
 static bool has_ddi_port_info(struct intel_display *display)
@@ -3383,6 +3410,11 @@ void intel_bios_driver_remove(struct intel_display *display)
 	list_for_each_entry_safe(devdata, nd, &display->vbt.display_devices,
 				 node) {
 		list_del(&devdata->node);
+
+		if (devdata->vspeo)
+			kfree(devdata->vspeo->entries);
+
+		kfree(devdata->vspeo);
 		kfree(devdata->dsc);
 		kfree(devdata);
 	}
-- 
2.45.2


^ permalink raw reply related

* [PATCH v9 3/8] drm/i915/bios: print VS/PE-O port info
From: Michał Grzelak @ 2026-06-26 23:42 UTC (permalink / raw)
  To: intel-gfx, intel-xe; +Cc: Jani Nikula, Suraj Kandpal, Michał Grzelak
In-Reply-To: <20260626234246.2446451-1-michal.grzelak@intel.com>

Issue a debug message when port asks to override default Vswing /
Preemphasis tables.

Add helper intel_bios_encoder_requests_vspeo() to check if port
requests for overriding default VS/PE tables.

v6->v7
- expand VS/PE-O acronym in debug logging (Jani)

v3->v4
- change debug message when requesting VS/PE-O (Suraj)

Signed-off-by: Michał Grzelak <michal.grzelak@intel.com>
Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com> # v4
---
 drivers/gpu/drm/i915/display/intel_bios.c | 10 ++++++++++
 drivers/gpu/drm/i915/display/intel_bios.h |  1 +
 2 files changed, 11 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 31f401bcb82ef..fed86a2a6553e 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -2781,6 +2781,11 @@ static void print_ddi_port(const struct intel_bios_encoder_data *devdata)
 			    "Port %c supports dynamic DDI allocation in TCSS\n",
 			    port_name(port));
 
+	if (intel_bios_encoder_requests_vspeo(devdata))
+		drm_dbg_kms(display->drm,
+			    "Port %c requests vswing/pre-emphasis override\n",
+			    port_name(port));
+
 	hdmi_level_shift = intel_bios_hdmi_level_shift(devdata);
 	if (hdmi_level_shift >= 0) {
 		drm_dbg_kms(display->drm,
@@ -3809,6 +3814,11 @@ int intel_bios_hdmi_ddc_pin(const struct intel_bios_encoder_data *devdata)
 	return map_ddc_pin(devdata->display, devdata->child.ddc_pin);
 }
 
+bool intel_bios_encoder_requests_vspeo(const struct intel_bios_encoder_data *devdata)
+{
+	return devdata->display->vbt.version >= 218 && devdata->child.use_vbt_vswing;
+}
+
 bool intel_bios_encoder_supports_typec_usb(const struct intel_bios_encoder_data *devdata)
 {
 	return devdata->display->vbt.version >= 195 && devdata->child.dp_usb_type_c;
diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h
index 75dff27b42289..7a50a272cd27d 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.h
+++ b/drivers/gpu/drm/i915/display/intel_bios.h
@@ -73,6 +73,7 @@ bool intel_bios_get_dsc_params(struct intel_encoder *encoder,
 const struct intel_bios_encoder_data *
 intel_bios_encoder_data_lookup(struct intel_display *display, enum port port);
 
+bool intel_bios_encoder_requests_vspeo(const struct intel_bios_encoder_data *devdata);
 bool intel_bios_encoder_supports_dvi(const struct intel_bios_encoder_data *devdata);
 bool intel_bios_encoder_supports_hdmi(const struct intel_bios_encoder_data *devdata);
 bool intel_bios_encoder_supports_dp(const struct intel_bios_encoder_data *devdata);
-- 
2.45.2


^ permalink raw reply related

* [PATCH v9 2/8] drm/i915/bios: store VBT #57's metadata in intel_vbt_data
From: Michał Grzelak @ 2026-06-26 23:42 UTC (permalink / raw)
  To: intel-gfx, intel-xe; +Cc: Jani Nikula, Suraj Kandpal, Michał Grzelak
In-Reply-To: <20260626234246.2446451-1-michal.grzelak@intel.com>

Store tables, number of tables, number of rows and number of columns in
intel_vbt_data when search for the VBT #57 has succeeded. Structurize
all VS/PE-O relevant metadata inside anonymous struct named as vspeo.

Presence of C20 or newer PHY causes each table to contain 16 rows. Each
table contains 10 rows in case C20 PHY is absent. Use display version to
determine number of rows since there is no helper in intel_bios.c to
check presence of any C20+ PHY. pre-MTL platforms should have 10 rows
while MTL+ should have 16 rows.

v5->v6
- add Bspec (Suraj)

v3->v4
- remove unnecessary init of VS/PE-O metadata (Suraj)
- add helper for computing number of rows (Suraj)
- fix num_rows's type (Jani, Suraj)
- declare num_rows (Suraj)

Bspec: 68963
Signed-off-by: Michał Grzelak <michal.grzelak@intel.com>
Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com> # v7
---
 drivers/gpu/drm/i915/display/intel_bios.c         | 10 ++++++++++
 drivers/gpu/drm/i915/display/intel_display_core.h |  7 +++++++
 2 files changed, 17 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 7728e1ffc9044..31f401bcb82ef 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -2185,6 +2185,11 @@ parse_compression_parameters(struct intel_display *display)
 	}
 }
 
+static int vswing_preemph_num_rows(struct intel_display *display)
+{
+	return DISPLAY_VER(display) >= 14 ? 16 : 10;
+}
+
 static void
 parse_vswing_preemph_override(struct intel_display *display)
 {
@@ -2198,6 +2203,11 @@ parse_vswing_preemph_override(struct intel_display *display)
 	/* pre-ICL GOPs don't have VBT #57 */
 	if (!block)
 		return;
+
+	display->vbt.vspeo.tables = block->tables;
+	display->vbt.vspeo.num_tables = block->num_tables;
+	display->vbt.vspeo.num_columns = block->num_columns;
+	display->vbt.vspeo.num_rows = vswing_preemph_num_rows(display);
 }
 
 static u8 translate_iboost(struct intel_display *display, u8 val)
diff --git a/drivers/gpu/drm/i915/display/intel_display_core.h b/drivers/gpu/drm/i915/display/intel_display_core.h
index 17f7d3abdb9c5..82754dceb3b84 100644
--- a/drivers/gpu/drm/i915/display/intel_display_core.h
+++ b/drivers/gpu/drm/i915/display/intel_display_core.h
@@ -242,6 +242,13 @@ struct intel_vbt_data {
 	struct list_head display_devices;
 	struct list_head bdb_blocks;
 
+	struct {
+		const u32 *tables;
+		int num_tables;
+		int num_columns;
+		int num_rows;
+	} vspeo;
+
 	struct sdvo_device_mapping {
 		u8 initialized;
 		u8 dvo_port;
-- 
2.45.2


^ permalink raw reply related

* [PATCH v9 1/8] drm/i915/bios: search for VBT #57 by default
From: Michał Grzelak @ 2026-06-26 23:42 UTC (permalink / raw)
  To: intel-gfx, intel-xe; +Cc: Jani Nikula, Suraj Kandpal, Michał Grzelak
In-Reply-To: <20260626234246.2446451-1-michal.grzelak@intel.com>

Start searching for Vswing / Preemphasis Override Block during VBT
parsing at init_bdb_blocks().

Check for failure since pre-ICL GOPs do not contain the block. Check
also if VBT version is appropriately up-to-date.

v6->v7
- parse VBT#57 before blocks dependent on child device list (Jani)
- remove debug message (Suraj)

v3->v4
- add Bspec (Suraj)

Bspec: 32063
Signed-off-by: Michał Grzelak <michal.grzelak@intel.com>
Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com> # v3
---
 drivers/gpu/drm/i915/display/intel_bios.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 15ebadc72b884..7728e1ffc9044 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -200,6 +200,8 @@ static const struct {
 	  .min_size = sizeof(struct bdb_mipi_sequence) },
 	{ .section_id = BDB_COMPRESSION_PARAMETERS,
 	  .min_size = sizeof(struct bdb_compression_parameters), },
+	{ .section_id = BDB_VSWING_PREEMPH,
+	  .min_size = sizeof(struct bdb_vswing_preemph), },
 	{ .section_id = BDB_GENERIC_DTD,
 	  .min_size = sizeof(struct bdb_generic_dtd), },
 };
@@ -2183,6 +2185,21 @@ parse_compression_parameters(struct intel_display *display)
 	}
 }
 
+static void
+parse_vswing_preemph_override(struct intel_display *display)
+{
+	const struct bdb_vswing_preemph *block;
+
+	if (display->vbt.version < 218)
+		return;
+
+	block = bdb_find_section(display, BDB_VSWING_PREEMPH);
+
+	/* pre-ICL GOPs don't have VBT #57 */
+	if (!block)
+		return;
+}
+
 static u8 translate_iboost(struct intel_display *display, u8 val)
 {
 	static const u8 mapping[] = { 1, 3, 7 }; /* See VBT spec */
@@ -3271,6 +3288,7 @@ void intel_bios_init(struct intel_display *display)
 	parse_general_features(display);
 	parse_general_definitions(display);
 	parse_driver_features(display);
+	parse_vswing_preemph_override(display);
 
 	/* Depends on child device list */
 	parse_compression_parameters(display);
-- 
2.45.2


^ permalink raw reply related

* [PATCH v9 0/7] Vswing / Pre-emphasis Override
From: Michał Grzelak @ 2026-06-26 23:42 UTC (permalink / raw)
  To: intel-gfx, intel-xe; +Cc: Jani Nikula, Suraj Kandpal, Michał Grzelak

Next version of [1]. Corresponding IGT v4 is at [2].

This series still has LT disabled.

Loaded custom VBT#57 on PTL. VBT#57 decoded by [2]:

Block 57 min size 2 less than block size 1154
BDB block 57 (1154 bytes, min 2 bytes) - Vswing Preemph:
        Number of vswing tables: 6
        Number of columns: 3
        Number of rows: 16
        PHY type: Cx0
        Vswing Table #1 (C10: DP 1.4 RBR/HBR; C20: UNUSED):
                Preset #01: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #02: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #03: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #04: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #05: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #06: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #07: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #08: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #09: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #10: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #11: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #12: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #13: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #14: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #15: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #16: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
        Vswing Table #2 (C10: DP 1.4 HBR2/HBR3; C20: UNUSED):
                Preset #01: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #02: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #03: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #04: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #05: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #06: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #07: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #08: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #09: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #10: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #11: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #12: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #13: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #14: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #15: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #16: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
        Vswing Table #3 (C10: eDP non-HBR3; C20: UNUSED):
                Preset #01: vswing: 0x0000001a, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #02: vswing: 0x00000021, pre-cursor: 0x00000000, post-cursor: 0x00000006
                Preset #03: vswing: 0x00000026, pre-cursor: 0x00000000, post-cursor: 0x0000000b
                Preset #04: vswing: 0x0000002b, pre-cursor: 0x00000000, post-cursor: 0x00000013
                Preset #05: vswing: 0x00000027, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #06: vswing: 0x0000002d, pre-cursor: 0x00000000, post-cursor: 0x00000007
                Preset #07: vswing: 0x0000002e, pre-cursor: 0x00000000, post-cursor: 0x0000000d
                Preset #08: vswing: 0x0000002e, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #09: vswing: 0x00000037, pre-cursor: 0x00000000, post-cursor: 0x00000007
                Preset #10: vswing: 0x0000003e, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #11: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #12: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #13: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #14: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #15: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #16: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
        Vswing Table #4 (C10: eDP HBR3; C20: UNUSED):
                Preset #01: vswing: 0x0000001a, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #02: vswing: 0x00000021, pre-cursor: 0x00000000, post-cursor: 0x00000006
                Preset #03: vswing: 0x00000026, pre-cursor: 0x00000000, post-cursor: 0x0000000b
                Preset #04: vswing: 0x0000002b, pre-cursor: 0x00000000, post-cursor: 0x00000013
                Preset #05: vswing: 0x00000027, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #06: vswing: 0x0000002d, pre-cursor: 0x00000000, post-cursor: 0x00000007
                Preset #07: vswing: 0x0000002e, pre-cursor: 0x00000000, post-cursor: 0x0000000d
                Preset #08: vswing: 0x0000002e, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #09: vswing: 0x00000037, pre-cursor: 0x00000000, post-cursor: 0x00000007
                Preset #10: vswing: 0x0000003e, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #11: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #12: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #13: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #14: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #15: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #16: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
        Vswing Table #5 (C10: UNUSED; C20: DP 1.4):
                Preset #01: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #02: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #03: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #04: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #05: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #06: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #07: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #08: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #09: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #10: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #11: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #12: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #13: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #14: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #15: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #16: vswing: 0x00000000, pre-cursor: 0x00000000, post-cursor: 0x00000000
        Vswing Table #6 (C10: UNUSED; C20: DP 2.X):
                Preset #01: vswing: 0x00000030, pre-cursor: 0x00000000, post-cursor: 0x00000000
                Preset #02: vswing: 0x0000002b, pre-cursor: 0x00000000, post-cursor: 0x00000005
                Preset #03: vswing: 0x00000028, pre-cursor: 0x00000000, post-cursor: 0x00000008
                Preset #04: vswing: 0x00000025, pre-cursor: 0x00000000, post-cursor: 0x0000000b
                Preset #05: vswing: 0x00000021, pre-cursor: 0x00000000, post-cursor: 0x0000000f
                Preset #06: vswing: 0x0000002e, pre-cursor: 0x00000002, post-cursor: 0x00000000
                Preset #07: vswing: 0x0000002a, pre-cursor: 0x00000002, post-cursor: 0x00000004
                Preset #08: vswing: 0x00000026, pre-cursor: 0x00000002, post-cursor: 0x00000008
                Preset #09: vswing: 0x00000023, pre-cursor: 0x00000002, post-cursor: 0x0000000b
                Preset #10: vswing: 0x00000021, pre-cursor: 0x00000002, post-cursor: 0x0000000d
                Preset #11: vswing: 0x0000002c, pre-cursor: 0x00000004, post-cursor: 0x00000000
                Preset #12: vswing: 0x00000028, pre-cursor: 0x00000004, post-cursor: 0x00000004
                Preset #13: vswing: 0x00000025, pre-cursor: 0x00000004, post-cursor: 0x00000007
                Preset #14: vswing: 0x00000021, pre-cursor: 0x00000004, post-cursor: 0x0000000b
                Preset #15: vswing: 0x00000028, pre-cursor: 0x00000008, post-cursor: 0x00000000
                Preset #16: vswing: 0x0000001e, pre-cursor: 0x00000002, post-cursor: 0x00000002

BR,
Michał

[1] https://lore.kernel.org/intel-gfx/20260615181207.1033389-1-michal.grzelak@intel.com/
[2] https://lore.kernel.org/igt-dev/20260616111202.1254067-1-michal.grzelak@intel.com/

---
Changelog:
v8->v9 
- init vspeo before using it
- deconstify intel_ddi_buf_trans_entry in separate commit

v7->v8
- remove comments (Suraj)
- add check for LT (Suraj)

v6->v7
- parse VBT#57 before blocks dependant on child device list (Jani)
- expand VS/PE-O acronym in debug logging (Jani)
- handle VS/PE-O's VBT details in intel_bios_* functions (Jani)
- remove vspeo's cast to (void *) (Jani)
- check devdata->vspeo if VS/PE-O was requested
- call encoder->get_buf_trans() once (Jani)
- return NULL from intel_bios_get_* when using default (Jani)
- validate VS/PE-O in intel_bios.c (Jani)
- inline *_get_vspeo_buf_trans()
- remove temporarily LT

v5->v6
- check if devdata is not NULL
- add Bspec (Suraj)
- remove drm_WARN_ONCE (Suraj)
- pass default VS/PE tables to LT's BIOS accessor (Suraj)
- set txswing & _level from default VS/PE tables (Suraj)
- add helper checking if VS/PE-O has been allocated (Suraj)

v4->v5
- set devdata->vspeo->num_entries in intel_bios.c
- add if-ladder instead of function pointer
- blend index computation with table parsing
- remove WARN and debug messages
- remove enums entirely
- add spaces around operators (Suraj)
- remove spaces after type casting (Suraj)
- remove INTEL_DISPLAY_STATE_WARN (Suraj)
- change funcs prefix from snps_ to mtl_ (Suraj)

v3->v4
- add Bspec (Suraj)
- remove unnecessary init of VS/PE-O metadata (Suraj)
- add helper for computing number of rows (Suraj)
- fix num_rows's type (Jani, Suraj)
- declare num_rows (Suraj)
- change debug message when requesting VS/PE-O (Suraj)
- stick to solely changing VBT data into current structures (Jani)
- move iterator declaration to declaration block (Suraj)

v2->v3
- remove unnecessary braces from if block (Suraj)
- return -EINVAL instead of -1 (Suraj)

Michał Grzelak (8):
  drm/i915/bios: search for VBT #57 by default
  drm/i915/bios: store VBT #57's metadata in intel_vbt_data
  drm/i915/bios: print VS/PE-O port info
  drm/i915/bios: de/allocate VS/PE-O buffer for each port
  drm/i915/buf_trans: deconstify intel_ddi_buf_trans_entry
  drm/i915: override Snps's VS/PE when requested
  drm/i915: override Combo's VS/PE when requested
  drm/i915/bios: remove VS/PE-O warning

 drivers/gpu/drm/i915/display/intel_bios.c     | 276 +++++++++++++++++-
 drivers/gpu/drm/i915/display/intel_bios.h     |  14 +
 .../drm/i915/display/intel_ddi_buf_trans.c    | 147 ++++++----
 .../drm/i915/display/intel_ddi_buf_trans.h    |   2 +-
 .../gpu/drm/i915/display/intel_display_core.h |   7 +
 5 files changed, 376 insertions(+), 70 deletions(-)

-- 
2.45.2


^ permalink raw reply

* Re: [PATCH v2 3/4] drm/xe/oa: Provide OA status through status ioctl for mmap interface
From: Dixit, Ashutosh @ 2026-06-26 22:39 UTC (permalink / raw)
  To: Umesh Nerlige Ramappa; +Cc: intel-xe
In-Reply-To: <aj220bc19LXLlsP1@soc-5CG1426VCC.clients.intel.com>

On Thu, 25 Jun 2026 16:16:33 -0700, Umesh Nerlige Ramappa wrote:
>

Hi Umesh,

> On Tue, Jun 16, 2026 at 06:54:21PM -0700, Ashutosh Dixit wrote:
> > When only the OA mmap interface is in use, OA status can be provided
> > through the status ioctl. This enables us to stop whitelisting the OA
> > status register, thereby saving one nonpriv slot per OA unit.
> >
> > Signed-off-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
> > ---
> > drivers/gpu/drm/xe/xe_oa.c       | 7 +++++++
> > drivers/gpu/drm/xe/xe_oa_types.h | 3 +++
> > 2 files changed, 10 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c
> > index 9fbd21b0ef974..985be10855c33 100644
> > --- a/drivers/gpu/drm/xe/xe_oa.c
> > +++ b/drivers/gpu/drm/xe/xe_oa.c
> > @@ -544,6 +544,7 @@ static int __xe_oa_read(struct xe_oa_stream *stream, char __user *buf,
> >	/* Only clear our bits to avoid side-effects */
> >	stream->oa_status = xe_mmio_rmw32(&stream->gt->mmio, __oa_regs(stream)->oa_status,
> >					  OASTATUS_RELEVANT_BITS, 0);
> > +	stream->oa_status_read = true;
> >	/*
> >	 * Signal to userspace that there is non-zero OA status to read via
> >	 * @DRM_XE_OBSERVATION_IOCTL_STATUS observation stream fd ioctl
> > @@ -1603,6 +1604,12 @@ static long xe_oa_status_locked(struct xe_oa_stream *stream, unsigned long arg)
> >	struct drm_xe_oa_stream_status status = {};
> >	void __user *uaddr = (void __user *)arg;
> >
> > +	/* Provide oa_status through the status ioctl, when only mmap() interface is used */
> > +	if (!stream->oa_status_read)
> > +		stream->oa_status = xe_mmio_rmw32(&stream->gt->mmio, __oa_regs(stream)->oa_status,
> > +						  OASTATUS_RELEVANT_BITS, 0);
> > +	stream->oa_status_read = false;
> > +
>
> This is asymmetric especially since we cannot control a user calling mmap
> and read from the same application. I would suggest that we avoid clearing
> the register status bits in _xe_oa_read.  read() will continue to return
> EIO until the status ioctl is called. In the status ioctl, we always read
> the latest value from the HW REG, return that and then clear the register
> bits.

This is the text in xe_drm.h:
"
 * %DRM_XE_OBSERVATION_IOCTL_STATUS observation stream fd ioctl. Userspace can
 * call the ioctl to query stream status in response to EIO errno from
 * observation fd read().
"

So, at least in my mind, calling the status ioctl was always optional
(indicated by "Userspace *can* call") allowing userspace to ignore the EIO
return and still be able to continue. So if we do what you suggest above,
even our own IGT's will need to be fixed, because they can hang, if EIO is
returned continuously.

There is no perfect solution to this problem and that is why I came up with
the scheme in this patch, which to me seems to be good enough and works for
all common use cases.

Thanks.
--
Ashutosh

> >	/* Map from register to uapi bits */
> >	if (stream->oa_status & OASTATUS_REPORT_LOST)
> >		status.oa_status |= DRM_XE_OASTATUS_REPORT_LOST;
> > diff --git a/drivers/gpu/drm/xe/xe_oa_types.h b/drivers/gpu/drm/xe/xe_oa_types.h
> > index 3d9ec8490899c..a84456540a13c 100644
> > --- a/drivers/gpu/drm/xe/xe_oa_types.h
> > +++ b/drivers/gpu/drm/xe/xe_oa_types.h
> > @@ -244,6 +244,9 @@ struct xe_oa_stream {
> >	/** @oa_status: temporary storage for oa_status register value */
> >	u32 oa_status;
> >
> > +	/** @oa_status_read: true when read() interface is used to read oa_status */
> > +	bool oa_status_read;
> > +
> >	/** @no_preempt: Whether preemption and timeslicing is disabled for stream exec_q */
> >	u32 no_preempt;
> >
> > --
> > 2.54.0
> >

^ permalink raw reply

* [PATCH v3] drm/xe/tests/rtp: Add kunit test for whitelist upper bounds
From: Matt Roper @ 2026-06-26 21:53 UTC (permalink / raw)
  To: intel-xe; +Cc: Gustavo Sousa, Matt Roper

Xe must only add registers to the GT whitelist if they are listed in the
"Software Allowlist" section of the bspec.  These registers have been
carefully reviewed by the architecture/security teams to ensure that
they are safe to whitelist from a security perspective.  The list of
allowed registers changes from platform to platform, and it is not safe
to assume that a register is safe to whitelist on a new platform/IP just
because it was whitelisted on older ones.  This means that whitelist
entries in the driver that used undefined upper bounds
(XE_RTP_END_VERSION_UNDEFINED) for their version ranges should always be
considered illegal since they could potentially open unexpected security
holes on future platforms.  Add a kunit test to scan the whitelist RTP
table and ensure that all entries have well-defined upper bounds on IP
version ranges.

Reviewed-by: Gustavo Sousa <gustavo.sousa@intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
Changes in v3:
- Restructure assertions so that the output on failures will be more
  understandable/useful.  (Gustavo)
- Link to v2: https://lore.kernel.org/r/20260626-kunit_whitelist_bounds-v2-1-223dc3699734@intel.com

Changes in v2:
- Add missing EXPORT_SYMBOL_IF_KUNIT(register_whitelist)
- Link to v1: https://lore.kernel.org/r/20260625-kunit_whitelist_bounds-v1-1-d8f5f055f1f0@intel.com
---
 drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c | 21 +++++++++++++++++++++
 drivers/gpu/drm/xe/xe_reg_whitelist.c         |  5 ++++-
 drivers/gpu/drm/xe/xe_reg_whitelist.h         |  4 ++++
 3 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c
index ef379cbb6a86..7e2fc39ac62c 100644
--- a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c
+++ b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c
@@ -5,6 +5,7 @@
 
 #include <kunit/test.h>
 
+#include "xe_reg_whitelist.h"
 #include "xe_rtp_types.h"
 #include "xe_tuning.h"
 #include "xe_wa.h"
@@ -75,11 +76,31 @@ static void xe_rtp_table_dev_oob_test(struct kunit *test)
 
 RTP_TABLE_PARAM(device_oob_was);
 
+static void xe_rtp_table_missing_upper_bound_test(struct kunit *test)
+{
+	const struct xe_rtp_entry_sr *entry = test->param_value;
+
+	for (int i = 0; i < entry->n_rules; i++) {
+		u8 match_type = entry->rules[i].match_type;
+
+		KUNIT_EXPECT_FALSE(test,
+				   match_type == XE_RTP_MATCH_GRAPHICS_VERSION_RANGE &&
+				   entry->rules[i].ver_end == XE_RTP_END_VERSION_UNDEFINED);
+		KUNIT_EXPECT_FALSE(test,
+				   match_type == XE_RTP_MATCH_MEDIA_VERSION_RANGE &&
+				   entry->rules[i].ver_end == XE_RTP_END_VERSION_UNDEFINED);
+	}
+}
+
+RTP_TABLE_PARAM(register_whitelist);
+
 static struct kunit_case xe_rtp_table_tests[] = {
 	KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_was_gen_params),
 	KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_tunings_gen_params),
 	KUNIT_CASE_PARAM(xe_rtp_table_oob_test, oob_was_gen_params),
 	KUNIT_CASE_PARAM(xe_rtp_table_dev_oob_test, device_oob_was_gen_params),
+	KUNIT_CASE_PARAM(xe_rtp_table_missing_upper_bound_test,
+			 register_whitelist_gen_params),
 	{}
 };
 
diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c
index 3d9e3daab01a..fe996d23007b 100644
--- a/drivers/gpu/drm/xe/xe_reg_whitelist.c
+++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c
@@ -5,6 +5,8 @@
 
 #include "xe_reg_whitelist.h"
 
+#include <kunit/visibility.h>
+
 #include "regs/xe_engine_regs.h"
 #include "regs/xe_gt_regs.h"
 #include "regs/xe_oa_regs.h"
@@ -41,7 +43,7 @@ static bool match_multi_queue_class(const struct xe_device *xe,
 	return xe_gt_supports_multi_queue(gt, hwe->class);
 }
 
-static const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR(
+VISIBLE_IF_KUNIT const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR(
 	{ XE_RTP_NAME("WaAllowPMDepthAndInvocationCountAccessFromUMD, 1408556865"),
 	  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210), ENGINE_CLASS(RENDER)),
 	  XE_RTP_ACTIONS(WHITELIST(PS_INVOCATION_COUNT,
@@ -104,6 +106,7 @@ static const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR(
 				   RING_FORCE_TO_NONPRIV_ACCESS_RW))
 	},
 );
+EXPORT_SYMBOL_IF_KUNIT(register_whitelist);
 
 static const struct xe_rtp_table_sr oa_whitelist = XE_RTP_TABLE_SR(
 
diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.h b/drivers/gpu/drm/xe/xe_reg_whitelist.h
index e1eb1b7d5480..c0248063d515 100644
--- a/drivers/gpu/drm/xe/xe_reg_whitelist.h
+++ b/drivers/gpu/drm/xe/xe_reg_whitelist.h
@@ -14,6 +14,10 @@ struct xe_hw_engine;
 struct xe_reg_sr;
 struct xe_reg_sr_entry;
 
+#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
+extern const struct xe_rtp_table_sr register_whitelist;
+#endif
+
 void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe);
 
 void xe_reg_whitelist_oa_regs(struct xe_gt *gt);

---
base-commit: c04e038b8787434bf489ea6de4ab2e2d936083c7
change-id: 20260625-kunit_whitelist_bounds-a88495e5cc7b

Best regards,
-- 
Matt Roper
Graphics Software Engineer
Linux GPU Platform Enablement
Intel Corporation


^ permalink raw reply related

* Re: [PATCH v6 03/10] drm: link connectors to backlight devices
From: Mario Limonciello @ 2026-06-26 21:40 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: dri-devel, harry.wentland, Simona Vetter, Alex Deucher,
	Maarten Lankhorst, Thomas Zimmermann, David Airlie, Xaver Hugl,
	amd-gfx, open list:INTEL DRM DISPLAY FOR XE AND I915 DRIVERS,
	open list:INTEL DRM DISPLAY FOR XE AND I915 DRIVERS,
	Mario Limonciello (AMD), Dmitry Baryshkov
In-Reply-To: <20260626-warping-quizzical-cuttlefish-beb8be@houat>



On 6/26/26 02:34, Maxime Ripard wrote:
> On Wed, Jun 24, 2026 at 09:57:43AM -0700, Mario Limonciello wrote:
>> From: "Mario Limonciello (AMD)" <superm1@kernel.org>
>>
>> This will show which connector in sysfs matches which backlight.
>>
>> Tested-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> # SM8150-HDK
>> Signed-off-by: Mario Limonciello (AMD) <superm1@kernel.org>
>> ---
>>   drivers/gpu/drm/Kconfig             |   1 +
>>   drivers/gpu/drm/Makefile            |   1 +
>>   drivers/gpu/drm/drm_backlight.c     | 371 ++++++++++++++++++++++++++++
>>   drivers/gpu/drm/drm_connector.c     |  12 +
>>   drivers/gpu/drm/drm_drv.c           |   8 +
>>   drivers/gpu/drm/drm_mode_config.c   |   7 +
>>   drivers/gpu/drm/drm_mode_object.c   |  66 ++++-
>>   drivers/gpu/drm/drm_sysfs.c         |  28 ++-
>>   drivers/video/backlight/backlight.c |  17 ++
>>   include/drm/drm_backlight.h         |  51 ++++
>>   include/drm/drm_connector.h         |   3 +
>>   include/drm/drm_mode_config.h       |   5 +
>>   include/linux/backlight.h           |  13 +
>>   13 files changed, 578 insertions(+), 5 deletions(-)
>>   create mode 100644 drivers/gpu/drm/drm_backlight.c
>>   create mode 100644 include/drm/drm_backlight.h
>>
>> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
>> index 323422861e8f6..d6035bbbdc83f 100644
>> --- a/drivers/gpu/drm/Kconfig
>> +++ b/drivers/gpu/drm/Kconfig
>> @@ -17,6 +17,7 @@ menuconfig DRM
>>   # device and dmabuf fd. Let's make sure that is available for our userspace.
>>   	select KCMP
>>   	select VIDEO
>> +	select BACKLIGHT_CLASS_DEVICE
>>   	help
>>   	  Kernel-level support for the Direct Rendering Infrastructure (DRI)
>>   	  introduced in XFree86 4.0. If you say Y here, you need to select
>> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
>> index e97faabcd7830..bf980a2ac1e6b 100644
>> --- a/drivers/gpu/drm/Makefile
>> +++ b/drivers/gpu/drm/Makefile
>> @@ -78,6 +78,7 @@ drm-$(CONFIG_DRM_CLIENT) += \
>>   	drm_client_event.o \
>>   	drm_client_modeset.o \
>>   	drm_client_sysrq.o
>> +drm-y += drm_backlight.o
>>   drm-$(CONFIG_COMPAT) += drm_ioc32.o
>>   drm-$(CONFIG_DRM_PANEL) += drm_panel.o
>>   drm-$(CONFIG_OF) += drm_of.o
>> diff --git a/drivers/gpu/drm/drm_backlight.c b/drivers/gpu/drm/drm_backlight.c
>> new file mode 100644
>> index 0000000000000..b1ec470be86ca
>> --- /dev/null
>> +++ b/drivers/gpu/drm/drm_backlight.c
>> @@ -0,0 +1,371 @@
>> +// SPDX-License-Identifier: MIT
>> +/*
>> + * DRM Backlight Helpers
>> + * Copyright (c) 2014 David Herrmann
>> + * Copyright (c) 2026 Advanced Micro Devices, Inc.
>> + */
>> +
>> +#include <linux/backlight.h>
>> +#include <linux/fs.h>
>> +#include <linux/list.h>
>> +#include <linux/math64.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/notifier.h>
>> +#include <linux/slab.h>
>> +#include <linux/spinlock.h>
>> +#include <drm/drm_backlight.h>
>> +#include <drm/drm_connector.h>
>> +#include <drm/drm_device.h>
>> +#include <drm/drm_mode_config.h>
>> +
>> +/**
>> + * DOC: Backlight Devices
>> + *
>> + * Backlight devices have always been managed as a separate subsystem,
>> + * independent of DRM. They are usually controlled via separate hardware
>> + * interfaces than the display controller, so the split works out fine.
>> + * However, backlight brightness is a property of a display, and thus a
>> + * property of a DRM connector. We already manage DPMS states via connector
>> + * properties, so it is natural to keep brightness control at the same place.
>> + *
>> + * This DRM backlight interface implements generic backlight properties on
>> + * connectors. It does not handle any hardware backends but simply forwards
>> + * the requests to a linked backlight device. The links between connectors and
>> + * backlight devices are established by DRM drivers; user-space cannot create
>> + * or modify these links. A 'change' uevent is sent whenever the brightness is
>> + * updated.
> 
> I think we should explain why, because if it's a property and comes from
> the userspace, then why would luminance be special and trigger a uevent
> when it's updated, unlike any other property?

At one point there was a concept of userspace could still change it from 
sysfs, but now that's changed.  I think you're right and this can be 
dropped.

> 
>> + * Drivers have to call drm_backlight_alloc() after allocating a connector via
>> + * drm_connector_init(). This will automatically add a backlight device to the
>> + * given connector. Drivers must then link a hardware backlight by calling
>> + * drm_backlight_link() with the registered backlight_device. If no link is
>> + * established, the DRM backlight property reports an empty range and
>> + * brightness changes are no-ops.
>> + */
> 
> It's not clear to me why we need to dynamically allocate them at all. If
> we're using the backlight subsystem we'll already have a handle to it.
> If we don't and want to implement something like DDC/CI, then it just
> becomes a hassle. Why not treat it like i2c, add a backlight field to
> drm_connector, and create the link at registration, add a new hook to
> set luminance, and then provide helpers to either use the backlight API,
> or anything else if the driver wants to.

I did envision that later on we can have displays with DDC use this 
infrastructure as well.  But I didn't want to hold up the series 
implementing that.

> 
>> +struct drm_backlight {
>> +	struct list_head list;
>> +	struct drm_connector *connector;
>> +	struct backlight_device *link;
>> +	/*
>> +	 * Number of luminance-aware DRM clients that have taken over this
>> +	 * connector's backlight. While > 0, legacy sysfs writes to the
>> +	 * linked backlight_device return -EBUSY. Protected by
>> +	 * drm_backlight_lock.
>> +	 */
>> +	unsigned int luminance_clients;
>> +};
>> +
>> +static LIST_HEAD(drm_backlight_list);
>> +static DEFINE_SPINLOCK(drm_backlight_lock);
>> +
>> +/* caller must hold @drm_backlight_lock */
>> +static bool __drm_backlight_is_registered(struct drm_backlight *b)
>> +{
>> +	lockdep_assert_held(&drm_backlight_lock);
>> +	/* a device is live if it is linked to @drm_backlight_list */
>> +	return !list_empty(&b->list);
>> +}
>> +
>> +/* caller must hold @drm_backlight_lock */
>> +static void __drm_backlight_real_changed(struct drm_backlight *b, uint64_t v)
>> +{
>> +	unsigned int max, set;
>> +
>> +	lockdep_assert_held(&drm_backlight_lock);
>> +
>> +	if (!b->link)
>> +		return;
>> +
>> +	max = b->link->props.max_brightness;
>> +	if (max < 1)
>> +		return;
>> +
>> +	set = v;
>> +	if (set >= max)
>> +		set = max;
>> +}
>> +
>> +/**
>> + * __drm_backlight_update_prop_range - update the luminance property range
>> + * @b: backlight device
>> + *
>> + * Updates the luminance property range based on the linked backlight device's
>> + * max_brightness. If no device is linked, sets range to 0-0 to indicate
>> + * unavailability.
>> + */
>> +static void __drm_backlight_update_prop_range(struct drm_backlight *b)
>> +{
>> +	struct drm_device *dev = b->connector->dev;
>> +	struct drm_property *prop = dev->mode_config.luminance_property;
>> +	unsigned int max = 0;
>> +
>> +	lockdep_assert_held(&drm_backlight_lock);
>> +
>> +	if (b->link && b->link->props.max_brightness > 0)
>> +		max = b->link->props.max_brightness;
>> +
>> +	/* Update property range to match hardware capabilities.
>> +	 * Range of 0-0 indicates no backing device.
>> +	 * Range of 1-max for normal operation (0 reserved for display off).
>> +	 */
>> +	if (prop->values[1] != max) {
>> +		prop->values[0] = max ? 1 : 0;
>> +		prop->values[1] = max;
>> +	}
>> +}
>> +
>> +/* caller must hold @drm_backlight_lock */
>> +static bool __drm_backlight_link(struct drm_backlight *b,
>> +				 struct backlight_device *bd)
>> +{
>> +	if (bd == b->link)
>> +		return false;
>> +
>> +	backlight_device_unref(b->link);
>> +	b->link = bd;
>> +	backlight_device_ref(b->link);
>> +	if (bd)
>> +		__drm_backlight_real_changed(b, bd->props.brightness);
>> +	__drm_backlight_update_prop_range(b);
>> +
>> +	return true;
>> +}
>> +
>> +/**
>> + * drm_backlight_alloc - add backlight capability to a connector
>> + * @connector: connector to add backlight to
>> + *
>> + * This allocates a new DRM-backlight device and attaches it to @connector.
>> + * This *must* be called before registering the connector. The backlight
>> + * device will be automatically registered in sync with the connector. It will
>> + * also get removed once the connector is removed.
>> + *
>> + * No hardware backlight is linked by default. Drivers must call
>> + * drm_backlight_link() to associate a registered backlight_device with the
>> + * connector. User-space cannot create or modify this link.
>> + *
>> + * Returns: 0 on success, negative error code on failure.
>> + */
>> +int drm_backlight_alloc(struct drm_connector *connector)
>> +{
>> +	struct drm_mode_config *config = &connector->dev->mode_config;
>> +	struct drm_backlight *b;
>> +
>> +	b = kzalloc_obj(*b, GFP_KERNEL);
>> +	if (!b)
>> +		return -ENOMEM;
>> +
>> +	INIT_LIST_HEAD(&b->list);
>> +	b->connector = connector;
>> +	connector->backlight = b;
>> +
>> +	drm_object_attach_property(&connector->base,
>> +				   config->luminance_property, 0);
>> +
>> +	return 0;
>> +}
>> +EXPORT_SYMBOL(drm_backlight_alloc);
>> +
>> +void drm_backlight_free(struct drm_connector *connector)
>> +{
>> +	struct drm_backlight *b = connector->backlight;
>> +
>> +	if (!b)
>> +		return;
>> +
>> +	WARN_ON(__drm_backlight_is_registered(b));
>> +	WARN_ON(b->link);
>> +
>> +	kfree(b);
>> +	connector->backlight = NULL;
>> +}
>> +EXPORT_SYMBOL(drm_backlight_free);
>> +
>> +void drm_backlight_register(struct drm_backlight *b)
>> +{
>> +	if (!b)
>> +		return;
>> +
>> +	WARN_ON(__drm_backlight_is_registered(b));
>> +
>> +	guard(spinlock)(&drm_backlight_lock);
>> +	list_add(&b->list, &drm_backlight_list);
>> +}
>> +EXPORT_SYMBOL(drm_backlight_register);
>> +
>> +void drm_backlight_unregister(struct drm_backlight *b)
>> +{
>> +	if (!b)
>> +		return;
>> +
>> +	WARN_ON(!__drm_backlight_is_registered(b));
>> +
>> +	scoped_guard(spinlock, &drm_backlight_lock) {
>> +		list_del_init(&b->list);
>> +		__drm_backlight_link(b, NULL);
>> +	}
>> +}
>> +EXPORT_SYMBOL(drm_backlight_unregister);
>> +
>> +/**
>> + * drm_backlight_link - link a backlight device to a DRM backlight
>> + * @b: DRM backlight to modify
>> + * @bd: backlight device to link, or NULL to unlink
>> + *
>> + * Establish the link between a DRM connector's backlight property and a
>> + * registered backlight_device. Drivers must call this with the
>> + * backlight_device they registered for the connector. Passing NULL unlinks
>> + * any previously linked device.
>> + *
>> + * The caller is responsible for ensuring @bd remains valid until either it
>> + * is unlinked via drm_backlight_link(b, NULL) or the connector is
>> + * unregistered.
>> + *
>> + * Whenever a hardware backlight is linked or unlinked, a uevent with
>> + * "BACKLIGHT=1" is generated on the connector.
>> + */
>> +void drm_backlight_link(struct drm_backlight *b, struct backlight_device *bd)
>> +{
>> +	if (!b)
>> +		return;
>> +
>> +	guard(spinlock)(&drm_backlight_lock);
>> +	__drm_backlight_link(b, bd);
>> +}
>> +EXPORT_SYMBOL(drm_backlight_link);
>> +
>> +/**
>> + * drm_backlight_get_device - get the backlight_device linked to a DRM backlight
>> + * @b: DRM backlight
>> + *
>> + * Returns the &backlight_device linked to @b, or NULL if no device is linked
>> + * or @b is NULL. The caller must hold the appropriate lock to prevent the
>> + * link from changing while the pointer is in use.
>> + */
>> +struct backlight_device *drm_backlight_get_device(struct drm_backlight *b)
>> +{
>> +	if (!b)
>> +		return NULL;
>> +
>> +	guard(spinlock)(&drm_backlight_lock);
>> +	return b->link;
>> +}
>> +EXPORT_SYMBOL(drm_backlight_get_device);
>> +
>> +/**
>> + * drm_backlight_inhibit_legacy - disable legacy sysfs control of the linked bd
>> + * @b: DRM backlight to inhibit
>> + *
>> + * Record that one more luminance-aware DRM client has taken over @b. While
>> + * any clients are recorded, writes to the linked backlight_device's legacy
>> + * ``brightness`` sysfs attribute return ``-EBUSY``. The takeover follows
>> + * @b->link if the link changes.
>> + *
>> + * Calls must be balanced with drm_backlight_uninhibit_legacy().
>> + */
>> +void drm_backlight_inhibit_legacy(struct drm_backlight *b)
>> +{
>> +	if (!b)
>> +		return;
>> +}
>> +EXPORT_SYMBOL(drm_backlight_inhibit_legacy);
>> +
>> +/**
>> + * drm_backlight_uninhibit_legacy - re-enable legacy sysfs control
>> + * @b: DRM backlight to uninhibit
>> + *
>> + * Balances a previous drm_backlight_inhibit_legacy() call. When the last
>> + * luminance-aware client goes away, legacy sysfs writes are allowed again.
>> + */
>> +void drm_backlight_uninhibit_legacy(struct drm_backlight *b)
>> +{
>> +	if (!b)
>> +		return;
>> +}
>> +EXPORT_SYMBOL(drm_backlight_uninhibit_legacy);
>> +
>> +/**
>> + * drm_backlight_inhibit_legacy_all - inhibit legacy sysfs on every connector
>> + * @dev: DRM device whose connectors should be inhibited
>> + *
>> + * Walks all connectors on @dev and calls drm_backlight_inhibit_legacy() on
>> + * each connector that has a DRM backlight attached. Used when a client
>> + * declares it is luminance-aware via DRM_CLIENT_CAP_LUMINANCE.
>> + */
>> +void drm_backlight_inhibit_legacy_all(struct drm_device *dev)
>> +{
>> +	struct drm_connector_list_iter iter;
>> +	struct drm_connector *connector;
>> +
>> +	drm_connector_list_iter_begin(dev, &iter);
>> +	drm_for_each_connector_iter(connector, &iter)
>> +		drm_backlight_inhibit_legacy(connector->backlight);
>> +	drm_connector_list_iter_end(&iter);
>> +}
>> +EXPORT_SYMBOL(drm_backlight_inhibit_legacy_all);
>> +
>> +/**
>> + * drm_backlight_uninhibit_legacy_all - reverse drm_backlight_inhibit_legacy_all()
>> + * @dev: DRM device whose connectors should be uninhibited
>> + */
>> +void drm_backlight_uninhibit_legacy_all(struct drm_device *dev)
>> +{
>> +	struct drm_connector_list_iter iter;
>> +	struct drm_connector *connector;
>> +
>> +	drm_connector_list_iter_begin(dev, &iter);
>> +	drm_for_each_connector_iter(connector, &iter)
>> +		drm_backlight_uninhibit_legacy(connector->backlight);
>> +	drm_connector_list_iter_end(&iter);
>> +}
>> +EXPORT_SYMBOL(drm_backlight_uninhibit_legacy_all);
>> +
>> +void drm_backlight_set_luminance(struct drm_backlight *b, unsigned int value)
>> +{
>> +	guard(spinlock)(&drm_backlight_lock);
>> +	__drm_backlight_real_changed(b, value);
>> +}
>> +EXPORT_SYMBOL(drm_backlight_set_luminance);
>> +
>> +static int drm_backlight_notify(struct notifier_block *self,
>> +				unsigned long event, void *data)
>> +{
>> +	struct backlight_device *bd = data;
>> +	struct drm_backlight *b;
>> +
>> +	guard(spinlock)(&drm_backlight_lock);
>> +
>> +	switch (event) {
>> +	case BACKLIGHT_UNREGISTERED:
>> +		list_for_each_entry(b, &drm_backlight_list, list)
>> +			if (b->link == bd)
>> +				__drm_backlight_link(b, NULL);
>> +
>> +		break;
>> +	case BACKLIGHT_BRIGHTNESS_CHANGED:
>> +		/* Update DRM property value when hardware backlight changes */
>> +		list_for_each_entry(b, &drm_backlight_list, list)
>> +			if (b->link == bd)
>> +				__drm_backlight_real_changed(b, bd->props.brightness);
>> +
>> +		break;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static struct notifier_block drm_backlight_notifier = {
>> +	.notifier_call = drm_backlight_notify,
>> +};
>> +
>> +int drm_backlight_init(void)
>> +{
>> +	return backlight_register_notifier(&drm_backlight_notifier);
>> +}
>> +
>> +void drm_backlight_exit(void)
>> +{
>> +	backlight_unregister_notifier(&drm_backlight_notifier);
>> +}
>> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
>> index 3fa4d2082cd72..128d431f0d6b0 100644
>> --- a/drivers/gpu/drm/drm_connector.c
>> +++ b/drivers/gpu/drm/drm_connector.c
>> @@ -21,6 +21,7 @@
>>    */
>>   
>>   #include <drm/drm_auth.h>
>> +#include <drm/drm_backlight.h>
>>   #include <drm/drm_connector.h>
>>   #include <drm/drm_drv.h>
>>   #include <drm/drm_edid.h>
>> @@ -760,6 +761,7 @@ void drm_connector_cleanup(struct drm_connector *connector)
>>   	struct drm_device *dev = connector->dev;
>>   	struct drm_display_mode *mode, *t;
>>   
>> +	drm_backlight_free(connector);
>>   	/* The connector should have been removed from userspace long before
>>   	 * it is finally destroyed.
>>   	 */
>> @@ -845,6 +847,8 @@ int drm_connector_register(struct drm_connector *connector)
>>   	if (connector->registration_state != DRM_CONNECTOR_INITIALIZING)
>>   		goto unlock;
>>   
>> +	drm_backlight_register(connector->backlight);
>> +
>>   	ret = drm_sysfs_connector_add(connector);
>>   	if (ret)
>>   		goto unlock;
>> @@ -931,6 +935,8 @@ EXPORT_SYMBOL(drm_connector_dynamic_register);
>>   void drm_connector_unregister(struct drm_connector *connector)
>>   {
>>   	mutex_lock(&connector->mutex);
>> +	drm_backlight_unregister(connector->backlight);
>> +
>>   	if (connector->registration_state != DRM_CONNECTOR_REGISTERED) {
>>   		mutex_unlock(&connector->mutex);
>>   		return;
>> @@ -3252,10 +3258,16 @@ int drm_connector_set_obj_prop(struct drm_mode_object *obj,
>>   {
>>   	int ret = -EINVAL;
>>   	struct drm_connector *connector = obj_to_connector(obj);
>> +	struct drm_mode_config *config = &connector->dev->mode_config;
>>   
>>   	/* Do DPMS ourselves */
>>   	if (property == connector->dev->mode_config.dpms_property) {
>>   		ret = (*connector->funcs->dpms)(connector, (int)value);
>> +	} else if (property == config->luminance_property) {
>> +		if (connector->backlight && connector->dpms == DRM_MODE_DPMS_ON)
>> +			drm_backlight_set_luminance(connector->backlight,
>> +						    value);
>> +		ret = 0;
>>   	} else if (connector->funcs->set_property)
>>   		ret = connector->funcs->set_property(connector, property, value);
>>   
>> diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
>> index 675675480da49..5bf402197867a 100644
>> --- a/drivers/gpu/drm/drm_drv.c
>> +++ b/drivers/gpu/drm/drm_drv.c
>> @@ -42,6 +42,7 @@
>>   #include <linux/xarray.h>
>>   
>>   #include <drm/drm_accel.h>
>> +#include <drm/drm_backlight.h>
>>   #include <drm/drm_bridge.h>
>>   #include <drm/drm_cache.h>
>>   #include <drm/drm_client_event.h>
>> @@ -1230,6 +1231,7 @@ static void drm_core_exit(void)
>>   	drm_privacy_screen_lookup_exit();
>>   	drm_panic_exit();
>>   	accel_core_exit();
>> +	drm_backlight_exit();
>>   	unregister_chrdev(DRM_MAJOR, "drm");
>>   	drm_debugfs_remove_root();
>>   	drm_sysfs_destroy();
>> @@ -1253,6 +1255,12 @@ static int __init drm_core_init(void)
>>   	drm_debugfs_init_root();
>>   	drm_debugfs_bridge_params();
>>   
>> +	ret = drm_backlight_init();
>> +	if (ret < 0) {
>> +		DRM_ERROR("Cannot initialize backlight interface\n");
>> +		goto error;
>> +	}
>> +
>>   	ret = register_chrdev(DRM_MAJOR, "drm", &drm_stub_fops);
>>   	if (ret < 0)
>>   		goto error;
>> diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c
>> index 66f7dc37b5970..25c5d29694624 100644
>> --- a/drivers/gpu/drm/drm_mode_config.c
>> +++ b/drivers/gpu/drm/drm_mode_config.c
>> @@ -32,6 +32,7 @@
>>   #include <drm/drm_print.h>
>>   #include <drm/drm_colorop.h>
>>   #include <linux/dma-resv.h>
>> +#include <drm/drm_backlight.h>
>>   
>>   #include "drm_crtc_internal.h"
>>   #include "drm_internal.h"
>> @@ -407,6 +408,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
>>   		return -ENOMEM;
>>   	dev->mode_config.size_hints_property = prop;
>>   
>> +	prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
>> +					 "LUMINANCE", 0, 0);
>> +	if (!prop)
>> +		return -ENOMEM;
>> +	dev->mode_config.luminance_property = prop;
>> +
>>   	return 0;
>>   }
>>   
>> diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c
>> index 21fc9deda4371..a50d33af95e8c 100644
>> --- a/drivers/gpu/drm/drm_mode_object.c
>> +++ b/drivers/gpu/drm/drm_mode_object.c
>> @@ -30,6 +30,7 @@
>>   #include <drm/drm_mode_object.h>
>>   #include <drm/drm_plane.h>
>>   #include <drm/drm_print.h>
>> +#include <drm/drm_backlight.h>
>>   
>>   #include "drm_crtc_internal.h"
>>   
>> @@ -287,11 +288,72 @@ int drm_object_property_set_value(struct drm_mode_object *obj,
>>   {
>>   	int i;
>>   
>> -	WARN_ON(drm_drv_uses_atomic_modeset(property->dev) &&
>> -		!(property->flags & DRM_MODE_PROP_IMMUTABLE));
> 
> drm_object_property_set_value() is explicitly documented to be for
> legacy properties only. This warning is here for a reason, you should
> update the atomic path.

I seem to remember having a problem earlier on.  I'll try again.

> 
>> +	/* Exempt dpms and luminance properties from the atomic warning, as these
>> +	 * have special interdependencies managed internally in this function
>> +	 */
>> +	if (obj->type == DRM_MODE_OBJECT_CONNECTOR) {
>> +		struct drm_connector *connector = obj_to_connector(obj);
>> +		struct drm_mode_config *config = &connector->dev->mode_config;
>> +
>> +		if (property != config->dpms_property &&
>> +		    property != config->luminance_property) {
>> +			WARN_ON(drm_drv_uses_atomic_modeset(property->dev) &&
>> +				!(property->flags & DRM_MODE_PROP_IMMUTABLE));
>> +		}
>> +	} else {
>> +		WARN_ON(drm_drv_uses_atomic_modeset(property->dev) &&
>> +			!(property->flags & DRM_MODE_PROP_IMMUTABLE));
>> +	}
>>   
>>   	for (i = 0; i < obj->properties->count; i++) {
>> +		/* If properties depends on each other
>> +		 * this is where to resolve that issue
>> +		 */
> 
> This is not the right commit style:
> https://www.kernel.org/doc/html/latest/process/coding-style.html#commenting
> 
>>   		if (obj->properties->properties[i] == property) {
>> +			/* Connector-specific property interdependencies */
>> +			if (obj->type == DRM_MODE_OBJECT_CONNECTOR) {
>> +				struct drm_connector *connector = obj_to_connector(obj);
>> +				struct drm_property *dpms_property =
>> +					connector->dev->mode_config.dpms_property;
>> +				struct drm_property *luminance_property =
>> +					connector->dev->mode_config.luminance_property;
>> +
>> +				if (property == dpms_property) {
>> +					/* When DPMS goes from ON -> OFF,
>> +					 * set the brightness to the minimum possible
>> +					 * to save power.
>> +					 */
>> +					if (obj->properties->values[i] !=
>> +					    DRM_MODE_DPMS_OFF &&
>> +					    val == DRM_MODE_DPMS_OFF)
>> +						drm_backlight_set_luminance(
>> +							connector->backlight, 0);
>> +					/* When DPMS OFF -> ON, reset the brightness
>> +					 * to the original level
>> +					 */
>> +					else if (obj->properties->values[i] ==
>> +						 DRM_MODE_DPMS_OFF &&
>> +						 val != DRM_MODE_DPMS_OFF) {
>> +						uint64_t value;
>> +
>> +						drm_object_property_get_value(
>> +							obj, luminance_property,
>> +							&value);
>> +						drm_backlight_set_luminance(
>> +							connector->backlight, value);
>> +					}
>> +				} else if (property == luminance_property) {
>> +					/* Always update the property value to remember
>> +					 * the user's desired brightness, but only update
>> +					 * hardware when DPMS is ON.
>> +					 */
>> +					obj->properties->values[i] = val;
>> +					if (connector->dpms == DRM_MODE_DPMS_ON)
>> +						drm_backlight_set_luminance(
>> +							connector->backlight, val);
>> +					return 0;
>> +				}
>> +			}
> 
> And this all shouldn't be plugged into the function directly, but a helper ideally.
> 
>>   			obj->properties->values[i] = val;
>>   			return 0;
>>   		}
>> diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
>> index ef4e923a87284..8609e1660f210 100644
>> --- a/drivers/gpu/drm/drm_sysfs.c
>> +++ b/drivers/gpu/drm/drm_sysfs.c
>> @@ -11,6 +11,7 @@
>>    */
>>   
>>   #include <linux/acpi.h>
>> +#include <linux/backlight.h>
>>   #include <linux/component.h>
>>   #include <linux/device.h>
>>   #include <linux/err.h>
>> @@ -27,6 +28,7 @@
>>   #include <drm/drm_device.h>
>>   #include <drm/drm_file.h>
>>   #include <drm/drm_modes.h>
>> +#include <drm/drm_backlight.h>
>>   #include <drm/drm_print.h>
>>   #include <drm/drm_property.h>
>>   #include <drm/drm_sysfs.h>
>> @@ -391,15 +393,35 @@ int drm_sysfs_connector_add(struct drm_connector *connector)
>>   
>>   int drm_sysfs_connector_add_late(struct drm_connector *connector)
>>   {
>> -	if (connector->ddc)
>> -		return sysfs_create_link(&connector->kdev->kobj,
>> -					 &connector->ddc->dev.kobj, "ddc");
>> +	if (connector->ddc) {
>> +		int ret = sysfs_create_link(&connector->kdev->kobj,
>> +					    &connector->ddc->dev.kobj, "ddc");
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	if (connector->backlight) {
>> +		struct backlight_device *bd = drm_backlight_get_device(connector->backlight);
>> +
>> +		if (bd) {
>> +			int ret = sysfs_create_link(&connector->kdev->kobj,
>> +						    &bd->dev.kobj, "backlight");
>> +			if (ret) {
>> +				if (connector->ddc)
>> +					sysfs_remove_link(&connector->kdev->kobj, "ddc");
>> +				return ret;
>> +			}
>> +		}
>> +	}
>>   
>>   	return 0;
>>   }
>>   
>>   void drm_sysfs_connector_remove_early(struct drm_connector *connector)
>>   {
>> +	if (connector->backlight && drm_backlight_get_device(connector->backlight))
>> +		sysfs_remove_link(&connector->kdev->kobj, "backlight");
>> +
>>   	if (connector->ddc)
>>   		sysfs_remove_link(&connector->kdev->kobj, "ddc");
>>   }
>> diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
>> index cd1a161ae7bc6..13954c2220b7e 100644
>> --- a/drivers/video/backlight/backlight.c
>> +++ b/drivers/video/backlight/backlight.c
>> @@ -126,6 +126,9 @@ static void backlight_generate_event(struct backlight_device *bd,
>>   	case BACKLIGHT_UPDATE_HOTKEY:
>>   		envp[0] = "SOURCE=hotkey";
>>   		break;
>> +	case BACKLIGHT_UPDATE_DRM:
>> +		envp[0] = "SOURCE=drm";
>> +		break;
>>   	default:
>>   		envp[0] = "SOURCE=unknown";
>>   		break;
>> @@ -579,6 +582,20 @@ int backlight_unregister_notifier(struct notifier_block *nb)
>>   }
>>   EXPORT_SYMBOL(backlight_unregister_notifier);
>>   
>> +/**
>> + * backlight_notify_brightness - notify brightness change to listeners
>> + * @bd: backlight device that changed
>> + *
>> + * Notify registered listeners that the backlight brightness has changed.
>> + * This is called automatically after successful brightness updates.
>> + */
>> +void backlight_notify_brightness(struct backlight_device *bd)
>> +{
>> +	blocking_notifier_call_chain(&backlight_notifier,
>> +				     BACKLIGHT_BRIGHTNESS_CHANGED, bd);
>> +}
>> +EXPORT_SYMBOL(backlight_notify_brightness);
>> +
> 
> This should be in separate commits.
> 
>>   /**
>>    * devm_backlight_device_register - register a new backlight device
>>    * @dev: the device to register
>> diff --git a/include/drm/drm_backlight.h b/include/drm/drm_backlight.h
>> new file mode 100644
>> index 0000000000000..e0e09e38f7c06
>> --- /dev/null
>> +++ b/include/drm/drm_backlight.h
>> @@ -0,0 +1,51 @@
>> +/* SPDX-License-Identifier: MIT */
>> +#ifndef __DRM_BACKLIGHT_H__
>> +#define __DRM_BACKLIGHT_H__
>> +
>> +/*
>> + * Copyright (c) 2014 David Herrmann <dh.herrmann at gmail.com>
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a
>> + * copy of this software and associated documentation files (the "Software"),
>> + * to deal in the Software without restriction, including without limitation
>> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> + * and/or sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
>> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
>> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> + * OTHER DEALINGS IN THE SOFTWARE.
>> + */
>> +
>> +#include <linux/kernel.h>
>> +#include <linux/types.h>
>> +
>> +struct backlight_device;
>> +struct drm_backlight;
>> +struct drm_connector;
>> +struct drm_device;
>> +struct drm_mode_object;
>> +
>> +int drm_backlight_init(void);
>> +void drm_backlight_exit(void);
>> +
>> +int drm_backlight_alloc(struct drm_connector *connector);
>> +void drm_backlight_free(struct drm_connector *connector);
>> +void drm_backlight_register(struct drm_backlight *b);
>> +void drm_backlight_unregister(struct drm_backlight *b);
>> +
>> +void drm_backlight_link(struct drm_backlight *b, struct backlight_device *bd);
>> +struct backlight_device *drm_backlight_get_device(struct drm_backlight *b);
>> +void drm_backlight_set_luminance(struct drm_backlight *b, unsigned int value);
>> +void drm_backlight_inhibit_legacy(struct drm_backlight *b);
>> +void drm_backlight_uninhibit_legacy(struct drm_backlight *b);
>> +void drm_backlight_inhibit_legacy_all(struct drm_device *dev);
>> +void drm_backlight_uninhibit_legacy_all(struct drm_device *dev);
>> +#endif /* __DRM_BACKLIGHT_H__ */
>> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
>> index 5ad62c207d009..d78ac1068d12e 100644
>> --- a/include/drm/drm_connector.h
>> +++ b/include/drm/drm_connector.h
>> @@ -2410,6 +2410,9 @@ struct drm_connector {
>>   	 * @cec: CEC-related data.
>>   	 */
>>   	struct drm_connector_cec cec;
>> +
>> +	/* backlight link */
>> +	struct drm_backlight *backlight;
>>   };
>>   
>>   #define obj_to_connector(x) container_of(x, struct drm_connector, base)
>> diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
>> index e584652ddf676..b6d88319d5d0f 100644
>> --- a/include/drm/drm_mode_config.h
>> +++ b/include/drm/drm_mode_config.h
>> @@ -852,6 +852,11 @@ struct drm_mode_config {
>>   	 * the position of the output on the host's screen.
>>   	 */
>>   	struct drm_property *suggested_y_property;
>> +	/**
>> +	 * @luminance_property: Default connector property to control the
>> +	 * connector's backlight luminance.
>> +	 */
>> +	struct drm_property *luminance_property;
>>   
>>   	/**
>>   	 * @non_desktop_property: Optional connector property with a hint
>> diff --git a/include/linux/backlight.h b/include/linux/backlight.h
>> index 204eea9256fd7..26a7281d179c1 100644
>> --- a/include/linux/backlight.h
>> +++ b/include/linux/backlight.h
>> @@ -29,6 +29,7 @@ enum backlight_update_reason {
>>   	 * @BACKLIGHT_UPDATE_SYSFS: The backlight was updated using sysfs.
>>   	 */
>>   	BACKLIGHT_UPDATE_SYSFS,
>> +	BACKLIGHT_UPDATE_DRM,
> 
> Doc?
> 
> Maxime


^ permalink raw reply

* [PATCH] drm/xe: Drop 'force_execlist' module parameter
From: Matt Roper @ 2026-06-26 21:39 UTC (permalink / raw)
  To: intel-xe; +Cc: Matt Roper

During very early development of the Xe driver the force_execlist module
parameter could be used to exercise some parts of the driver in a
GuC-less manner.  This was primarily intended to ensure that the driver
was being designed and developed with proper modularity and layering;
use of the GuC firmware has always been considered mandatory for any
real Xe driver operation.  The "execlist" implementation in the driver
was never completed, and has further bitrotted over time to the point
where it hangs during execution of even the simplest IGT tests like
xe_exec_store now.

Drop the force_execlist parameter; it's broken and isn't going to get
fixed.  In the (very unlikely) event that we decide to bring something
like this back in the future, it would need to be as a per-device
configfs setting rather than a driver-wide module parameter.

The "execlist" implementation is now dead code, so it will probably also
be removed sometime in the near future.  There's a bit more general
refactoring we might want to do first before we take that step, so for
now we're just removing the module parameter.

Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/xe/xe_debugfs.c       | 1 -
 drivers/gpu/drm/xe/xe_device.h        | 2 +-
 drivers/gpu/drm/xe/xe_device_types.h  | 2 --
 drivers/gpu/drm/xe/xe_gt_mcr.c        | 3 +--
 drivers/gpu/drm/xe/xe_guc_tlb_inval.c | 6 ------
 drivers/gpu/drm/xe/xe_module.c        | 3 ---
 drivers/gpu/drm/xe/xe_module.h        | 1 -
 drivers/gpu/drm/xe/xe_pci.c           | 1 -
 8 files changed, 2 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c
index 22b471303984..3c018dbccc07 100644
--- a/drivers/gpu/drm/xe/xe_debugfs.c
+++ b/drivers/gpu/drm/xe/xe_debugfs.c
@@ -117,7 +117,6 @@ static int info(struct seq_file *m, void *data)
 	drm_printf(&p, "revid %d\n", xe->info.revid);
 	drm_printf(&p, "tile_count %d\n", xe->info.tile_count);
 	drm_printf(&p, "vm_max_level %d\n", xe->info.vm_max_level);
-	drm_printf(&p, "force_execlist %s\n", str_yes_no(xe->info.force_execlist));
 	drm_printf(&p, "has_flat_ccs %s\n", str_yes_no(xe->info.has_flat_ccs));
 	drm_printf(&p, "has_usm %s\n", str_yes_no(xe->info.has_usm));
 	drm_printf(&p, "skip_guc_pc %s\n", str_yes_no(xe->info.skip_guc_pc));
diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h
index 975768a6a9c8..8056d8bd7d6d 100644
--- a/drivers/gpu/drm/xe/xe_device.h
+++ b/drivers/gpu/drm/xe/xe_device.h
@@ -116,7 +116,7 @@ static inline struct xe_mmio *xe_root_tile_mmio(struct xe_device *xe)
 
 static inline bool xe_device_uc_enabled(struct xe_device *xe)
 {
-	return !xe->info.force_execlist;
+	return true;
 }
 
 #define for_each_tile(tile__, xe__, id__) \
diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
index 4e2f115f14e2..46a9e9fad7a9 100644
--- a/drivers/gpu/drm/xe/xe_device_types.h
+++ b/drivers/gpu/drm/xe/xe_device_types.h
@@ -144,8 +144,6 @@ struct xe_device {
 		 * Keep all flags below alphabetically sorted
 		 */
 
-		/** @info.force_execlist: Forced execlist submission */
-		u8 force_execlist:1;
 		/** @info.has_access_counter: Device supports access counter */
 		u8 has_access_counter:1;
 		/** @info.has_asid: Has address space ID */
diff --git a/drivers/gpu/drm/xe/xe_gt_mcr.c b/drivers/gpu/drm/xe/xe_gt_mcr.c
index d11cc9e25cdb..a97b236dab7c 100644
--- a/drivers/gpu/drm/xe/xe_gt_mcr.c
+++ b/drivers/gpu/drm/xe/xe_gt_mcr.c
@@ -404,8 +404,7 @@ static unsigned int dss_per_group(struct xe_gt *gt)
 	 * Some older platforms don't have tables or don't have complete tables.
 	 * Newer platforms should always have the required info.
 	 */
-	if (GRAPHICS_VERx100(gt_to_xe(gt)) >= 2000 &&
-	    !gt_to_xe(gt)->info.force_execlist)
+	if (GRAPHICS_VERx100(gt_to_xe(gt)) >= 2000)
 		xe_gt_err(gt, "Slice/Subslice counts missing from hwconfig table; using typical fallback values\n");
 
 	if (gt_to_xe(gt)->info.platform == XE_PVC)
diff --git a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c
index cf6d106e6036..046d0655122f 100644
--- a/drivers/gpu/drm/xe/xe_guc_tlb_inval.c
+++ b/drivers/gpu/drm/xe/xe_guc_tlb_inval.c
@@ -208,9 +208,6 @@ static int send_tlb_inval_asid_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno,
 
 	lockdep_assert_held(&tlb_inval->seqno_lock);
 
-	if (guc_to_xe(guc)->info.force_execlist)
-		return -ECANCELED;
-
 	return send_tlb_inval_ppgtt(guc, seqno, start, end, asid,
 				    XE_GUC_TLB_INVAL_PAGE_SELECTIVE, prl_sa);
 }
@@ -228,9 +225,6 @@ static int send_tlb_inval_ctx_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno,
 
 	lockdep_assert_held(&tlb_inval->seqno_lock);
 
-	if (xe->info.force_execlist)
-		return -ECANCELED;
-
 	vm = xe_device_asid_to_vm(xe, asid);
 	if (IS_ERR(vm))
 		return PTR_ERR(vm);
diff --git a/drivers/gpu/drm/xe/xe_module.c b/drivers/gpu/drm/xe/xe_module.c
index 4cb578182912..39e4fc85f019 100644
--- a/drivers/gpu/drm/xe/xe_module.c
+++ b/drivers/gpu/drm/xe/xe_module.c
@@ -36,9 +36,6 @@ module_param_named(svm_notifier_size, xe_modparam.svm_notifier_size, uint, 0600)
 MODULE_PARM_DESC(svm_notifier_size, "Set the svm notifier size in MiB, must be power of 2 "
 		 "[default=" __stringify(XE_DEFAULT_SVM_NOTIFIER_SIZE) "]");
 
-module_param_named_unsafe(force_execlist, xe_modparam.force_execlist, bool, 0444);
-MODULE_PARM_DESC(force_execlist, "Force Execlist submission");
-
 #if IS_ENABLED(CONFIG_DRM_XE_DISPLAY)
 module_param_named(probe_display, xe_modparam.probe_display, bool, 0444);
 MODULE_PARM_DESC(probe_display, "Probe display HW, otherwise it's left untouched "
diff --git a/drivers/gpu/drm/xe/xe_module.h b/drivers/gpu/drm/xe/xe_module.h
index 79cb9639c0f3..c75153471248 100644
--- a/drivers/gpu/drm/xe/xe_module.h
+++ b/drivers/gpu/drm/xe/xe_module.h
@@ -10,7 +10,6 @@
 
 /* Module modprobe variables */
 struct xe_modparam {
-	bool force_execlist;
 	bool probe_display;
 	int force_vram_bar_size;
 	int guc_log_level;
diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
index 9c249454cc95..15020df6937a 100644
--- a/drivers/gpu/drm/xe/xe_pci.c
+++ b/drivers/gpu/drm/xe/xe_pci.c
@@ -793,7 +793,6 @@ static int xe_info_init_early(struct xe_device *xe,
 	xe->info.probe_display = IS_ENABLED(CONFIG_DRM_XE_DISPLAY) &&
 				 xe_modparam.probe_display &&
 				 desc->has_display;
-	xe->info.force_execlist = xe_modparam.force_execlist;
 
 	xe_assert(xe, desc->max_gt_per_tile > 0);
 	xe_assert(xe, desc->max_gt_per_tile <= XE_MAX_GT_PER_TILE);

---
base-commit: 4020469e425c12c543a21904da37735c392223a3
change-id: 20260626-remove_execlists-45f82839fc8a

Best regards,
-- 
Matt Roper
Graphics Software Engineer
Linux GPU Platform Enablement
Intel Corporation


^ permalink raw reply related

* [PATCH] drm/xe/hw_engine: Fix double-free of managed BO in error path
From: Shuicheng Lin @ 2026-06-26 21:06 UTC (permalink / raw)
  To: intel-xe; +Cc: Shuicheng Lin, Zongyao Bai

The error path in hw_engine_init() explicitly frees a BO allocated
with xe_managed_bo_create_pin_map() via xe_bo_unpin_map_no_vm().
Since the managed BO already has a devm cleanup action registered,
this causes a double-free when devm unwinds during probe failure.

Remove the explicit free and let devm handle it, consistent with
all other xe_managed_bo_create_pin_map() callers.

Fixes: 23e939bc8f56 ("drm/xe: Add a helper for DRM device-lifetime BO create")
Assisted-by: Claude:claude-opus-4.6
Reviewed-by: Zongyao Bai <zongyao.bai@intel.com>
Signed-off-by: Shuicheng Lin <shuicheng.lin@intel.com>
---
Rebase to latest code and Re-send for CI.
---
 drivers/gpu/drm/xe/xe_hw_engine.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
index 76aee461bcbe..87d60c4117bd 100644
--- a/drivers/gpu/drm/xe/xe_hw_engine.c
+++ b/drivers/gpu/drm/xe/xe_hw_engine.c
@@ -636,7 +636,7 @@ static int hw_engine_init(struct xe_gt *gt, struct xe_hw_engine *hwe,
 		hwe->exl_port = xe_execlist_port_create(xe, hwe);
 		if (IS_ERR(hwe->exl_port)) {
 			err = PTR_ERR(hwe->exl_port);
-			goto err_hwsp;
+			goto err_name;
 		}
 	} else {
 		/* GSCCS has a special interrupt for reset */
@@ -656,8 +656,6 @@ static int hw_engine_init(struct xe_gt *gt, struct xe_hw_engine *hwe,
 
 	return devm_add_action_or_reset(xe->drm.dev, hw_engine_fini, hwe);
 
-err_hwsp:
-	xe_bo_unpin_map_no_vm(hwe->hwsp);
 err_name:
 	hwe->name = NULL;
 
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH 2/2] drm/xe/hw_engine: Fix double-free of managed BO in error path
From: Bai, Zongyao @ 2026-06-26 20:00 UTC (permalink / raw)
  To: intel-xe
In-Reply-To: <8c188c17-04fc-4b4a-9f3b-613004678b2e@intel.com>


On 6/26/2026 10:34 AM, Bai, Zongyao wrote:
>
> On 4/17/2026 9:19 AM, Shuicheng Lin wrote:
>> The error path in hw_engine_init() explicitly frees a BO allocated
>> with xe_managed_bo_create_pin_map() via xe_bo_unpin_map_no_vm().
>> Since the managed BO already has a devm cleanup action registered,
>> this causes a double-free when devm unwinds during probe failure.
>>
>> Remove the explicit free and let devm handle it, consistent with
>> all other xe_managed_bo_create_pin_map() callers.
>>
>> Fixes: 23e939bc8f56 ("drm/xe: Add a helper for DRM device-lifetime BO 
>> create")
>> Cc: Michał Winiarski <michal.winiarski@intel.com>
>> Assisted-by: Claude:claude-opus-4.6
>> Signed-off-by: Shuicheng Lin <shuicheng.lin@intel.com>
>> ---
>>   drivers/gpu/drm/xe/xe_hw_engine.c | 4 +---
>>   1 file changed, 1 insertion(+), 3 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c 
>> b/drivers/gpu/drm/xe/xe_hw_engine.c
>> index 2f9c1c063f16..b69e6c9e534e 100644
>> --- a/drivers/gpu/drm/xe/xe_hw_engine.c
>> +++ b/drivers/gpu/drm/xe/xe_hw_engine.c
>> @@ -629,7 +629,7 @@ static int hw_engine_init(struct xe_gt *gt, 
>> struct xe_hw_engine *hwe,
>>           hwe->exl_port = xe_execlist_port_create(xe, hwe);
>>           if (IS_ERR(hwe->exl_port)) {
>>               err = PTR_ERR(hwe->exl_port);
>> -            goto err_hwsp;
>> +            goto err_name;
>>           }
>>       } else {
>>           /* GSCCS has a special interrupt for reset */
>> @@ -649,8 +649,6 @@ static int hw_engine_init(struct xe_gt *gt, 
>> struct xe_hw_engine *hwe,
>>         return devm_add_action_or_reset(xe->drm.dev, hw_engine_fini, 
>> hwe);
>>   -err_hwsp:
>> -    xe_bo_unpin_map_no_vm(hwe->hwsp);
> Shall we keep err_hwsp?

My bad, the patch is correct here.

LGTM

Reviewed-by: Zongyao Bai <zongyao.bai@intel.com>

>>   err_name:
>>       hwe->name = NULL;

^ permalink raw reply

* Re: [PATCH v2] drm/xe/tests/rtp: Add kunit test for whitelist upper bounds
From: Gustavo Sousa @ 2026-06-26 18:04 UTC (permalink / raw)
  To: Matt Roper, intel-xe; +Cc: Matt Roper
In-Reply-To: <20260626-kunit_whitelist_bounds-v2-1-223dc3699734@intel.com>

Matt Roper <matthew.d.roper@intel.com> writes:

> Xe must only add registers to the GT whitelist if they are listed in the
> "Software Allowlist" section of the bspec.  These registers have been
> carefully reviewed by the architecture/security teams to ensure that
> they are safe to whitelist from a security perspective.  The list of
> allowed registers changes from platform to platform, and it is not safe
> to assume that a register is safe to whitelist on a new platform/IP just
> because it was whitelisted on older ones.  This means that whitelist
> entries in the driver that used undefined upper bounds
> (XE_RTP_END_VERSION_UNDEFINED) for their version ranges should always be
> considered illegal since they could potentially open unexpected security
> holes on future platforms.  Add a kunit test to scan the whitelist RTP
> table and ensure that all entries have well-defined upper bounds on IP
> version ranges.
>
> Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
> ---
> Changes in v2:
> - Add missing EXPORT_SYMBOL_IF_KUNIT(register_whitelist)
> - Link to v1: https://lore.kernel.org/r/20260625-kunit_whitelist_bounds-v1-1-d8f5f055f1f0@intel.com
> ---
>  drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c | 20 ++++++++++++++++++++
>  drivers/gpu/drm/xe/xe_reg_whitelist.c         |  5 ++++-
>  drivers/gpu/drm/xe/xe_reg_whitelist.h         |  4 ++++
>  3 files changed, 28 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c
> index ef379cbb6a86..72ae1c13ad72 100644
> --- a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c
> +++ b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c
> @@ -5,6 +5,7 @@
>  
>  #include <kunit/test.h>
>  
> +#include "xe_reg_whitelist.h"
>  #include "xe_rtp_types.h"
>  #include "xe_tuning.h"
>  #include "xe_wa.h"
> @@ -75,11 +76,30 @@ static void xe_rtp_table_dev_oob_test(struct kunit *test)
>  
>  RTP_TABLE_PARAM(device_oob_was);
>  
> +static void xe_rtp_table_missing_upper_bound_test(struct kunit *test)
> +{
> +	const struct xe_rtp_entry_sr *entry = test->param_value;
> +
> +	for (int i = 0; i < entry->n_rules; i++) {
> +		u8 match_type = entry->rules[i].match_type;
> +
> +		if (match_type != XE_RTP_MATCH_GRAPHICS_VERSION_RANGE &&
> +		    match_type != XE_RTP_MATCH_MEDIA_VERSION_RANGE)
> +			continue;
> +
> +		KUNIT_EXPECT_NE(test, entry->rules[i].ver_end, XE_RTP_END_VERSION_UNDEFINED);

I wonder if it would be more informative to embed the relevant match
types in the expectation:

  KUNIT_EXPECT_FALSE(test, match_type == XE_RTP_MATCH_GRAPHICS_VERSION_RANGE &&
                     ver_end == XE_RTP_END_VERSION_UNDEFINED);
  KUNIT_EXPECT_FALSE(test, match_type == XE_RTP_MATCH_MEDIA_VERSION_RANGE &&
                     ver_end == XE_RTP_END_VERSION_UNDEFINED);

This would make it easy to see in the output of a failed test that
XE_RTP_END_VERSION_UNDEFINED should not be used for those match types.

Your call.

Reviewed-by: Gustavo Sousa <gustavo.sousa@intel.com>


> +	}
> +}
> +
> +RTP_TABLE_PARAM(register_whitelist);
> +
>  static struct kunit_case xe_rtp_table_tests[] = {
>  	KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_was_gen_params),
>  	KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_tunings_gen_params),
>  	KUNIT_CASE_PARAM(xe_rtp_table_oob_test, oob_was_gen_params),
>  	KUNIT_CASE_PARAM(xe_rtp_table_dev_oob_test, device_oob_was_gen_params),
> +	KUNIT_CASE_PARAM(xe_rtp_table_missing_upper_bound_test,
> +			 register_whitelist_gen_params),
>  	{}
>  };
>  
> diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c
> index 3d9e3daab01a..fe996d23007b 100644
> --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c
> +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c
> @@ -5,6 +5,8 @@
>  
>  #include "xe_reg_whitelist.h"
>  
> +#include <kunit/visibility.h>
> +
>  #include "regs/xe_engine_regs.h"
>  #include "regs/xe_gt_regs.h"
>  #include "regs/xe_oa_regs.h"
> @@ -41,7 +43,7 @@ static bool match_multi_queue_class(const struct xe_device *xe,
>  	return xe_gt_supports_multi_queue(gt, hwe->class);
>  }
>  
> -static const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR(
> +VISIBLE_IF_KUNIT const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR(
>  	{ XE_RTP_NAME("WaAllowPMDepthAndInvocationCountAccessFromUMD, 1408556865"),
>  	  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210), ENGINE_CLASS(RENDER)),
>  	  XE_RTP_ACTIONS(WHITELIST(PS_INVOCATION_COUNT,
> @@ -104,6 +106,7 @@ static const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR(
>  				   RING_FORCE_TO_NONPRIV_ACCESS_RW))
>  	},
>  );
> +EXPORT_SYMBOL_IF_KUNIT(register_whitelist);
>  
>  static const struct xe_rtp_table_sr oa_whitelist = XE_RTP_TABLE_SR(
>  
> diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.h b/drivers/gpu/drm/xe/xe_reg_whitelist.h
> index e1eb1b7d5480..c0248063d515 100644
> --- a/drivers/gpu/drm/xe/xe_reg_whitelist.h
> +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.h
> @@ -14,6 +14,10 @@ struct xe_hw_engine;
>  struct xe_reg_sr;
>  struct xe_reg_sr_entry;
>  
> +#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
> +extern const struct xe_rtp_table_sr register_whitelist;
> +#endif
> +
>  void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe);
>  
>  void xe_reg_whitelist_oa_regs(struct xe_gt *gt);
>
> ---
> base-commit: c04e038b8787434bf489ea6de4ab2e2d936083c7
> change-id: 20260625-kunit_whitelist_bounds-a88495e5cc7b
>
> Best regards,
> -- 
> Matt Roper
> Graphics Software Engineer
> Linux GPU Platform Enablement
> Intel Corporation

^ permalink raw reply

* Re: [PATCH 2/2] drm/xe/hw_engine: Fix double-free of managed BO in error path
From: Bai, Zongyao @ 2026-06-26 17:34 UTC (permalink / raw)
  To: Shuicheng Lin, intel-xe; +Cc: Michał Winiarski
In-Reply-To: <20260417161901.3416021-3-shuicheng.lin@intel.com>


On 4/17/2026 9:19 AM, Shuicheng Lin wrote:
> The error path in hw_engine_init() explicitly frees a BO allocated
> with xe_managed_bo_create_pin_map() via xe_bo_unpin_map_no_vm().
> Since the managed BO already has a devm cleanup action registered,
> this causes a double-free when devm unwinds during probe failure.
>
> Remove the explicit free and let devm handle it, consistent with
> all other xe_managed_bo_create_pin_map() callers.
>
> Fixes: 23e939bc8f56 ("drm/xe: Add a helper for DRM device-lifetime BO create")
> Cc: Michał Winiarski <michal.winiarski@intel.com>
> Assisted-by: Claude:claude-opus-4.6
> Signed-off-by: Shuicheng Lin <shuicheng.lin@intel.com>
> ---
>   drivers/gpu/drm/xe/xe_hw_engine.c | 4 +---
>   1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c
> index 2f9c1c063f16..b69e6c9e534e 100644
> --- a/drivers/gpu/drm/xe/xe_hw_engine.c
> +++ b/drivers/gpu/drm/xe/xe_hw_engine.c
> @@ -629,7 +629,7 @@ static int hw_engine_init(struct xe_gt *gt, struct xe_hw_engine *hwe,
>   		hwe->exl_port = xe_execlist_port_create(xe, hwe);
>   		if (IS_ERR(hwe->exl_port)) {
>   			err = PTR_ERR(hwe->exl_port);
> -			goto err_hwsp;
> +			goto err_name;
>   		}
>   	} else {
>   		/* GSCCS has a special interrupt for reset */
> @@ -649,8 +649,6 @@ static int hw_engine_init(struct xe_gt *gt, struct xe_hw_engine *hwe,
>   
>   	return devm_add_action_or_reset(xe->drm.dev, hw_engine_fini, hwe);
>   
> -err_hwsp:
> -	xe_bo_unpin_map_no_vm(hwe->hwsp);
Shall we keep err_hwsp?
>   err_name:
>   	hwe->name = NULL;
>   

^ permalink raw reply

* Re: [PATCH v2 1/4] drm/xe/oa: Rename last argument of WHITELIST_OA_MMIO_TRG
From: Matt Roper @ 2026-06-26 16:39 UTC (permalink / raw)
  To: Ashutosh Dixit; +Cc: intel-xe, Umesh Nerlige Ramappa
In-Reply-To: <20260617015422.226177-2-ashutosh.dixit@intel.com>

On Tue, Jun 16, 2026 at 06:54:19PM -0700, Ashutosh Dixit wrote:
> OA head pointer registers are not used by UMD's and do not need to be
> whitelisted, the last argument of WHITELIST_OA_MMIO_TRG is actually used
> for whitelisting tail pointer and OA buffer registers. Rename the argument
> to tail_buf to reflect this. OA head pointer is sometimes provided to the
> WHITELIST_OA_MMIO_TRG to have the correct register offset alignment (16)
> for RING_FORCE_TO_NONPRIV_RANGE_4.

I think the proper fix here is to get rid of RANGE_4.  We should only be
using that in cases where we definitely have four consecutive registers
that _all_ need the be accessed by userspace and that are documented as
okay to whitelist in the specs.  If userspace only has a need for two
consecutive registers, there's no reason to be using RANGE_4.  Granting
userspace access to two extra unnecessary registers is a DRM uapi
violation (and also a potential security risk depending on what the
extra two registers wind up being).


Matt

> 
> Fixes: ed455775c5a6 ("drm/xe/rtp: Refactor OAG MMIO trigger register whitelisting")
> Signed-off-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
> ---
>  drivers/gpu/drm/xe/xe_reg_whitelist.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c
> index 2e84b1c49f374..a17ebacc1455b 100644
> --- a/drivers/gpu/drm/xe/xe_reg_whitelist.c
> +++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c
> @@ -104,10 +104,10 @@ static const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR(
>  				   RING_FORCE_TO_NONPRIV_ACCESS_RW))
>  	},
>  
> -#define WHITELIST_OA_MMIO_TRG(trg, status, head) \
> +#define WHITELIST_OA_MMIO_TRG(trg, status, tail_buf) \
>  	WHITELIST(trg, RING_FORCE_TO_NONPRIV_ACCESS_RW), \
>  	WHITELIST(status, RING_FORCE_TO_NONPRIV_ACCESS_RD), \
> -	WHITELIST(head, RING_FORCE_TO_NONPRIV_ACCESS_RD | RING_FORCE_TO_NONPRIV_RANGE_4)
> +	WHITELIST(tail_buf, RING_FORCE_TO_NONPRIV_ACCESS_RD | RING_FORCE_TO_NONPRIV_RANGE_4)
>  
>  #define WHITELIST_OAG_MMIO_TRG \
>  	WHITELIST_OA_MMIO_TRG(OAG_MMIOTRIGGER, OAG_OASTATUS, OAG_OAHEADPTR)
> -- 
> 2.54.0
> 

-- 
Matt Roper
Graphics Software Engineer
Linux GPU Platform Enablement
Intel Corporation

^ permalink raw reply

* Re: ✗ Xe.CI.FULL: failure for drm/xe: Use GuC fw 70.70.0 for pre-release platforms.
From: Julia Filipchuk @ 2026-06-26 16:36 UTC (permalink / raw)
  To: intel-xe
In-Reply-To: <178184697743.95114.14190693574122170221@6beec6c84f66>

Failure unrelated to patch.

On 6/18/2026 10:29 PM, Patchwork wrote:
>   * igt@kms_chamelium_color_pipeline@plane-ctm3x4-lut1d:
>     - shard-lnl:          NOTRUN -> [SKIP][1] +8 other tests skip
>    [1]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-168820v1/shard-lnl-6/igt@kms_chamelium_color_pipeline@plane-ctm3x4-lut1d.html
> 
>   * igt@kms_chamelium_color_pipeline@plane-lut1d-lut1d:
>     - shard-bmg:          NOTRUN -> [SKIP][2] +8 other tests skip
>    [2]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-168820v1/shard-bmg-2/igt@kms_chamelium_color_pipeline@plane-lut1d-lut1d.html

^ permalink raw reply

* [PATCH v2] drm/xe/tests/rtp: Add kunit test for whitelist upper bounds
From: Matt Roper @ 2026-06-26 16:18 UTC (permalink / raw)
  To: intel-xe; +Cc: Matt Roper

Xe must only add registers to the GT whitelist if they are listed in the
"Software Allowlist" section of the bspec.  These registers have been
carefully reviewed by the architecture/security teams to ensure that
they are safe to whitelist from a security perspective.  The list of
allowed registers changes from platform to platform, and it is not safe
to assume that a register is safe to whitelist on a new platform/IP just
because it was whitelisted on older ones.  This means that whitelist
entries in the driver that used undefined upper bounds
(XE_RTP_END_VERSION_UNDEFINED) for their version ranges should always be
considered illegal since they could potentially open unexpected security
holes on future platforms.  Add a kunit test to scan the whitelist RTP
table and ensure that all entries have well-defined upper bounds on IP
version ranges.

Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
Changes in v2:
- Add missing EXPORT_SYMBOL_IF_KUNIT(register_whitelist)
- Link to v1: https://lore.kernel.org/r/20260625-kunit_whitelist_bounds-v1-1-d8f5f055f1f0@intel.com
---
 drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c | 20 ++++++++++++++++++++
 drivers/gpu/drm/xe/xe_reg_whitelist.c         |  5 ++++-
 drivers/gpu/drm/xe/xe_reg_whitelist.h         |  4 ++++
 3 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c
index ef379cbb6a86..72ae1c13ad72 100644
--- a/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c
+++ b/drivers/gpu/drm/xe/tests/xe_rtp_tables_test.c
@@ -5,6 +5,7 @@
 
 #include <kunit/test.h>
 
+#include "xe_reg_whitelist.h"
 #include "xe_rtp_types.h"
 #include "xe_tuning.h"
 #include "xe_wa.h"
@@ -75,11 +76,30 @@ static void xe_rtp_table_dev_oob_test(struct kunit *test)
 
 RTP_TABLE_PARAM(device_oob_was);
 
+static void xe_rtp_table_missing_upper_bound_test(struct kunit *test)
+{
+	const struct xe_rtp_entry_sr *entry = test->param_value;
+
+	for (int i = 0; i < entry->n_rules; i++) {
+		u8 match_type = entry->rules[i].match_type;
+
+		if (match_type != XE_RTP_MATCH_GRAPHICS_VERSION_RANGE &&
+		    match_type != XE_RTP_MATCH_MEDIA_VERSION_RANGE)
+			continue;
+
+		KUNIT_EXPECT_NE(test, entry->rules[i].ver_end, XE_RTP_END_VERSION_UNDEFINED);
+	}
+}
+
+RTP_TABLE_PARAM(register_whitelist);
+
 static struct kunit_case xe_rtp_table_tests[] = {
 	KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_was_gen_params),
 	KUNIT_CASE_PARAM(xe_rtp_table_gt_test, gt_tunings_gen_params),
 	KUNIT_CASE_PARAM(xe_rtp_table_oob_test, oob_was_gen_params),
 	KUNIT_CASE_PARAM(xe_rtp_table_dev_oob_test, device_oob_was_gen_params),
+	KUNIT_CASE_PARAM(xe_rtp_table_missing_upper_bound_test,
+			 register_whitelist_gen_params),
 	{}
 };
 
diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.c b/drivers/gpu/drm/xe/xe_reg_whitelist.c
index 3d9e3daab01a..fe996d23007b 100644
--- a/drivers/gpu/drm/xe/xe_reg_whitelist.c
+++ b/drivers/gpu/drm/xe/xe_reg_whitelist.c
@@ -5,6 +5,8 @@
 
 #include "xe_reg_whitelist.h"
 
+#include <kunit/visibility.h>
+
 #include "regs/xe_engine_regs.h"
 #include "regs/xe_gt_regs.h"
 #include "regs/xe_oa_regs.h"
@@ -41,7 +43,7 @@ static bool match_multi_queue_class(const struct xe_device *xe,
 	return xe_gt_supports_multi_queue(gt, hwe->class);
 }
 
-static const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR(
+VISIBLE_IF_KUNIT const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR(
 	{ XE_RTP_NAME("WaAllowPMDepthAndInvocationCountAccessFromUMD, 1408556865"),
 	  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210), ENGINE_CLASS(RENDER)),
 	  XE_RTP_ACTIONS(WHITELIST(PS_INVOCATION_COUNT,
@@ -104,6 +106,7 @@ static const struct xe_rtp_table_sr register_whitelist = XE_RTP_TABLE_SR(
 				   RING_FORCE_TO_NONPRIV_ACCESS_RW))
 	},
 );
+EXPORT_SYMBOL_IF_KUNIT(register_whitelist);
 
 static const struct xe_rtp_table_sr oa_whitelist = XE_RTP_TABLE_SR(
 
diff --git a/drivers/gpu/drm/xe/xe_reg_whitelist.h b/drivers/gpu/drm/xe/xe_reg_whitelist.h
index e1eb1b7d5480..c0248063d515 100644
--- a/drivers/gpu/drm/xe/xe_reg_whitelist.h
+++ b/drivers/gpu/drm/xe/xe_reg_whitelist.h
@@ -14,6 +14,10 @@ struct xe_hw_engine;
 struct xe_reg_sr;
 struct xe_reg_sr_entry;
 
+#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
+extern const struct xe_rtp_table_sr register_whitelist;
+#endif
+
 void xe_reg_whitelist_process_engine(struct xe_hw_engine *hwe);
 
 void xe_reg_whitelist_oa_regs(struct xe_gt *gt);

---
base-commit: c04e038b8787434bf489ea6de4ab2e2d936083c7
change-id: 20260625-kunit_whitelist_bounds-a88495e5cc7b

Best regards,
-- 
Matt Roper
Graphics Software Engineer
Linux GPU Platform Enablement
Intel Corporation


^ permalink raw reply related

* Re: [PATCH v2] drm/xe/display: consider DPT when WA 22019338487 is active
From: Matthew Auld @ 2026-06-26 15:06 UTC (permalink / raw)
  To: Maarten Lankhorst, intel-xe
  Cc: Thomas Hellström, Matthew Brost, Rodrigo Vivi,
	Nikolay Mikhaylov, Uma Shankar, Jani Nikula, stable
In-Reply-To: <d6d3687d-3635-45c9-b5fc-42106d8e7019@lankhorst.se>

On 26/06/2026 15:53, Maarten Lankhorst wrote:
> Hey,
> 
> On 6/26/26 16:32, Matthew Auld wrote:
>> On 26/06/2026 14:37, Maarten Lankhorst wrote:
>>> Hey,
>>>
>>> On 6/26/26 12:27, Matthew Auld wrote:
>>>> On 23/06/2026 10:01, Matthew Auld wrote:
>>>>> WA 22019338487 (22019338487_display) indicates that stolen memory should
>>>>> not be used for display allocations on affected platforms (like Lunar
>>>>> Lake). In particular we need to be mindful of not hammering stolen over
>>>>> the BAR from the host side, like with issuing many writes.
>>>>>
>>>>> While the fbdev allocation in xe_display_bo.c properly respected this
>>>>> workaround, the Display Page Table (DPT) allocation in xe_fb_pin.c
>>>>> continued to unconditionally attempt to allocate from stolen memory on
>>>>> all integrated GPUs.
>>>>>
>>>>> Check XE_DEVICE_WA(xe, 22019338487_display) before attempting to
>>>>> allocate the DPT from stolen memory. If the workaround applies, skip the
>>>>> stolen allocation attempt and let the driver naturally fall back to
>>>>> allocating from system memory.
>>>>>
>>>>> Without this we will end up hammering stolen when programming the DPT on
>>>>> the host side during the normal operation, which seems to be exactly
>>>>> what the WA wants us to avoid.
>>>>>
>>>>> There are a bunch of users all getting some kind of hard hang in the fb
>>>>> pin programming sequence on LNL, so wondering if this could help there.
>>>>>
>>>>> v2 (Jani):
>>>>>      - Invert the WA check. No functional change.
>>>>>
>>>>> Assisted-by: Gemini:gemini-3.1-pro-preview
>>>>> Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7513
>>>>> Signed-off-by: Matthew Auld <matthew.auld@intel.com>
>>>>> Fixes: 775d0adc01a5 ("drm/xe/fbdev: Limit the usage of stolen for LNL+")
>>>>> Cc: "Thomas Hellström" <thomas.hellstrom@linux.intel.com>
>>>>> Cc: Matthew Brost <matthew.brost@intel.com>
>>>>> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
>>>>> Cc: Nikolay Mikhaylov <sonny@milton.pro>
>>>>> Cc: Uma Shankar <uma.shankar@intel.com>
>>>>> Cc: Jani Nikula <jani.nikula@intel.com>
>>>>> Cc: <stable@vger.kernel.org> # v6.12+
>>>>
>>>> Ping on this? So far two separate users report this fixes the hard machine hang for them, after several days of testing.
>>>
>>> Can we instead disable stolen entirely so we no longer need this workaround?
>>
>> I'm not sure. You mean disable it except for fbc etc ? We just need some patch to disable at least this dpt path on LNL, which is also easy to backport. We can take your patch to disable this completely instead and I guess remove the WA, so long as we can easily backport it. Either way we just need to land a fix for this ASAP.
> 
> There are 3 patches here:
> 1. Disable stolen for newly created framebuffers
> 2. Disable stolen for DPT
> 3. Disable stolen when taking over firmware framebuffers if media_gt exists
> 
> First 2 are always safe to backport, last one would need a more intrusive fix to prevent regressions, like copying the stolen framebuffer to system memory.

Ok. Should we split 1 & 2 into skipping it only for LNL, which we 
backport, and then another patch to remove stolen completely on top, 
which we don't backport, for those usages? Or least I'm not sure if 
there is some good reason why we want to make use of stolen on other 
platforms, so maybe that should be reviewed/handled separately. I know 
for the WA it's bad idea, but for other platforms I'm not sure tbh. 
Probably need to confirm with display folks.

> 
>>>
>>> https://patchwork.freedesktop.org/patch/735208/?series=159035&rev=19
>>> https://patchwork.freedesktop.org/patch/735215/?series=159035&rev=19
>>> https://patchwork.freedesktop.org/patch/735223/?series=159035&rev=19
>>>
>>> Sending a new version soon, I can split out those patches if needed.
>>> Ideally we find a way to preserve the initial framebuffer by blitting
>>> from the DSB FB to a system memory FB, but this may affect module load time.
>>>
>>> Kind regards,
>>> ~Maarten Lankhorst
>>>
>>>> https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7513#note_3537314
>>>>
>>>> https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7513#note_3531435
>>>>
>>>> Looking through the HSD I think it is clear we need something like this for the WA.
>>>>
>>>>> ---
>>>>>     drivers/gpu/drm/xe/display/xe_fb_pin.c | 5 +++++
>>>>>     1 file changed, 5 insertions(+)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/xe/display/xe_fb_pin.c b/drivers/gpu/drm/xe/display/xe_fb_pin.c
>>>>> index f93c98bec5b5..8ebb52741ea6 100644
>>>>> --- a/drivers/gpu/drm/xe/display/xe_fb_pin.c
>>>>> +++ b/drivers/gpu/drm/xe/display/xe_fb_pin.c
>>>>> @@ -20,6 +20,9 @@
>>>>>     #include "xe_pat.h"
>>>>>     #include "xe_pm.h"
>>>>>     #include "xe_vram_types.h"
>>>>> +#include "xe_wa.h"
>>>>> +
>>>>> +#include <generated/xe_device_wa_oob.h>
>>>>>       static void
>>>>>     write_dpt_rotated(struct xe_bo *bo, struct iosys_map *map, u32 *dpt_ofs, u32 bo_ofs,
>>>>> @@ -172,6 +175,8 @@ static int __xe_pin_fb_vma_dpt(struct drm_gem_object *obj,
>>>>>                                XE_BO_FLAG_GGTT |
>>>>>                                XE_BO_FLAG_PAGETABLE,
>>>>>                                pin_params->alignment, false);
>>>>> +    else if (XE_DEVICE_WA(xe, 22019338487_display))
>>>>> +        dpt = ERR_PTR(-ENODEV);
>>>>>         else
>>>>>             dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
>>>>>                                dpt_size,  ~0ull,
>>>>
>>>
>>
> 


^ permalink raw reply

* Re: [PATCH v2] drm/xe/display: consider DPT when WA 22019338487 is active
From: Maarten Lankhorst @ 2026-06-26 14:53 UTC (permalink / raw)
  To: Matthew Auld, intel-xe
  Cc: Thomas Hellström, Matthew Brost, Rodrigo Vivi,
	Nikolay Mikhaylov, Uma Shankar, Jani Nikula, stable
In-Reply-To: <dd6a1825-9c22-4c94-9ab5-7ccd24f96990@intel.com>

Hey,

On 6/26/26 16:32, Matthew Auld wrote:
> On 26/06/2026 14:37, Maarten Lankhorst wrote:
>> Hey,
>>
>> On 6/26/26 12:27, Matthew Auld wrote:
>>> On 23/06/2026 10:01, Matthew Auld wrote:
>>>> WA 22019338487 (22019338487_display) indicates that stolen memory should
>>>> not be used for display allocations on affected platforms (like Lunar
>>>> Lake). In particular we need to be mindful of not hammering stolen over
>>>> the BAR from the host side, like with issuing many writes.
>>>>
>>>> While the fbdev allocation in xe_display_bo.c properly respected this
>>>> workaround, the Display Page Table (DPT) allocation in xe_fb_pin.c
>>>> continued to unconditionally attempt to allocate from stolen memory on
>>>> all integrated GPUs.
>>>>
>>>> Check XE_DEVICE_WA(xe, 22019338487_display) before attempting to
>>>> allocate the DPT from stolen memory. If the workaround applies, skip the
>>>> stolen allocation attempt and let the driver naturally fall back to
>>>> allocating from system memory.
>>>>
>>>> Without this we will end up hammering stolen when programming the DPT on
>>>> the host side during the normal operation, which seems to be exactly
>>>> what the WA wants us to avoid.
>>>>
>>>> There are a bunch of users all getting some kind of hard hang in the fb
>>>> pin programming sequence on LNL, so wondering if this could help there.
>>>>
>>>> v2 (Jani):
>>>>     - Invert the WA check. No functional change.
>>>>
>>>> Assisted-by: Gemini:gemini-3.1-pro-preview
>>>> Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7513
>>>> Signed-off-by: Matthew Auld <matthew.auld@intel.com>
>>>> Fixes: 775d0adc01a5 ("drm/xe/fbdev: Limit the usage of stolen for LNL+")
>>>> Cc: "Thomas Hellström" <thomas.hellstrom@linux.intel.com>
>>>> Cc: Matthew Brost <matthew.brost@intel.com>
>>>> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
>>>> Cc: Nikolay Mikhaylov <sonny@milton.pro>
>>>> Cc: Uma Shankar <uma.shankar@intel.com>
>>>> Cc: Jani Nikula <jani.nikula@intel.com>
>>>> Cc: <stable@vger.kernel.org> # v6.12+
>>>
>>> Ping on this? So far two separate users report this fixes the hard machine hang for them, after several days of testing.
>>
>> Can we instead disable stolen entirely so we no longer need this workaround?
> 
> I'm not sure. You mean disable it except for fbc etc ? We just need some patch to disable at least this dpt path on LNL, which is also easy to backport. We can take your patch to disable this completely instead and I guess remove the WA, so long as we can easily backport it. Either way we just need to land a fix for this ASAP.

There are 3 patches here:
1. Disable stolen for newly created framebuffers
2. Disable stolen for DPT
3. Disable stolen when taking over firmware framebuffers if media_gt exists

First 2 are always safe to backport, last one would need a more intrusive fix to prevent regressions, like copying the stolen framebuffer to system memory.

>>
>> https://patchwork.freedesktop.org/patch/735208/?series=159035&rev=19
>> https://patchwork.freedesktop.org/patch/735215/?series=159035&rev=19
>> https://patchwork.freedesktop.org/patch/735223/?series=159035&rev=19
>>
>> Sending a new version soon, I can split out those patches if needed.
>> Ideally we find a way to preserve the initial framebuffer by blitting
>> from the DSB FB to a system memory FB, but this may affect module load time.
>>
>> Kind regards,
>> ~Maarten Lankhorst
>>
>>> https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7513#note_3537314
>>>
>>> https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7513#note_3531435
>>>
>>> Looking through the HSD I think it is clear we need something like this for the WA.
>>>
>>>> ---
>>>>    drivers/gpu/drm/xe/display/xe_fb_pin.c | 5 +++++
>>>>    1 file changed, 5 insertions(+)
>>>>
>>>> diff --git a/drivers/gpu/drm/xe/display/xe_fb_pin.c b/drivers/gpu/drm/xe/display/xe_fb_pin.c
>>>> index f93c98bec5b5..8ebb52741ea6 100644
>>>> --- a/drivers/gpu/drm/xe/display/xe_fb_pin.c
>>>> +++ b/drivers/gpu/drm/xe/display/xe_fb_pin.c
>>>> @@ -20,6 +20,9 @@
>>>>    #include "xe_pat.h"
>>>>    #include "xe_pm.h"
>>>>    #include "xe_vram_types.h"
>>>> +#include "xe_wa.h"
>>>> +
>>>> +#include <generated/xe_device_wa_oob.h>
>>>>      static void
>>>>    write_dpt_rotated(struct xe_bo *bo, struct iosys_map *map, u32 *dpt_ofs, u32 bo_ofs,
>>>> @@ -172,6 +175,8 @@ static int __xe_pin_fb_vma_dpt(struct drm_gem_object *obj,
>>>>                               XE_BO_FLAG_GGTT |
>>>>                               XE_BO_FLAG_PAGETABLE,
>>>>                               pin_params->alignment, false);
>>>> +    else if (XE_DEVICE_WA(xe, 22019338487_display))
>>>> +        dpt = ERR_PTR(-ENODEV);
>>>>        else
>>>>            dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
>>>>                               dpt_size,  ~0ull,
>>>
>>
> 


^ permalink raw reply

* Re: [PATCH v2] drm/xe/display: consider DPT when WA 22019338487 is active
From: Matthew Auld @ 2026-06-26 14:32 UTC (permalink / raw)
  To: Maarten Lankhorst, intel-xe
  Cc: Thomas Hellström, Matthew Brost, Rodrigo Vivi,
	Nikolay Mikhaylov, Uma Shankar, Jani Nikula, stable
In-Reply-To: <9924291e-5108-41b3-9131-12b292e8bcd2@lankhorst.se>

On 26/06/2026 14:37, Maarten Lankhorst wrote:
> Hey,
> 
> On 6/26/26 12:27, Matthew Auld wrote:
>> On 23/06/2026 10:01, Matthew Auld wrote:
>>> WA 22019338487 (22019338487_display) indicates that stolen memory should
>>> not be used for display allocations on affected platforms (like Lunar
>>> Lake). In particular we need to be mindful of not hammering stolen over
>>> the BAR from the host side, like with issuing many writes.
>>>
>>> While the fbdev allocation in xe_display_bo.c properly respected this
>>> workaround, the Display Page Table (DPT) allocation in xe_fb_pin.c
>>> continued to unconditionally attempt to allocate from stolen memory on
>>> all integrated GPUs.
>>>
>>> Check XE_DEVICE_WA(xe, 22019338487_display) before attempting to
>>> allocate the DPT from stolen memory. If the workaround applies, skip the
>>> stolen allocation attempt and let the driver naturally fall back to
>>> allocating from system memory.
>>>
>>> Without this we will end up hammering stolen when programming the DPT on
>>> the host side during the normal operation, which seems to be exactly
>>> what the WA wants us to avoid.
>>>
>>> There are a bunch of users all getting some kind of hard hang in the fb
>>> pin programming sequence on LNL, so wondering if this could help there.
>>>
>>> v2 (Jani):
>>>     - Invert the WA check. No functional change.
>>>
>>> Assisted-by: Gemini:gemini-3.1-pro-preview
>>> Link: https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7513
>>> Signed-off-by: Matthew Auld <matthew.auld@intel.com>
>>> Fixes: 775d0adc01a5 ("drm/xe/fbdev: Limit the usage of stolen for LNL+")
>>> Cc: "Thomas Hellström" <thomas.hellstrom@linux.intel.com>
>>> Cc: Matthew Brost <matthew.brost@intel.com>
>>> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
>>> Cc: Nikolay Mikhaylov <sonny@milton.pro>
>>> Cc: Uma Shankar <uma.shankar@intel.com>
>>> Cc: Jani Nikula <jani.nikula@intel.com>
>>> Cc: <stable@vger.kernel.org> # v6.12+
>>
>> Ping on this? So far two separate users report this fixes the hard machine hang for them, after several days of testing.
> 
> Can we instead disable stolen entirely so we no longer need this workaround?

I'm not sure. You mean disable it except for fbc etc ? We just need some 
patch to disable at least this dpt path on LNL, which is also easy to 
backport. We can take your patch to disable this completely instead and 
I guess remove the WA, so long as we can easily backport it. Either way 
we just need to land a fix for this ASAP.

> 
> https://patchwork.freedesktop.org/patch/735208/?series=159035&rev=19
> https://patchwork.freedesktop.org/patch/735215/?series=159035&rev=19
> https://patchwork.freedesktop.org/patch/735223/?series=159035&rev=19
> 
> Sending a new version soon, I can split out those patches if needed.
> Ideally we find a way to preserve the initial framebuffer by blitting
> from the DSB FB to a system memory FB, but this may affect module load time.
> 
> Kind regards,
> ~Maarten Lankhorst
> 
>> https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7513#note_3537314
>>
>> https://gitlab.freedesktop.org/drm/xe/kernel/-/work_items/7513#note_3531435
>>
>> Looking through the HSD I think it is clear we need something like this for the WA.
>>
>>> ---
>>>    drivers/gpu/drm/xe/display/xe_fb_pin.c | 5 +++++
>>>    1 file changed, 5 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/xe/display/xe_fb_pin.c b/drivers/gpu/drm/xe/display/xe_fb_pin.c
>>> index f93c98bec5b5..8ebb52741ea6 100644
>>> --- a/drivers/gpu/drm/xe/display/xe_fb_pin.c
>>> +++ b/drivers/gpu/drm/xe/display/xe_fb_pin.c
>>> @@ -20,6 +20,9 @@
>>>    #include "xe_pat.h"
>>>    #include "xe_pm.h"
>>>    #include "xe_vram_types.h"
>>> +#include "xe_wa.h"
>>> +
>>> +#include <generated/xe_device_wa_oob.h>
>>>      static void
>>>    write_dpt_rotated(struct xe_bo *bo, struct iosys_map *map, u32 *dpt_ofs, u32 bo_ofs,
>>> @@ -172,6 +175,8 @@ static int __xe_pin_fb_vma_dpt(struct drm_gem_object *obj,
>>>                               XE_BO_FLAG_GGTT |
>>>                               XE_BO_FLAG_PAGETABLE,
>>>                               pin_params->alignment, false);
>>> +    else if (XE_DEVICE_WA(xe, 22019338487_display))
>>> +        dpt = ERR_PTR(-ENODEV);
>>>        else
>>>            dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
>>>                               dpt_size,  ~0ull,
>>
> 


^ permalink raw reply

* Re: [PATCH] drm/i915/vrr: require valid min/max vfreq for VRR
From: Jani Nikula @ 2026-06-26 14:05 UTC (permalink / raw)
  To: Ville Syrjälä
  Cc: intel-gfx, intel-xe, Martin Hodo, stable, Ankit Nautiyal
In-Reply-To: <aj6BTiskgYhSUGYd@intel.com>

On Fri, 26 Jun 2026, Ville Syrjälä <ville.syrjala@linux.intel.com> wrote:
> On Thu, Jun 25, 2026 at 04:10:40PM +0300, Jani Nikula wrote:
>> Ensure the EDID provided min/max vfreq are valid. Most scenarios are
>> already covered (by coincidence) through the checks in
>> intel_vrr_is_capable() and intel_vrr_is_in_range(), but be more explicit
>> about it. At worst, a zero min_vfreq could lead to a division by zero in
>> intel_vrr_compute_vmax().
>> 
>> Discovered using AI-assisted static analysis confirmed by Intel Product
>> Security.
>> 
>> Reported-by: Martin Hodo <martin.hodo@intel.com>
>> Fixes: 117cd09ba528 ("drm/i915/display/dp: Compute VRR state in atomic_check")
>> Cc: <stable@vger.kernel.org> # v5.12+
>> Cc: Ankit Nautiyal <ankit.k.nautiyal@intel.com>
>> Signed-off-by: Jani Nikula <jani.nikula@intel.com>
>> ---
>>  drivers/gpu/drm/i915/display/intel_vrr.c | 4 ++++
>>  1 file changed, 4 insertions(+)
>> 
>> diff --git a/drivers/gpu/drm/i915/display/intel_vrr.c b/drivers/gpu/drm/i915/display/intel_vrr.c
>> index 5d9b11185296..bffbdee76ee1 100644
>> --- a/drivers/gpu/drm/i915/display/intel_vrr.c
>> +++ b/drivers/gpu/drm/i915/display/intel_vrr.c
>> @@ -76,6 +76,10 @@ bool intel_vrr_is_capable(struct intel_connector *connector)
>>  		return false;
>>  	}
>>  
>> +	if (!info->monitor_range.min_vfreq || !info->monitor_range.max_vfreq ||
>> +	    info->monitor_range.min_vfreq > info->monitor_range.max_vfreq)
>> +		return false;
>
> Perhaps it should be the responsibility of the EDID parser to make sure
> the range isn't completely insane?

The min_vfreq/max_vfreq may be 0 if the EDID doesn't have the info, and
if the EDID has bogus info, leaving them to 0 is pretty much the only
thing we can do.

Since we need the !0 check here anyway, I decided to start off with
this.

BR,
Jani.

>
>> +
>>  	return info->monitor_range.max_vfreq - info->monitor_range.min_vfreq > 10;
>
> I've been tempted to get rid of this completely arbitrary 10Hz thing as well.
>
>>  }
>>  
>> -- 
>> 2.47.3

-- 
Jani Nikula, Intel

^ permalink raw reply

* [PATCH v2] drm/i915/bios: range check LFP Data Block panel_type2
From: Jani Nikula @ 2026-06-26 14:01 UTC (permalink / raw)
  To: Jani Nikula, intel-gfx, intel-xe
  Cc: Martin Hodo, stable, Animesh Manna, Ville Syrjälä,
	Michał Grzelak
In-Reply-To: <20260625135130.1067872-1-jani.nikula@intel.com>

While the panel_type from LFP Data Block is range checked, panel_type2
is not. Add a few helpers for range checking, and use them to not only
check panel_type2, but also improve clarity and correctness in the panel
type selection.

Discovered using AI-assisted static analysis confirmed by Intel Product
Security.

v2:
- Fix commit message typo (Michał)
- Add is_panel_type_pnp() (Ville)

Reported-by: Martin Hodo <martin.hodo@intel.com>
Fixes: 6434cf630086 ("drm/i915/bios: calculate panel type as per child device index in VBT")
Cc: <stable@vger.kernel.org> # v6.0+
Cc: Animesh Manna <animesh.manna@intel.com>
Cc: Ville Syrjälä <ville.syrjala@intel.com>
Reviewed-by: Michał Grzelak <michal.grzelak@intel.com> # v1
Signed-off-by: Jani Nikula <jani.nikula@intel.com>
---
 drivers/gpu/drm/i915/display/intel_bios.c | 36 ++++++++++++++++++-----
 1 file changed, 28 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c
index 15ebadc72b88..97cbae2e547e 100644
--- a/drivers/gpu/drm/i915/display/intel_bios.c
+++ b/drivers/gpu/drm/i915/display/intel_bios.c
@@ -623,6 +623,21 @@ get_lfp_data_tail(const struct bdb_lfp_data *data,
 		return NULL;
 }
 
+static bool is_panel_type_valid(int panel_type)
+{
+	return panel_type >= 0 && panel_type < 16;
+}
+
+static bool is_panel_type_pnp(int panel_type)
+{
+	return panel_type == 0xff;
+}
+
+static bool is_panel_type_valid_or_pnp(int panel_type)
+{
+	return is_panel_type_valid(panel_type) || is_panel_type_pnp(panel_type);
+}
+
 static int opregion_get_panel_type(struct intel_display *display,
 				   const struct intel_bios_encoder_data *devdata,
 				   const struct drm_edid *drm_edid, bool use_fallback)
@@ -640,15 +655,21 @@ static int vbt_get_panel_type(struct intel_display *display,
 	if (!lfp_options)
 		return -1;
 
-	if (lfp_options->panel_type > 0xf &&
-	    lfp_options->panel_type != 0xff) {
+	if (!is_panel_type_valid_or_pnp(lfp_options->panel_type)) {
 		drm_dbg_kms(display->drm, "Invalid VBT panel type 0x%x\n",
 			    lfp_options->panel_type);
 		return -1;
 	}
 
-	if (devdata && devdata->child.handle == DEVICE_HANDLE_LFP2)
+	if (devdata && devdata->child.handle == DEVICE_HANDLE_LFP2) {
+		if (!is_panel_type_valid_or_pnp(lfp_options->panel_type2)) {
+			drm_dbg_kms(display->drm, "Invalid VBT panel type 2 0x%x\n",
+				    lfp_options->panel_type2);
+			return -1;
+		}
+
 		return lfp_options->panel_type2;
+	}
 
 	drm_WARN_ON(display->drm,
 		    devdata && devdata->child.handle != DEVICE_HANDLE_LFP1);
@@ -762,13 +783,12 @@ static int get_panel_type(struct intel_display *display,
 				    panel_types[i].name, panel_types[i].panel_type);
 	}
 
-	if (panel_types[PANEL_TYPE_OPREGION].panel_type >= 0)
+	if (is_panel_type_valid(panel_types[PANEL_TYPE_OPREGION].panel_type))
 		i = PANEL_TYPE_OPREGION;
-	else if (panel_types[PANEL_TYPE_VBT].panel_type == 0xff &&
-		 panel_types[PANEL_TYPE_PNPID].panel_type >= 0)
+	else if (is_panel_type_pnp(panel_types[PANEL_TYPE_VBT].panel_type) &&
+		 is_panel_type_valid(panel_types[PANEL_TYPE_PNPID].panel_type))
 		i = PANEL_TYPE_PNPID;
-	else if (panel_types[PANEL_TYPE_VBT].panel_type != 0xff &&
-		 panel_types[PANEL_TYPE_VBT].panel_type >= 0)
+	else if (is_panel_type_valid(panel_types[PANEL_TYPE_VBT].panel_type))
 		i = PANEL_TYPE_VBT;
 	else
 		i = PANEL_TYPE_FALLBACK;
-- 
2.47.3


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox