All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 4/9] drm/xe/hwmon: expose pwm[1-3]
  2026-10-15 19:01 [PATCH v3 0/9] " Karthik Poosa
@ 2026-10-15 19:01 ` Karthik Poosa
  0 siblings, 0 replies; 26+ messages in thread
From: Karthik Poosa @ 2026-10-15 19:01 UTC (permalink / raw)
  To: intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi, soham.purkait,
	ravi.kishore.koppuravuri, Karthik Poosa

Expose pwm[1-3] fan duty attributes through hwmon.

This enables reading and writing user PWM values (0..255) for each
available fan channel.

Update Xe hwmon ABI documentation for pwm[1-3].

This sysfs node can be used for manual control of fan speed,
irrespective of fan curve.

v2:
 - Use xe helpers for dmesg logs.
 - Avoid using hwmon->num_fans to get fan count in
   xe_hwmon_pwm_is_visible().

v3:
 - Set PWM directly through the user table; avoid initializing it from the
   stock table. (Soham)
 - Move the unused xe_hwmon_activate_user_fan_table() to the subsequent
   patch.
 - Fail pwmN reads when no value has been written, rather than activating
   the user table from the stock table.
 - Define MIN_FAN_CONTROL_POINTS as 2.
 - Use MIN_FAN_CONTROL_POINTS for PWM configuration. (Soham)
 - Use batched writes for configuring fan control points when setting pwmN.
 - Add and rephrase couple debug logs.
 - Update the hwmon documentation.

Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
Assisted-by: LLM
---
 .../ABI/testing/sysfs-driver-intel-xe-hwmon   |   9 +
 drivers/gpu/drm/xe/xe_hwmon.c                 | 170 ++++++++++++++++++
 drivers/gpu/drm/xe/xe_pcode_api.h             |   3 +
 3 files changed, 182 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
index 5ee68aefa485..ce17e9ca3ed8 100644
--- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
+++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
@@ -321,3 +321,12 @@ Description:	RW. Package burst power limit interval (Tau in PL2/Tau) in
 		milliseconds over which sustained power is averaged.
 
 		Only supported for particular Intel Xe graphics platforms.
+
+What:           /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/pwm[1-3]
+Date:           October 2026
+KernelVersion:  7.3
+Contact:        intel-xe@lists.freedesktop.org
+Description:    RW. Target fan PWM duty value in the range 0..255. 0 is zero
+                fan speed and 255 is 100% fan speed.
+
+                Only supported for particular Intel Xe graphics platforms.
diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
index 32016c5d4770..a86ed741feb3 100644
--- a/drivers/gpu/drm/xe/xe_hwmon.c
+++ b/drivers/gpu/drm/xe/xe_hwmon.c
@@ -8,6 +8,7 @@
 #include <linux/jiffies.h>
 #include <linux/types.h>
 #include <linux/units.h>
+#include <linux/delay.h>
 
 #include <drm/drm_managed.h>
 #include "regs/xe_gt_regs.h"
@@ -153,6 +154,9 @@ enum fan_table_type {
 /* Maximum number of fan control points supported by each fan. */
 #define MAX_FAN_CONTROL_POINTS	(10)
 
+/* Minimum number of points required for a user fan table. */
+#define MIN_FAN_CONTROL_POINTS  (2)
+
 /* Fan control point index: bit31 selects fan table type; bits30:0 control point index. */
 #define FCP_INDEX(FAN_TABLE_TYPE, POINT_NUM) (((FAN_TABLE_TYPE) << 31) | \
 						((POINT_NUM) & REG_GENMASK(30, 0)))
@@ -913,6 +917,7 @@ static const struct hwmon_channel_info * const hwmon_info[] = {
 	HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT | HWMON_E_LABEL, HWMON_E_INPUT | HWMON_E_LABEL),
 	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_MAX, HWMON_F_INPUT | HWMON_F_MAX,
 			   HWMON_F_INPUT | HWMON_F_MAX),
+	HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT, HWMON_PWM_INPUT, HWMON_PWM_INPUT),
 	NULL
 };
 
@@ -1154,6 +1159,89 @@ static int xe_hwmon_get_fan_enable_mask(struct xe_hwmon *hwmon)
 	return 0;
 }
 
+static int xe_hwmon_get_fan_point_count(struct xe_hwmon *hwmon, u8 fan, u32 *point_count,
+					enum fan_table_type table_type)
+{
+	int ret;
+
+	ret = xe_hwmon_pcode_read_fan_control(hwmon,
+					      (table_type == USER_FAN_TABLE) ?
+					      FSC_READ_USER_FAN_CONTROL_POINTS :
+					      FSC_READ_STOCK_FAN_CONTROL_POINTS,
+					      fan, point_count);
+	if (ret) {
+		xe_err(hwmon->xe, "failed to read fan %d %s point count, ret=%d\n", fan,
+		       (table_type == USER_FAN_TABLE) ? "user" : "stock", ret);
+		return ret;
+	}
+
+	if (*point_count > MAX_FAN_CONTROL_POINTS) {
+		xe_err(hwmon->xe, "fan %d %s point count %u exceeds max %u\n", fan,
+		       (table_type == USER_FAN_TABLE) ? "user" : "stock", *point_count,
+		       MAX_FAN_CONTROL_POINTS);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Temperature to set when setting the fan PWM with pwmN. */
+#define FIXED_PWM_TEMP	(1)
+
+static int xe_hwmon_set_user_fan_pwm(struct xe_hwmon *hwmon, u8 fan, u8 pwm)
+{
+	struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
+	struct xe_pcode_write writes[MIN_FAN_CONTROL_POINTS + 1];
+	u32 point_count = 0;
+	u8 clamped_pwm;
+	int ret, i;
+
+	pwm = DIV_ROUND_CLOSEST(pwm * 100, U8_MAX);
+	clamped_pwm = max_t(u8, pwm, min_t(u32, fi->min_pwm, U8_MAX));
+
+	/*
+	 * Set the first fan control point in the user table to the clamped PWM value.
+	 * Use only the first fan control point for setting the PWM value.
+	 */
+
+	for (i = 0; i < MIN_FAN_CONTROL_POINTS; i++) {
+		writes[i].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_FAN_TABLE, fan);
+		writes[i].data = FIELD_PREP(FAN_CONTROL_POINT_TEMP_MASK, FIXED_PWM_TEMP + (i)) |
+					    FIELD_PREP(FAN_CONTROL_POINT_SPEED_MASK, clamped_pwm);
+		xe_dbg(hwmon->xe, "prepared fan control point %d with temp=%d, speed=%u\n", i,
+		       FIXED_PWM_TEMP + (i), clamped_pwm);
+	}
+
+	writes[i].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_NUM_FAN_CONTROL_POINTS, fan);
+	writes[i].data = MIN_FAN_CONTROL_POINTS;
+	ret = xe_pcode_write_batch(xe_device_get_root_tile(hwmon->xe), writes, ARRAY_SIZE(writes));
+	if (ret) {
+		xe_err(hwmon->xe, "failed to write pwm %d for fan %d, ret=%d\n", pwm, fan, ret);
+		return ret;
+	}
+	xe_dbg(hwmon->xe, "applied fixed pwm %u for fan %d\n", clamped_pwm, fan);
+
+	/* Verify if the fan points are set */
+	ret = xe_hwmon_get_fan_point_count(hwmon, fan, &point_count, USER_FAN_TABLE);
+	if (ret && point_count == 0) {
+		xe_err(hwmon->xe, "pwm set verify failed for fan %d, ret=%d, point count=%u\n", fan,
+		       ret, point_count);
+		return ret;
+	}
+
+	/* Update the user fan table cache. */
+	for (i = 0; i < MIN_FAN_CONTROL_POINTS; i++) {
+		fi->fan_table[USER_FAN_TABLE].fcp[i].temp = FIXED_PWM_TEMP + (i);
+		fi->fan_table[USER_FAN_TABLE].fcp[i].speed = clamped_pwm;
+		xe_dbg(hwmon->xe, "fan %d user table cache point %d with temp=%d, speed=%u\n", fan,
+		       i, fi->fan_table[USER_FAN_TABLE].fcp[i].temp,
+			  fi->fan_table[USER_FAN_TABLE].fcp[i].speed);
+	}
+	fi->fan_table[USER_FAN_TABLE].point_count = MIN_FAN_CONTROL_POINTS;
+
+	return 0;
+}
+
 static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
 {
 	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
@@ -1774,6 +1862,20 @@ xe_hwmon_fan_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
 	}
 }
 
+static umode_t
+xe_hwmon_pwm_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
+{
+	if (!hwmon->xe->info.has_fan_control || !IS_FAN_ENABLED(channel))
+		return 0;
+
+	switch (attr) {
+	case hwmon_pwm_input:
+		return 0644;
+	default:
+		return 0;
+	}
+}
+
 static int
 xe_hwmon_fan_input_read(struct xe_hwmon *hwmon, int channel, long *val)
 {
@@ -1828,6 +1930,67 @@ xe_hwmon_fan_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
 	}
 }
 
+static int
+xe_hwmon_pwm_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
+{
+	struct xe_hwmon_fan_info *fi;
+	int ret = 0;
+
+	if (channel < 0 || channel >= FAN_MAX)
+		return -EINVAL;
+
+	mutex_lock(&hwmon->hwmon_lock);
+
+	fi = &hwmon->fi[channel];
+
+	switch (attr) {
+	case hwmon_pwm_input:
+		/* Check if user fan table is set else activate it.*/
+		if (!fi->fan_table[USER_FAN_TABLE].point_count) {
+			xe_warn(hwmon->xe, "pwm not set for fan %d\n", channel);
+			ret = -ENXIO;
+			goto unlock;
+		}
+		*val = DIV_ROUND_CLOSEST(fi->fan_table[USER_FAN_TABLE].fcp[0].speed * U8_MAX, 100);
+		xe_dbg(hwmon->xe, "pwm read for fan %d: %ld\n", channel, *val);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+unlock:
+	mutex_unlock(&hwmon->hwmon_lock);
+	return ret;
+}
+
+static int
+xe_hwmon_pwm_write(struct xe_hwmon *hwmon, u32 attr, int channel, long val)
+{
+	int ret = 0;
+
+	if (channel < 0 || channel >= FAN_MAX)
+		return -EINVAL;
+
+	mutex_lock(&hwmon->hwmon_lock);
+
+	switch (attr) {
+	case hwmon_pwm_input:
+		if (val < 0 || val > U8_MAX) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = xe_hwmon_set_user_fan_pwm(hwmon, channel, (u8)val);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+	mutex_unlock(&hwmon->hwmon_lock);
+
+	return ret;
+}
+
 static umode_t
 xe_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
 		    u32 attr, int channel)
@@ -1854,6 +2017,9 @@ xe_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
 	case hwmon_fan:
 		ret = xe_hwmon_fan_is_visible(hwmon, attr, channel);
 		break;
+	case hwmon_pwm:
+		ret = xe_hwmon_pwm_is_visible(hwmon, attr, channel);
+		break;
 	default:
 		ret = 0;
 		break;
@@ -1883,6 +2049,8 @@ xe_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
 		return xe_hwmon_energy_read(hwmon, attr, channel, val);
 	case hwmon_fan:
 		return xe_hwmon_fan_read(hwmon, attr, channel, val);
+	case hwmon_pwm:
+		return xe_hwmon_pwm_read(hwmon, attr, channel, val);
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -1901,6 +2069,8 @@ xe_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
 		return xe_hwmon_power_write(hwmon, attr, channel, val);
 	case hwmon_curr:
 		return xe_hwmon_curr_write(hwmon, attr, channel, val);
+	case hwmon_pwm:
+		return xe_hwmon_pwm_write(hwmon, attr, channel, val);
 	default:
 		return -EOPNOTSUPP;
 	}
diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h
index 32bac74c4281..80642bee0ac8 100644
--- a/drivers/gpu/drm/xe/xe_pcode_api.h
+++ b/drivers/gpu/drm/xe/xe_pcode_api.h
@@ -82,9 +82,12 @@
 #define     PCODE_MBOX_DOMAIN_HBM		0x2
 
 #define   FAN_SPEED_CONTROL			0x7D
+#define     FSC_WRITE_NUM_FAN_CONTROL_POINTS	0x0
+#define     FSC_WRITE_FAN_TABLE			0x1
 #define     FSC_READ_MAX_FAN_RPS        0x3
 #define     FSC_READ_NUM_FANS			0x4
 #define     FSC_READ_STOCK_FAN_CONTROL_POINTS	0x5
+#define     FSC_READ_USER_FAN_CONTROL_POINTS	0x6
 #define     FSC_READ_FAN_TABLE			0x7
 #define     FAN_CONTROL_POINT_TEMP_MASK		REG_GENMASK(7, 0)
 #define     FAN_CONTROL_POINT_SPEED_MASK	REG_GENMASK(15, 8)
-- 
2.25.1


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

* [PATCH v3 0/9] Add fan control support
@ 2026-10-15 19:07 Karthik Poosa
  2026-10-15 19:07 ` [PATCH v3 1/9] drm/xe/hwmon: initialize fan-control backend and table cache Karthik Poosa
                   ` (12 more replies)
  0 siblings, 13 replies; 26+ messages in thread
From: Karthik Poosa @ 2026-10-15 19:07 UTC (permalink / raw)
  To: intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi, soham.purkait,
	ravi.kishore.koppuravuri, Karthik Poosa

This series adds Intel Xe fan control support through the hwmon sysfs ABI,
including fan maximum reporting, direct PWM control, mode control, and
programmable fan-curve points on supported platforms, BMG as of now.

The patch set is ordered from backend enablement to user-visible controls
and full curve programming support.

Series overview

drm/xe/hwmon: initialize fan-control backend and runtime state
Initializes the fan-control backend and runtime state needed to safely
expose fan controls through hwmon.

drm/xe/hwmon: expose fanN_max
Adds fan maximum RPM reporting through fan1_max, fan2_max, and fan3_max.

drm/xe/hwmon: expose pwm1-3
Adds direct PWM duty control through pwm1-3 with hwmon-compatible 0..255
scaling.

drm/xe/hwmon: expose pwm1-3_enable
Adds PWM mode control through pwm1-3_enable:
0 = full speed
1 = manual user control
2 = firmware automatic control

drm/xe/hwmon: enable fan curve control support
Adds programmable per-fan curve points through:
pwm1-3_auto_point1-10_temp
pwm1-3_auto_point1-10_pwm

ABI updates are included in
Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon, with implementation
in drivers/gpu/drm/xe/xe_hwmon.c.

Sysfs nodes and usage

Read fan speed and max RPM:
cat /sys/class/hwmon/hwmonX/fan1_input
cat /sys/class/hwmon/hwmonX/fan1_max

Set manual mode and direct PWM:
echo 1 > /sys/class/hwmon/hwmonX/pwm1_enable
echo 120 > /sys/class/hwmon/hwmonX/pwm1

Return to firmware automatic control:
echo 2 > /sys/class/hwmon/hwmonX/pwm1_enable

Program a fan curve:
echo 1 > /sys/class/hwmon/hwmonX/pwm1_enable
echo 30000 > /sys/class/hwmon/hwmonX/pwm1_auto_point1_temp
echo 20 > /sys/class/hwmon/hwmonX/pwm1_auto_point1_pwm
...
echo 85000 > /sys/class/hwmon/hwmonX/pwm1_auto_point10_temp
echo 200 > /sys/class/hwmon/hwmonX/pwm1_auto_point10_pwm

Note:

Package temperature (temp2_input) is used as the temperature reference for
fan table control.
For hardware acceptance, fan-curve temperatures must be strictly
increasing.
The user fan table is committed to hardware only after the last curve point
is written.
Fan curve currently supports only 10 fan curve points.

v2:

 - Added kernel-doc for fan control flow and sysfs behavior.
 - Added save/restore support for user fan table across suspend/resume.
 - Added late-binding handling to refresh fan information after late
   binding completes.
 - Preserved user-selected PWM mode across late-binding updates (do not
   force auto mode).
 - Fan curve points show stock table points when pwmX_enable=2.

v3:
 - Address review comments of v2.
 - Add an ordered PCODE write-batch helper for programming fan tables.
 - Support variable fan curve points.
 - Add missing failure checks.
 - Use only 2 fan curve points while setting pwmN.

Karthik Poosa (9):
  drm/xe/hwmon: initialize fan-control backend and table cache
  drm/xe/hwmon: expose fanN_max
  drm/xe/pcode: add ordered write batch helper
  drm/xe/hwmon: expose pwm[1-3]
  drm/xe/hwmon: expose pwm[1-3]_enable
  drm/xe/hwmon: Enable fan curve control support
  drm/xe/hwmon: Add kernel-doc for fan control
  drm/xe/hwmon: preserve fan user table across suspend resume
  drm/xe/hwmon: Update fan info after late binding

 .../ABI/testing/sysfs-driver-intel-xe-hwmon   |   32 +
 drivers/gpu/drm/xe/xe_hwmon.c                 | 1407 ++++++++++++++++-
 drivers/gpu/drm/xe/xe_hwmon.h                 |    6 +
 drivers/gpu/drm/xe/xe_late_bind_fw.c          |    3 +
 drivers/gpu/drm/xe/xe_pcode.c                 |   20 +
 drivers/gpu/drm/xe/xe_pcode.h                 |    7 +
 drivers/gpu/drm/xe/xe_pcode_api.h             |    9 +
 drivers/gpu/drm/xe/xe_pm.c                    |    9 +
 8 files changed, 1478 insertions(+), 15 deletions(-)

-- 
2.25.1


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

* [PATCH v3 1/9] drm/xe/hwmon: initialize fan-control backend and table cache
  2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
@ 2026-10-15 19:07 ` Karthik Poosa
  2026-10-28 18:46   ` Purkait, Soham
  2026-10-15 19:07 ` [PATCH v3 2/9] drm/xe/hwmon: expose fanN_max Karthik Poosa
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 26+ messages in thread
From: Karthik Poosa @ 2026-10-15 19:07 UTC (permalink / raw)
  To: intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi, soham.purkait,
	ravi.kishore.koppuravuri, Karthik Poosa

Initialize Xe hwmon fan-control support by detecting fan count,
reading stock fan control points and min PWM.

v2:
 - Avoid user table initialization during probe. (Badal)
 - Move unused code to appropriate patches.
 - Use xe helpers for dmesg logs.

v3:
 - Rebase.
 - Refine a few debug log messages and comments.
 - Update xe_hwmon_read_fan_control_info() to return on any stock table
   read failures.
 - Avoid returning when num_fans is 0 in
   xe_hwmon_get_preregistration_info(), ensuring thermal mailbox
   initialization is not skipped.
 - Remove XE_PCODE_FAN_CONTROL_TIMEOUT_MS which is unncessary as default
   timeout itself is now 10ms.
 - Use xe_pcode_read() instead of xe_pcode_read_timeout().
 - Rename fan_control_point_count to point_count in struct fan_table.
 - Resolve kgdoc warnings.
 - Add valid check for stock table fan point count.
 - Use the fan-enable bitmap reported by FSC_READ_NUM_FANS when enumerating
   fans. This avoids assuming contiguous fan indices and allows masks with
   gaps to be represented correctly in the hwmon interface.

Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
Assisted-by: LLM
---
 drivers/gpu/drm/xe/xe_hwmon.c     | 167 +++++++++++++++++++++++++++---
 drivers/gpu/drm/xe/xe_pcode_api.h |   5 +
 2 files changed, 157 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
index 42acfeb8818c..f2bd20f8b0a2 100644
--- a/drivers/gpu/drm/xe/xe_hwmon.c
+++ b/drivers/gpu/drm/xe/xe_hwmon.c
@@ -21,6 +21,7 @@
 #include "xe_pcode_api.h"
 #include "xe_sriov.h"
 #include "xe_pm.h"
+#include "xe_printk.h"
 #include "xe_vsec.h"
 #include "regs/xe_pmt.h"
 
@@ -137,14 +138,51 @@ struct xe_hwmon_energy_info {
 	long accum_energy;
 };
 
+enum fan_table_type {
+	/** @STOCK_FAN_TABLE: firmware-provided fan table */
+	STOCK_FAN_TABLE,
+	/** @USER_FAN_TABLE: user fan table written through sysfs */
+	USER_FAN_TABLE,
+	/** @FAN_TABLE_MAX: number of fan tables tracked per fan */
+	FAN_TABLE_MAX,
+};
+
+/* Check if a fan is enabled based on the fan_enable_mask got from FSC_READ_NUM_FANS. */
+#define IS_FAN_ENABLED(fan) (hwmon->fan_enable_mask & BIT(fan))
+
+/* Maximum number of fan control points supported by each fan. */
+#define MAX_FAN_CONTROL_POINTS	(10)
+
+/* Fan control point index: bit31 selects fan table type; bits30:0 control point index. */
+#define FCP_INDEX(FAN_TABLE_TYPE, POINT_NUM) (((FAN_TABLE_TYPE) << 31) | \
+						((POINT_NUM) & REG_GENMASK(30, 0)))
+
 /**
- * struct xe_hwmon_fan_info - to cache previous fan reading
+ * struct xe_hwmon_fan_info - cached fan telemetry and control state
+ *
+ * Each fan keeps the latest tachometer sampling state along with two fan
+ * tables: the stock table discovered from firmware and the user table managed
+ * by hwmon sysfs writes.
  */
 struct xe_hwmon_fan_info {
 	/** @reg_val_prev: previous fan reg val */
 	u32 reg_val_prev;
 	/** @time_prev: previous timestamp */
 	u64 time_prev;
+	/** @fan_table: fan control tables */
+	struct fan_table {
+		/** @point_count: number of fan control points */
+		u8 point_count;
+		/** @fcp: array of fan control points */
+		struct fan_control_point {
+			/** @temp: temperature in degree celsius */
+			u8 temp;
+			/** @speed: fan speed in percentage */
+			u8 speed;
+		} fcp[MAX_FAN_CONTROL_POINTS];
+	} fan_table[FAN_TABLE_MAX];
+	/** @min_pwm: minimum fan PWM */
+	u32 min_pwm;
 };
 
 /**
@@ -193,6 +231,8 @@ struct xe_hwmon {
 	int scl_shift_time;
 	/** @ei: Energy info for energyN_input */
 	struct xe_hwmon_energy_info ei[CHANNEL_MAX];
+	/** @fan_enable_mask: bitmask of available fans */
+	u32 fan_enable_mask;
 	/** @fi: Fan info for fanN_input */
 	struct xe_hwmon_fan_info fi[FAN_MAX];
 	/** @read_power_limit_from_pcode: pcode accepted power limits write for the channel */
@@ -1075,17 +1115,112 @@ static int xe_hwmon_pcode_write_i1(const struct xe_hwmon *hwmon, u32 uval)
 			      (uval & POWER_SETUP_I1_DATA_MASK));
 }
 
-static int xe_hwmon_pcode_read_fan_control(const struct xe_hwmon *hwmon, u32 subcmd, u32 *uval)
+static int xe_hwmon_pcode_read_fan_control(const struct xe_hwmon *hwmon, u32 subcmd, u8 fan_num,
+					   u32 *uval)
 {
 	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
+	return xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL, subcmd, fan_num),
+				     uval, NULL);
+}
+
+static int xe_hwmon_get_fan_enable_mask(struct xe_hwmon *hwmon)
+{
+	int ret;
 
 	/* Platforms that don't return correct value */
-	if (hwmon->xe->info.platform == XE_DG2 && subcmd == FSC_READ_NUM_FANS) {
-		*uval = 2;
+	if (hwmon->xe->info.platform == XE_DG2) {
+		hwmon->fan_enable_mask = GENMASK(1, 0);
 		return 0;
 	}
 
-	return xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL, subcmd, 0), uval, NULL);
+	ret = xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_NUM_FANS, 0,
+					      &hwmon->fan_enable_mask);
+	if (ret) {
+		xe_warn(hwmon->xe, "failed to read number of fans, ret=%d\n", ret);
+		return ret;
+	}
+
+	/* Check if fan mask exceeds FAN_MAX and log a warning if it does */
+	if (hwmon->fan_enable_mask & ~GENMASK(FAN_MAX - 1, 0)) {
+		xe_warn(hwmon->xe, "fan enable mask exceeds maximum supported fans\n");
+		return -EINVAL;
+	}
+
+	xe_info(hwmon->xe, "Number of fans detected: %u\n",
+		hweight32(hwmon->fan_enable_mask));
+	return 0;
+}
+
+static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
+{
+	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
+	int point;
+	int fan;
+	int ret;
+
+	for (fan = 0; fan < FAN_MAX; fan++) {
+		u32 stock_fcp_count = 0;
+
+		struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
+
+		if (!IS_FAN_ENABLED(fan))
+			continue;
+
+		ret = xe_hwmon_pcode_read_fan_control(hwmon,
+						      FSC_READ_STOCK_FAN_CONTROL_POINTS,
+						      fan, &stock_fcp_count);
+		if (ret) {
+			xe_err(hwmon->xe,
+			       "failed to read fan %d stock table point count, ret=%d\n",
+			       fan, ret);
+			return ret;
+		}
+
+		if (!stock_fcp_count || stock_fcp_count > MAX_FAN_CONTROL_POINTS) {
+			xe_warn(hwmon->xe,
+				"fan %d stock table point count %u is invalid\n",
+				fan, stock_fcp_count);
+			return -EINVAL;
+		}
+
+		fi->fan_table[STOCK_FAN_TABLE].point_count = stock_fcp_count;
+		xe_dbg(hwmon->xe, "fan %d stock table point count is %u\n", fan,
+		       fi->fan_table[STOCK_FAN_TABLE].point_count);
+
+		/* Cache the stock fan table for later use. */
+		for (point = 0; point < fi->fan_table[STOCK_FAN_TABLE].point_count;
+		     point++) {
+			u32 fcp = 0;
+
+			fcp = FCP_INDEX(STOCK_FAN_TABLE, point);
+			ret = xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL,
+								  FSC_READ_FAN_TABLE, fan),
+					    &fcp, NULL);
+			if (ret) {
+				xe_err(hwmon->xe, "failed to read fan %d stock point %d, ret=%d\n",
+				       fan, point, ret);
+				fi->fan_table[STOCK_FAN_TABLE].point_count = 0;
+				return ret;
+			}
+
+			fi->fan_table[STOCK_FAN_TABLE].fcp[point].temp =
+						REG_FIELD_GET(FAN_CONTROL_POINT_TEMP_MASK, fcp);
+			fi->fan_table[STOCK_FAN_TABLE].fcp[point].speed =
+						REG_FIELD_GET(FAN_CONTROL_POINT_SPEED_MASK, fcp);
+			xe_dbg(hwmon->xe, "fan %d stock point %d: temp %u C, speed %u\n",
+			       fan, point, fi->fan_table[STOCK_FAN_TABLE].fcp[point].temp,
+			       fi->fan_table[STOCK_FAN_TABLE].fcp[point].speed);
+		}
+
+		/* Read minimum fan PWM */
+		ret = xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_FAN_MIN_PWM, fan,
+						      &fi->min_pwm);
+		if (ret)
+			xe_warn(hwmon->xe, "fan %d min pwm unavailable, ret=%d\n", fan, ret);
+		else
+			xe_dbg(hwmon->xe, "fan %d min PWM %u\n", fan, fi->min_pwm);
+	}
+	return 0;
 }
 
 static int xe_hwmon_power_curr_crit_read(struct xe_hwmon *hwmon, int channel,
@@ -1615,17 +1750,12 @@ xe_hwmon_energy_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
 static umode_t
 xe_hwmon_fan_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
 {
-	u32 uval = 0;
-
 	if (!hwmon->xe->info.has_fan_control)
 		return 0;
 
 	switch (attr) {
 	case hwmon_fan_input:
-		if (xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_NUM_FANS, &uval))
-			return 0;
-
-		return channel < uval ? 0444 : 0;
+		return IS_FAN_ENABLED(channel) ? 0444 : 0;
 	default:
 		return 0;
 	}
@@ -1858,11 +1988,18 @@ xe_hwmon_get_preregistration_info(struct xe_hwmon *hwmon)
 		if (xe_hwmon_is_visible(hwmon, hwmon_energy, hwmon_energy_input, channel))
 			xe_hwmon_energy_get(hwmon, channel, &energy);
 
-	/* Initialize 'struct xe_hwmon_fan_info' with initial fan register reading. */
-	for (channel = 0; channel < FAN_MAX; channel++)
-		if (xe_hwmon_is_visible(hwmon, hwmon_fan, hwmon_fan_input, channel))
-			xe_hwmon_fan_input_read(hwmon, channel, &fan_speed);
+	if (hwmon->xe->info.has_fan_control) {
+		xe_hwmon_get_fan_enable_mask(hwmon);
+
+		/* Initialize 'struct xe_hwmon_fan_info' with initial fan register reading. */
+		for (channel = 0; channel < FAN_MAX; channel++)
+			if (IS_FAN_ENABLED(channel))
+				xe_hwmon_fan_input_read(hwmon, channel, &fan_speed);
 
+		/* Fan control tables initialization */
+		if (xe_hwmon_read_fan_control_info(hwmon))
+			xe_warn(hwmon->xe, "Fan control tables are not available\n");
+	}
 	return xe_hwmon_init_temp_info(hwmon);
 }
 
diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h
index 00c4fc7d0124..0349b24a8259 100644
--- a/drivers/gpu/drm/xe/xe_pcode_api.h
+++ b/drivers/gpu/drm/xe/xe_pcode_api.h
@@ -83,6 +83,11 @@
 
 #define   FAN_SPEED_CONTROL			0x7D
 #define     FSC_READ_NUM_FANS			0x4
+#define     FSC_READ_STOCK_FAN_CONTROL_POINTS	0x5
+#define     FSC_READ_FAN_TABLE			0x7
+#define     FAN_CONTROL_POINT_TEMP_MASK		REG_GENMASK(7, 0)
+#define     FAN_CONTROL_POINT_SPEED_MASK	REG_GENMASK(15, 8)
+#define     FSC_READ_FAN_MIN_PWM		0x8
 
 #define PCODE_SCRATCH(x)		XE_REG(0x138320 + ((x) * 4))
 /* PCODE_SCRATCH0 */
-- 
2.25.1


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

* [PATCH v3 2/9] drm/xe/hwmon: expose fanN_max
  2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
  2026-10-15 19:07 ` [PATCH v3 1/9] drm/xe/hwmon: initialize fan-control backend and table cache Karthik Poosa
@ 2026-10-15 19:07 ` Karthik Poosa
  2026-10-29  4:35   ` Purkait, Soham
  2026-10-15 19:07 ` [PATCH v3 3/9] drm/xe/pcode: add ordered write batch helper Karthik Poosa
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 26+ messages in thread
From: Karthik Poosa @ 2026-10-15 19:07 UTC (permalink / raw)
  To: intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi, soham.purkait,
	ravi.kishore.koppuravuri, Karthik Poosa

Expose fan maximum RPM via fanN_max.

The value is derived from the firmware-reported maximum fan RPS and
converted to RPM in the fan hwmon read path.

Update Xe hwmon ABI documentation for fanN_max.

v2: Use xe helper for dmesg logs.

v3:
 - Fix indentation of the max_rps struct member.
 - Enable fanN_max only when fanN is supported.

Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
Assisted-by: LLM
---
 .../ABI/testing/sysfs-driver-intel-xe-hwmon   |  8 ++++++++
 drivers/gpu/drm/xe/xe_hwmon.c                 | 19 ++++++++++++++++++-
 drivers/gpu/drm/xe/xe_pcode_api.h             |  1 +
 3 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
index 0da739d9a816..5ee68aefa485 100644
--- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
+++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
@@ -266,6 +266,14 @@ Description:	RO. Fan 3 speed in RPM.
 
 		Only supported for particular Intel Xe graphics platforms.
 
+What:           /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/fan[1-3]_max
+Date:           October 2026
+KernelVersion:  7.3
+Contact:        intel-xe@lists.freedesktop.org
+Description:    RO. Maximum fan speed in RPM for each fan channel.
+
+                Only supported for particular Intel Xe graphics platforms.
+
 What:		/sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/power1_cap
 Date:		May 2025
 KernelVersion:	6.15
diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
index f2bd20f8b0a2..32016c5d4770 100644
--- a/drivers/gpu/drm/xe/xe_hwmon.c
+++ b/drivers/gpu/drm/xe/xe_hwmon.c
@@ -181,6 +181,8 @@ struct xe_hwmon_fan_info {
 			u8 speed;
 		} fcp[MAX_FAN_CONTROL_POINTS];
 	} fan_table[FAN_TABLE_MAX];
+	/** @max_rps: maximum fan RPS */
+	u32 max_rps;
 	/** @min_pwm: minimum fan PWM */
 	u32 min_pwm;
 };
@@ -909,7 +911,8 @@ static const struct hwmon_channel_info * const hwmon_info[] = {
 	HWMON_CHANNEL_INFO(curr, HWMON_C_LABEL, HWMON_C_CRIT | HWMON_C_LABEL),
 	HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL),
 	HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT | HWMON_E_LABEL, HWMON_E_INPUT | HWMON_E_LABEL),
-	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT, HWMON_F_INPUT, HWMON_F_INPUT),
+	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_MAX, HWMON_F_INPUT | HWMON_F_MAX,
+			   HWMON_F_INPUT | HWMON_F_MAX),
 	NULL
 };
 
@@ -1219,6 +1222,14 @@ static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
 			xe_warn(hwmon->xe, "fan %d min pwm unavailable, ret=%d\n", fan, ret);
 		else
 			xe_dbg(hwmon->xe, "fan %d min PWM %u\n", fan, fi->min_pwm);
+
+		/* Read max fan RPS*/
+		ret = xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_MAX_FAN_RPS, fan,
+						      &fi->max_rps);
+		if (ret)
+			xe_warn(hwmon->xe, "failed to read fan %d max RPS, ret=%d\n", fan, ret);
+		else
+			xe_dbg(hwmon->xe, "fan %d max RPS %u\n", fan, fi->max_rps);
 	}
 	return 0;
 }
@@ -1756,6 +1767,8 @@ xe_hwmon_fan_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
 	switch (attr) {
 	case hwmon_fan_input:
 		return IS_FAN_ENABLED(channel) ? 0444 : 0;
+	case hwmon_fan_max:
+		return IS_FAN_ENABLED(channel) && hwmon->fi[channel].max_rps ? 0444 : 0;
 	default:
 		return 0;
 	}
@@ -1806,6 +1819,10 @@ xe_hwmon_fan_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
 	switch (attr) {
 	case hwmon_fan_input:
 		return xe_hwmon_fan_input_read(hwmon, channel, val);
+	case hwmon_fan_max:
+		/* Convert RPS to RPM */
+		*val = (long)hwmon->fi[channel].max_rps * 60;
+		return 0;
 	default:
 		return -EOPNOTSUPP;
 	}
diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h
index 0349b24a8259..32bac74c4281 100644
--- a/drivers/gpu/drm/xe/xe_pcode_api.h
+++ b/drivers/gpu/drm/xe/xe_pcode_api.h
@@ -82,6 +82,7 @@
 #define     PCODE_MBOX_DOMAIN_HBM		0x2
 
 #define   FAN_SPEED_CONTROL			0x7D
+#define     FSC_READ_MAX_FAN_RPS        0x3
 #define     FSC_READ_NUM_FANS			0x4
 #define     FSC_READ_STOCK_FAN_CONTROL_POINTS	0x5
 #define     FSC_READ_FAN_TABLE			0x7
-- 
2.25.1


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

* [PATCH v3 3/9] drm/xe/pcode: add ordered write batch helper
  2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
  2026-10-15 19:07 ` [PATCH v3 1/9] drm/xe/hwmon: initialize fan-control backend and table cache Karthik Poosa
  2026-10-15 19:07 ` [PATCH v3 2/9] drm/xe/hwmon: expose fanN_max Karthik Poosa
@ 2026-10-15 19:07 ` Karthik Poosa
  2026-10-29  5:45   ` Purkait, Soham
  2026-10-15 19:07 ` [PATCH v3 4/9] drm/xe/hwmon: expose pwm[1-3] Karthik Poosa
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 26+ messages in thread
From: Karthik Poosa @ 2026-10-15 19:07 UTC (permalink / raw)
  To: intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi, soham.purkait,
	ravi.kishore.koppuravuri, Karthik Poosa

Provide a pcode write helper that keeps the mailbox lock held while issuing
an ordered sequence of writes.
This will be used while writing the fan table ensuring that is not
interleaved by any other pcode mailbox command.

Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
---
 drivers/gpu/drm/xe/xe_pcode.c | 20 ++++++++++++++++++++
 drivers/gpu/drm/xe/xe_pcode.h |  7 +++++++
 2 files changed, 27 insertions(+)

diff --git a/drivers/gpu/drm/xe/xe_pcode.c b/drivers/gpu/drm/xe/xe_pcode.c
index 266deecbb100..ca107b0234d9 100644
--- a/drivers/gpu/drm/xe/xe_pcode.c
+++ b/drivers/gpu/drm/xe/xe_pcode.c
@@ -124,6 +124,26 @@ int xe_pcode_write_timeout(struct xe_tile *tile, u32 mbox, u32 data, int timeout
 	return err;
 }
 
+int xe_pcode_write_batch(struct xe_tile *tile, const struct xe_pcode_write *writes,
+			 unsigned int count)
+{
+	unsigned int i;
+	int err = 0;
+
+	mutex_lock(&tile->pcode.lock);
+	for (i = 0; i < count; i++) {
+		u32 data = writes[i].data;
+
+		err = pcode_mailbox_rw(tile, writes[i].mbox, &data, NULL, PCODE_DEFAULT_TIMEOUT_MS,
+				       false, false);
+		if (err)
+			break;
+	}
+	mutex_unlock(&tile->pcode.lock);
+
+	return err;
+}
+
 int xe_pcode_write64_timeout(struct xe_tile *tile, u32 mbox, u32 data0, u32 data1, int timeout)
 {
 	int err;
diff --git a/drivers/gpu/drm/xe/xe_pcode.h b/drivers/gpu/drm/xe/xe_pcode.h
index 7e43792b0037..74bd553ab390 100644
--- a/drivers/gpu/drm/xe/xe_pcode.h
+++ b/drivers/gpu/drm/xe/xe_pcode.h
@@ -18,6 +18,11 @@ struct xe_pcode_version {
 	u32 engg;
 };
 
+struct xe_pcode_write {
+	u32 mbox;
+	u32 data;
+};
+
 #define PCODE_DEFAULT_TIMEOUT_MS	10
 
 int xe_pcode_init_early(struct xe_tile *tile);
@@ -28,6 +33,8 @@ int xe_pcode_init_min_freq_table(struct xe_tile *tile, u32 min_gt_freq,
 int xe_pcode_read(struct xe_tile *tile, u32 mbox, u32 *val0, u32 *val1);
 int xe_pcode_write_timeout(struct xe_tile *tile, u32 mbox, u32 val,
 			   int timeout_ms);
+int xe_pcode_write_batch(struct xe_tile *tile, const struct xe_pcode_write *writes,
+			 unsigned int count);
 int xe_pcode_write64_timeout(struct xe_tile *tile, u32 mbox, u32 data0,
 			     u32 data1, int timeout);
 int xe_get_pcode_version(struct xe_device *xe, struct xe_pcode_version *version);
-- 
2.25.1


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

* [PATCH v3 4/9] drm/xe/hwmon: expose pwm[1-3]
  2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
                   ` (2 preceding siblings ...)
  2026-10-15 19:07 ` [PATCH v3 3/9] drm/xe/pcode: add ordered write batch helper Karthik Poosa
@ 2026-10-15 19:07 ` Karthik Poosa
  2026-10-29 11:31   ` Purkait, Soham
  2026-10-15 19:07 ` [PATCH v3 5/9] drm/xe/hwmon: expose pwm[1-3]_enable Karthik Poosa
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 26+ messages in thread
From: Karthik Poosa @ 2026-10-15 19:07 UTC (permalink / raw)
  To: intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi, soham.purkait,
	ravi.kishore.koppuravuri, Karthik Poosa

Expose pwm[1-3] fan duty attributes through hwmon.

This enables reading and writing user PWM values (0..255) for each
available fan channel.

Update Xe hwmon ABI documentation for pwm[1-3].

This sysfs node can be used for manual control of fan speed,
irrespective of fan curve.

v2:
 - Use xe helpers for dmesg logs.
 - Avoid using hwmon->num_fans to get fan count in
   xe_hwmon_pwm_is_visible().

v3:
 - Set PWM directly through the user table; avoid initializing it from the
   stock table. (Soham)
 - Move the unused xe_hwmon_activate_user_fan_table() to the subsequent
   patch.
 - Fail pwmN reads when no value has been written, rather than activating
   the user table from the stock table.
 - Define MIN_FAN_CONTROL_POINTS as 2.
 - Use MIN_FAN_CONTROL_POINTS for PWM configuration. (Soham)
 - Use batched writes for configuring fan control points when setting pwmN.
 - Add and rephrase couple debug logs.
 - Update the hwmon documentation.

Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
Assisted-by: LLM
---
 .../ABI/testing/sysfs-driver-intel-xe-hwmon   |   9 +
 drivers/gpu/drm/xe/xe_hwmon.c                 | 170 ++++++++++++++++++
 drivers/gpu/drm/xe/xe_pcode_api.h             |   3 +
 3 files changed, 182 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
index 5ee68aefa485..ce17e9ca3ed8 100644
--- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
+++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
@@ -321,3 +321,12 @@ Description:	RW. Package burst power limit interval (Tau in PL2/Tau) in
 		milliseconds over which sustained power is averaged.
 
 		Only supported for particular Intel Xe graphics platforms.
+
+What:           /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/pwm[1-3]
+Date:           October 2026
+KernelVersion:  7.3
+Contact:        intel-xe@lists.freedesktop.org
+Description:    RW. Target fan PWM duty value in the range 0..255. 0 is zero
+                fan speed and 255 is 100% fan speed.
+
+                Only supported for particular Intel Xe graphics platforms.
diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
index 32016c5d4770..a86ed741feb3 100644
--- a/drivers/gpu/drm/xe/xe_hwmon.c
+++ b/drivers/gpu/drm/xe/xe_hwmon.c
@@ -8,6 +8,7 @@
 #include <linux/jiffies.h>
 #include <linux/types.h>
 #include <linux/units.h>
+#include <linux/delay.h>
 
 #include <drm/drm_managed.h>
 #include "regs/xe_gt_regs.h"
@@ -153,6 +154,9 @@ enum fan_table_type {
 /* Maximum number of fan control points supported by each fan. */
 #define MAX_FAN_CONTROL_POINTS	(10)
 
+/* Minimum number of points required for a user fan table. */
+#define MIN_FAN_CONTROL_POINTS  (2)
+
 /* Fan control point index: bit31 selects fan table type; bits30:0 control point index. */
 #define FCP_INDEX(FAN_TABLE_TYPE, POINT_NUM) (((FAN_TABLE_TYPE) << 31) | \
 						((POINT_NUM) & REG_GENMASK(30, 0)))
@@ -913,6 +917,7 @@ static const struct hwmon_channel_info * const hwmon_info[] = {
 	HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT | HWMON_E_LABEL, HWMON_E_INPUT | HWMON_E_LABEL),
 	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_MAX, HWMON_F_INPUT | HWMON_F_MAX,
 			   HWMON_F_INPUT | HWMON_F_MAX),
+	HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT, HWMON_PWM_INPUT, HWMON_PWM_INPUT),
 	NULL
 };
 
@@ -1154,6 +1159,89 @@ static int xe_hwmon_get_fan_enable_mask(struct xe_hwmon *hwmon)
 	return 0;
 }
 
+static int xe_hwmon_get_fan_point_count(struct xe_hwmon *hwmon, u8 fan, u32 *point_count,
+					enum fan_table_type table_type)
+{
+	int ret;
+
+	ret = xe_hwmon_pcode_read_fan_control(hwmon,
+					      (table_type == USER_FAN_TABLE) ?
+					      FSC_READ_USER_FAN_CONTROL_POINTS :
+					      FSC_READ_STOCK_FAN_CONTROL_POINTS,
+					      fan, point_count);
+	if (ret) {
+		xe_err(hwmon->xe, "failed to read fan %d %s point count, ret=%d\n", fan,
+		       (table_type == USER_FAN_TABLE) ? "user" : "stock", ret);
+		return ret;
+	}
+
+	if (*point_count > MAX_FAN_CONTROL_POINTS) {
+		xe_err(hwmon->xe, "fan %d %s point count %u exceeds max %u\n", fan,
+		       (table_type == USER_FAN_TABLE) ? "user" : "stock", *point_count,
+		       MAX_FAN_CONTROL_POINTS);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Temperature to set when setting the fan PWM with pwmN. */
+#define FIXED_PWM_TEMP	(1)
+
+static int xe_hwmon_set_user_fan_pwm(struct xe_hwmon *hwmon, u8 fan, u8 pwm)
+{
+	struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
+	struct xe_pcode_write writes[MIN_FAN_CONTROL_POINTS + 1];
+	u32 point_count = 0;
+	u8 clamped_pwm;
+	int ret, i;
+
+	pwm = DIV_ROUND_CLOSEST(pwm * 100, U8_MAX);
+	clamped_pwm = max_t(u8, pwm, min_t(u32, fi->min_pwm, U8_MAX));
+
+	/*
+	 * Set the first fan control point in the user table to the clamped PWM value.
+	 * Use only the first fan control point for setting the PWM value.
+	 */
+
+	for (i = 0; i < MIN_FAN_CONTROL_POINTS; i++) {
+		writes[i].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_FAN_TABLE, fan);
+		writes[i].data = FIELD_PREP(FAN_CONTROL_POINT_TEMP_MASK, FIXED_PWM_TEMP + (i)) |
+					    FIELD_PREP(FAN_CONTROL_POINT_SPEED_MASK, clamped_pwm);
+		xe_dbg(hwmon->xe, "prepared fan control point %d with temp=%d, speed=%u\n", i,
+		       FIXED_PWM_TEMP + (i), clamped_pwm);
+	}
+
+	writes[i].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_NUM_FAN_CONTROL_POINTS, fan);
+	writes[i].data = MIN_FAN_CONTROL_POINTS;
+	ret = xe_pcode_write_batch(xe_device_get_root_tile(hwmon->xe), writes, ARRAY_SIZE(writes));
+	if (ret) {
+		xe_err(hwmon->xe, "failed to write pwm %d for fan %d, ret=%d\n", pwm, fan, ret);
+		return ret;
+	}
+	xe_dbg(hwmon->xe, "applied fixed pwm %u for fan %d\n", clamped_pwm, fan);
+
+	/* Verify if the fan points are set */
+	ret = xe_hwmon_get_fan_point_count(hwmon, fan, &point_count, USER_FAN_TABLE);
+	if (ret && point_count == 0) {
+		xe_err(hwmon->xe, "pwm set verify failed for fan %d, ret=%d, point count=%u\n", fan,
+		       ret, point_count);
+		return ret;
+	}
+
+	/* Update the user fan table cache. */
+	for (i = 0; i < MIN_FAN_CONTROL_POINTS; i++) {
+		fi->fan_table[USER_FAN_TABLE].fcp[i].temp = FIXED_PWM_TEMP + (i);
+		fi->fan_table[USER_FAN_TABLE].fcp[i].speed = clamped_pwm;
+		xe_dbg(hwmon->xe, "fan %d user table cache point %d with temp=%d, speed=%u\n", fan,
+		       i, fi->fan_table[USER_FAN_TABLE].fcp[i].temp,
+			  fi->fan_table[USER_FAN_TABLE].fcp[i].speed);
+	}
+	fi->fan_table[USER_FAN_TABLE].point_count = MIN_FAN_CONTROL_POINTS;
+
+	return 0;
+}
+
 static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
 {
 	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
@@ -1774,6 +1862,20 @@ xe_hwmon_fan_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
 	}
 }
 
+static umode_t
+xe_hwmon_pwm_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
+{
+	if (!hwmon->xe->info.has_fan_control || !IS_FAN_ENABLED(channel))
+		return 0;
+
+	switch (attr) {
+	case hwmon_pwm_input:
+		return 0644;
+	default:
+		return 0;
+	}
+}
+
 static int
 xe_hwmon_fan_input_read(struct xe_hwmon *hwmon, int channel, long *val)
 {
@@ -1828,6 +1930,67 @@ xe_hwmon_fan_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
 	}
 }
 
+static int
+xe_hwmon_pwm_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
+{
+	struct xe_hwmon_fan_info *fi;
+	int ret = 0;
+
+	if (channel < 0 || channel >= FAN_MAX)
+		return -EINVAL;
+
+	mutex_lock(&hwmon->hwmon_lock);
+
+	fi = &hwmon->fi[channel];
+
+	switch (attr) {
+	case hwmon_pwm_input:
+		/* Check if user fan table is set else activate it.*/
+		if (!fi->fan_table[USER_FAN_TABLE].point_count) {
+			xe_warn(hwmon->xe, "pwm not set for fan %d\n", channel);
+			ret = -ENXIO;
+			goto unlock;
+		}
+		*val = DIV_ROUND_CLOSEST(fi->fan_table[USER_FAN_TABLE].fcp[0].speed * U8_MAX, 100);
+		xe_dbg(hwmon->xe, "pwm read for fan %d: %ld\n", channel, *val);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+
+unlock:
+	mutex_unlock(&hwmon->hwmon_lock);
+	return ret;
+}
+
+static int
+xe_hwmon_pwm_write(struct xe_hwmon *hwmon, u32 attr, int channel, long val)
+{
+	int ret = 0;
+
+	if (channel < 0 || channel >= FAN_MAX)
+		return -EINVAL;
+
+	mutex_lock(&hwmon->hwmon_lock);
+
+	switch (attr) {
+	case hwmon_pwm_input:
+		if (val < 0 || val > U8_MAX) {
+			ret = -EINVAL;
+			break;
+		}
+		ret = xe_hwmon_set_user_fan_pwm(hwmon, channel, (u8)val);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+		break;
+	}
+	mutex_unlock(&hwmon->hwmon_lock);
+
+	return ret;
+}
+
 static umode_t
 xe_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
 		    u32 attr, int channel)
@@ -1854,6 +2017,9 @@ xe_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
 	case hwmon_fan:
 		ret = xe_hwmon_fan_is_visible(hwmon, attr, channel);
 		break;
+	case hwmon_pwm:
+		ret = xe_hwmon_pwm_is_visible(hwmon, attr, channel);
+		break;
 	default:
 		ret = 0;
 		break;
@@ -1883,6 +2049,8 @@ xe_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
 		return xe_hwmon_energy_read(hwmon, attr, channel, val);
 	case hwmon_fan:
 		return xe_hwmon_fan_read(hwmon, attr, channel, val);
+	case hwmon_pwm:
+		return xe_hwmon_pwm_read(hwmon, attr, channel, val);
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -1901,6 +2069,8 @@ xe_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
 		return xe_hwmon_power_write(hwmon, attr, channel, val);
 	case hwmon_curr:
 		return xe_hwmon_curr_write(hwmon, attr, channel, val);
+	case hwmon_pwm:
+		return xe_hwmon_pwm_write(hwmon, attr, channel, val);
 	default:
 		return -EOPNOTSUPP;
 	}
diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h
index 32bac74c4281..80642bee0ac8 100644
--- a/drivers/gpu/drm/xe/xe_pcode_api.h
+++ b/drivers/gpu/drm/xe/xe_pcode_api.h
@@ -82,9 +82,12 @@
 #define     PCODE_MBOX_DOMAIN_HBM		0x2
 
 #define   FAN_SPEED_CONTROL			0x7D
+#define     FSC_WRITE_NUM_FAN_CONTROL_POINTS	0x0
+#define     FSC_WRITE_FAN_TABLE			0x1
 #define     FSC_READ_MAX_FAN_RPS        0x3
 #define     FSC_READ_NUM_FANS			0x4
 #define     FSC_READ_STOCK_FAN_CONTROL_POINTS	0x5
+#define     FSC_READ_USER_FAN_CONTROL_POINTS	0x6
 #define     FSC_READ_FAN_TABLE			0x7
 #define     FAN_CONTROL_POINT_TEMP_MASK		REG_GENMASK(7, 0)
 #define     FAN_CONTROL_POINT_SPEED_MASK	REG_GENMASK(15, 8)
-- 
2.25.1


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

* [PATCH v3 5/9] drm/xe/hwmon: expose pwm[1-3]_enable
  2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
                   ` (3 preceding siblings ...)
  2026-10-15 19:07 ` [PATCH v3 4/9] drm/xe/hwmon: expose pwm[1-3] Karthik Poosa
@ 2026-10-15 19:07 ` Karthik Poosa
  2026-10-29 18:33   ` Purkait, Soham
  2026-10-15 19:07 ` [PATCH v3 6/9] drm/xe/hwmon: Enable fan curve control support Karthik Poosa
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 26+ messages in thread
From: Karthik Poosa @ 2026-10-15 19:07 UTC (permalink / raw)
  To: intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi, soham.purkait,
	ravi.kishore.koppuravuri, Karthik Poosa

Expose pwm[1-3]_enable to control the fan operating mode through
the hwmon interface.
 
Mode 0 forces the fan to run at full speed.
Mode 1 enables user fan-table control.
Mode 2 restores firmware-controlled fan management.
 
Document pwm[1-3]_enable in the Xe hwmon ABI.

v2:
 - Use xe helpers for dmesg logs.
 - Update kernel version in Xe hwmon documentation.
 - Correct level of some dmesg logs.

v3:
 - Each pwm_enable mode now sets its own state; drop the redundant
   post-switch pwm_enable_mode/is_full_speed update. (Badal)
 - Fix misindented dead assignment in the stock-table branch.
 - Make error handling consistent across pwm_enable modes. (Badal)
 - Document the pwm[1-3] manual-mode write precondition in the ABI. (Badal)
 - Use xe_pcode_write() instead of the timeout variant api as it is not
   needed.

Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
Assisted-by: LLM
---
 .../ABI/testing/sysfs-driver-intel-xe-hwmon   |  15 ++
 drivers/gpu/drm/xe/xe_hwmon.c                 | 156 +++++++++++++++++-
 2 files changed, 168 insertions(+), 3 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
index ce17e9ca3ed8..92c91c57b3f2 100644
--- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
+++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
@@ -329,4 +329,19 @@ Contact:        intel-xe@lists.freedesktop.org
 Description:    RW. Target fan PWM duty value in the range 0..255. 0 is zero
                 fan speed and 255 is 100% fan speed.
 
+                Writing requires the corresponding pwm[1-3]_enable to be set to
+                1 (manual user-table mode) first; otherwise the write is
+                rejected with -EINVAL.
+
                 Only supported for particular Intel Xe graphics platforms.
+
+What:          /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/pwm[1-3]_enable
+Date:          September 2026
+KernelVersion: 7.3
+Contact:       intel-xe@lists.freedesktop.org
+Description:   RW. Fan control mode selector.
+
+               Use value 0 to run fans at full speed. Use value 1 to enable
+               user table control and value 2 to use firmware default behavior.
+
+               Only supported for particular Intel Xe graphics platforms.
diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
index a86ed741feb3..c3d5c682768d 100644
--- a/drivers/gpu/drm/xe/xe_hwmon.c
+++ b/drivers/gpu/drm/xe/xe_hwmon.c
@@ -139,6 +139,15 @@ struct xe_hwmon_energy_info {
 	long accum_energy;
 };
 
+enum xe_fan_pwm_enable_mode {
+	/** @XE_FAN_PWM_FULL_SPEED: force all user table points to full speed */
+	XE_FAN_PWM_FULL_SPEED = 0,
+	/** @XE_FAN_PWM_MANUAL_USER_TABLE: use the driver-managed user table */
+	XE_FAN_PWM_MANUAL_USER_TABLE = 1,
+	/** @XE_FAN_PWM_AUTO_STOCK_TABLE: use the firmware stock table */
+	XE_FAN_PWM_AUTO_STOCK_TABLE = 2,
+};
+
 enum fan_table_type {
 	/** @STOCK_FAN_TABLE: firmware-provided fan table */
 	STOCK_FAN_TABLE,
@@ -189,6 +198,10 @@ struct xe_hwmon_fan_info {
 	u32 max_rps;
 	/** @min_pwm: minimum fan PWM */
 	u32 min_pwm;
+	/** @pwm_enable_mode: current xe_fan_pwm_enable_mode */
+	u8 pwm_enable_mode;
+	/** @is_full_speed: flag indicating if fan is in full speed */
+	bool is_full_speed;
 };
 
 /**
@@ -917,7 +930,9 @@ static const struct hwmon_channel_info * const hwmon_info[] = {
 	HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT | HWMON_E_LABEL, HWMON_E_INPUT | HWMON_E_LABEL),
 	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_MAX, HWMON_F_INPUT | HWMON_F_MAX,
 			   HWMON_F_INPUT | HWMON_F_MAX),
-	HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT, HWMON_PWM_INPUT, HWMON_PWM_INPUT),
+	HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
+			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
+			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
 	NULL
 };
 
@@ -1185,10 +1200,80 @@ static int xe_hwmon_get_fan_point_count(struct xe_hwmon *hwmon, u8 fan, u32 *poi
 	return 0;
 }
 
+static int xe_hwmon_activate_user_fan_table(struct xe_hwmon *hwmon, u8 fan,
+					    bool is_full_speed, enum fan_table_type table_source)
+{
+	struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
+	struct xe_pcode_write writes[MAX_FAN_CONTROL_POINTS + 1];
+	u32 point_count;
+	int ret;
+	int point;
+	struct fan_table *source_table = &fi->fan_table[table_source];
+
+	xe_dbg(hwmon->xe, "activating fan %d user table from %s table\n", fan,
+	       (table_source == USER_FAN_TABLE) ? "user" : "stock");
+
+	point_count = source_table->point_count;
+	if (!point_count || point_count > MAX_FAN_CONTROL_POINTS) {
+		xe_err(hwmon->xe,
+		       "fan %d %s table point count %d is invalid, cannot activate user table\n",
+		       fan, (table_source == USER_FAN_TABLE) ? "user" : "stock", point_count);
+		return -EINVAL;
+	}
+
+	for (point = 0; point < point_count; point++) {
+		u8 temp = source_table->fcp[point].temp;
+		u8 speed = is_full_speed ? 100 : max_t(u8, source_table->fcp[point].speed,
+					    min_t(u32, fi->min_pwm, U8_MAX));
+
+		writes[point].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_FAN_TABLE, fan);
+		writes[point].data = FIELD_PREP(FAN_CONTROL_POINT_TEMP_MASK, temp) |
+					FIELD_PREP(FAN_CONTROL_POINT_SPEED_MASK, speed);
+	}
+
+	writes[point_count].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_NUM_FAN_CONTROL_POINTS,
+					      fan);
+	writes[point_count].data = point_count;
+	ret = xe_pcode_write_batch(xe_device_get_root_tile(hwmon->xe), writes, point_count + 1);
+	if (ret) {
+		xe_dbg(hwmon->xe, "failed to write fan %d user table, ret=%d\n", fan, ret);
+		return ret;
+	}
+
+	/* Verify if all the user points are set */
+	ret = xe_hwmon_get_fan_point_count(hwmon, fan, &point_count, USER_FAN_TABLE);
+	if (ret) {
+		xe_err(hwmon->xe,
+		       "failed to read fan %d user table point count, ret=%d\n", fan, ret);
+		return ret;
+	}
+	if (point_count != source_table->point_count) {
+		xe_err(hwmon->xe, "fan %d user table point count mismatch, expected %u, got %u\n",
+		       fan, source_table->point_count, point_count);
+		return -EIO;
+	}
+
+	if (table_source == STOCK_FAN_TABLE) {
+		for (point = 0; point < point_count; point++) {
+			fi->fan_table[USER_FAN_TABLE].fcp[point].temp =
+				source_table->fcp[point].temp;
+			fi->fan_table[USER_FAN_TABLE].fcp[point].speed =
+				is_full_speed ? 100 : max_t(u8, source_table->fcp[point].speed,
+							    min_t(u32, fi->min_pwm, U8_MAX));
+		}
+	}
+
+	fi->fan_table[USER_FAN_TABLE].point_count = point_count;
+	fi->pwm_enable_mode = XE_FAN_PWM_MANUAL_USER_TABLE;
+	fi->is_full_speed = is_full_speed;
+
+	return 0;
+}
+
 /* Temperature to set when setting the fan PWM with pwmN. */
 #define FIXED_PWM_TEMP	(1)
 
-static int xe_hwmon_set_user_fan_pwm(struct xe_hwmon *hwmon, u8 fan, u8 pwm)
+static int xe_hwmon_set_user_fan_pwm(struct xe_hwmon *hwmon, u8 fan, u8 pwm, bool full_speed)
 {
 	struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
 	struct xe_pcode_write writes[MIN_FAN_CONTROL_POINTS + 1];
@@ -1196,6 +1281,11 @@ static int xe_hwmon_set_user_fan_pwm(struct xe_hwmon *hwmon, u8 fan, u8 pwm)
 	u8 clamped_pwm;
 	int ret, i;
 
+	if (!full_speed && fi->pwm_enable_mode != XE_FAN_PWM_MANUAL_USER_TABLE) {
+		xe_dbg(hwmon->xe, "fan %d manual mode is not active, cannot set pwm\n", fan);
+		return -EINVAL;
+	}
+
 	pwm = DIV_ROUND_CLOSEST(pwm * 100, U8_MAX);
 	clamped_pwm = max_t(u8, pwm, min_t(u32, fi->min_pwm, U8_MAX));
 
@@ -1239,6 +1329,8 @@ static int xe_hwmon_set_user_fan_pwm(struct xe_hwmon *hwmon, u8 fan, u8 pwm)
 	}
 	fi->fan_table[USER_FAN_TABLE].point_count = MIN_FAN_CONTROL_POINTS;
 
+	fi->pwm_enable_mode = XE_FAN_PWM_MANUAL_USER_TABLE;
+	fi->is_full_speed = full_speed;
 	return 0;
 }
 
@@ -1303,6 +1395,9 @@ static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
 			       fi->fan_table[STOCK_FAN_TABLE].fcp[point].speed);
 		}
 
+		/* Set PWM enable mode to automatic i.e stock table in use. */
+		fi->pwm_enable_mode = XE_FAN_PWM_AUTO_STOCK_TABLE;
+
 		/* Read minimum fan PWM */
 		ret = xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_FAN_MIN_PWM, fan,
 						      &fi->min_pwm);
@@ -1870,6 +1965,7 @@ xe_hwmon_pwm_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
 
 	switch (attr) {
 	case hwmon_pwm_input:
+	case hwmon_pwm_enable:
 		return 0644;
 	default:
 		return 0;
@@ -1954,6 +2050,9 @@ xe_hwmon_pwm_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
 		*val = DIV_ROUND_CLOSEST(fi->fan_table[USER_FAN_TABLE].fcp[0].speed * U8_MAX, 100);
 		xe_dbg(hwmon->xe, "pwm read for fan %d: %ld\n", channel, *val);
 		break;
+	case hwmon_pwm_enable:
+		*val = fi->pwm_enable_mode;
+		break;
 	default:
 		ret = -EOPNOTSUPP;
 		break;
@@ -1967,11 +2066,15 @@ xe_hwmon_pwm_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
 static int
 xe_hwmon_pwm_write(struct xe_hwmon *hwmon, u32 attr, int channel, long val)
 {
+	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
+	struct xe_hwmon_fan_info *fi;
 	int ret = 0;
 
 	if (channel < 0 || channel >= FAN_MAX)
 		return -EINVAL;
 
+	fi = &hwmon->fi[channel];
+
 	mutex_lock(&hwmon->hwmon_lock);
 
 	switch (attr) {
@@ -1980,12 +2083,59 @@ xe_hwmon_pwm_write(struct xe_hwmon *hwmon, u32 attr, int channel, long val)
 			ret = -EINVAL;
 			break;
 		}
-		ret = xe_hwmon_set_user_fan_pwm(hwmon, channel, (u8)val);
+		ret = xe_hwmon_set_user_fan_pwm(hwmon, channel, (u8)val, false);
+		break;
+	case hwmon_pwm_enable:
+		if (val == XE_FAN_PWM_FULL_SPEED) {
+			ret = xe_hwmon_set_user_fan_pwm(hwmon, channel, U8_MAX, true);
+			if (ret) {
+				xe_warn(hwmon->xe,
+					"full speed enable for fan %d failed, ret=%d\n",
+					channel, ret);
+				break;
+			}
+		} else if (val == XE_FAN_PWM_MANUAL_USER_TABLE) {
+			enum fan_table_type source = fi->fan_table[USER_FAN_TABLE].point_count ?
+				USER_FAN_TABLE : STOCK_FAN_TABLE;
+
+			/*
+			 * Manual fan speed control using user fan table.
+			 * If user fan table is not programmed, it would be initialized with
+			 * clamped stock points which allows manual control with some
+			 * default points.
+			 */
+			ret = xe_hwmon_activate_user_fan_table(hwmon, channel, false, source);
+			if (ret) {
+				xe_warn(hwmon->xe,
+					"failed to activate user fan table for fan %d, ret=%d\n",
+					channel, ret);
+				break;
+			}
+		} else if (val == XE_FAN_PWM_AUTO_STOCK_TABLE) {
+			/* Switch to stock table specifying the user points to 0. */
+			ret = xe_pcode_write(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL,
+								   FSC_WRITE_NUM_FAN_CONTROL_POINTS,
+								   channel), 0);
+			if (ret) {
+				xe_warn(hwmon->xe,
+					"failed to disable user fan table for fan %d, ret=%d\n",
+					channel, ret);
+				break;
+			}
+			xe_dbg(hwmon->xe,
+			       "automatic control enabled for fan %d using stock table\n",
+			       channel);
+			fi->pwm_enable_mode = XE_FAN_PWM_AUTO_STOCK_TABLE;
+			fi->is_full_speed = false;
+		} else {
+			ret = -EINVAL;
+		}
 		break;
 	default:
 		ret = -EOPNOTSUPP;
 		break;
 	}
+
 	mutex_unlock(&hwmon->hwmon_lock);
 
 	return ret;
-- 
2.25.1


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

* [PATCH v3 6/9] drm/xe/hwmon: Enable fan curve control support
  2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
                   ` (4 preceding siblings ...)
  2026-10-15 19:07 ` [PATCH v3 5/9] drm/xe/hwmon: expose pwm[1-3]_enable Karthik Poosa
@ 2026-10-15 19:07 ` Karthik Poosa
  2026-10-30  6:33   ` Purkait, Soham
  2026-10-15 19:07 ` [PATCH v3 7/9] drm/xe/hwmon: Add kernel-doc for fan control Karthik Poosa
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 26+ messages in thread
From: Karthik Poosa @ 2026-10-15 19:07 UTC (permalink / raw)
  To: intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi, soham.purkait,
	ravi.kishore.koppuravuri, Karthik Poosa

Expose curve-point temperature and pwm controls via
pwmF_auto_point[P]_temp and pwmF_auto_point[P]_pwm, where
F is the fan number and P is the fan curve point number.
Each fan curve point has temperature and pwm sysfs.

Update Xe hwmon ABI documentation for pwm auto point temperature
attributes.

v2:
- Use xe helpers for dmesg logs.
- Update kernel version in Xe hwmon documentation.
- Correct debug level of some dmesg logs.

v3:
 - Allow variable fan curve points from >=2 to MAX_FAN_CONTROL_POINTS.
 - Expose all MAX_FAN_CONTROL_POINTS fan-curve slots so users can extend
   a short fan table.
 - Stage temp/PWM pairs without changing the active curve. Commit at a
   (0, 0) end marker or after all MAX_FAN_CONTROL_POINTS pairs.
 - Write the points together, verify the firmware count, then update the
   active cache.

Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
Assisted-by: LLM
---
 drivers/gpu/drm/xe/xe_hwmon.c | 693 +++++++++++++++++++++++++++++++++-
 1 file changed, 692 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
index c3d5c682768d..de2adb56d15b 100644
--- a/drivers/gpu/drm/xe/xe_hwmon.c
+++ b/drivers/gpu/drm/xe/xe_hwmon.c
@@ -193,6 +193,12 @@ struct xe_hwmon_fan_info {
 			/** @speed: fan speed in percentage */
 			u8 speed;
 		} fcp[MAX_FAN_CONTROL_POINTS];
+		/** @staged_fcp: curve supplied via sysfs but not yet committed */
+		struct fan_control_point staged_fcp[MAX_FAN_CONTROL_POINTS];
+		/** @temp_staged: bitmask of temperature fields supplied via sysfs */
+		u16 temp_staged;
+		/** @speed_staged: bitmask of PWM fields supplied via sysfs */
+		u16 speed_staged;
 	} fan_table[FAN_TABLE_MAX];
 	/** @max_rps: maximum fan RPS */
 	u32 max_rps;
@@ -899,8 +905,11 @@ static const struct attribute_group hwmon_attrgroup = {
 	.is_visible = xe_hwmon_attributes_visible,
 };
 
+static const struct attribute_group hwmon_curve_attrgroup;
+
 static const struct attribute_group *hwmon_groups[] = {
 	&hwmon_attrgroup,
+	&hwmon_curve_attrgroup,
 	NULL
 };
 
@@ -1200,6 +1209,74 @@ static int xe_hwmon_get_fan_point_count(struct xe_hwmon *hwmon, u8 fan, u32 *poi
 	return 0;
 }
 
+static int xe_hwmon_commit_user_fan_table(struct xe_hwmon *hwmon, u8 fan,
+					  const struct fan_control_point *points, u32 point_count)
+{
+	/* The extra write is for the final write that sets the number of fan control points */
+	struct xe_pcode_write writes[MAX_FAN_CONTROL_POINTS + 1];
+	u32 accepted_count = 0;
+	int point;
+	int ret;
+
+	if (!point_count) {
+		xe_err(hwmon->xe, "no fan control points provided for fan %d\n", fan);
+		return -ENODATA;
+	}
+
+	for (point = 0; point < point_count; point++) {
+		u8 temp = points[point].temp;
+		u8 speed = points[point].speed;
+
+		/* Ensure fan control points are strictly increasing order */
+		if (point > 0) {
+			u8 prev_temp = points[point - 1].temp;
+			u8 prev_speed = points[point - 1].speed;
+
+			if (temp < prev_temp || speed < prev_speed) {
+				xe_dbg(hwmon->xe,
+				       "fan %d invalid point prev > current %d: %u/%u prev=%u/%u\n",
+					fan, point, temp, speed, prev_temp, prev_speed);
+				return -EINVAL;
+			}
+		}
+
+		/* Prepare the write for this fan control point */
+		writes[point].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_FAN_TABLE,
+						fan);
+		writes[point].data = FIELD_PREP(FAN_CONTROL_POINT_TEMP_MASK, temp) |
+				FIELD_PREP(FAN_CONTROL_POINT_SPEED_MASK, speed);
+	}
+
+	xe_dbg(hwmon->xe, "committing fan %d user table with %d points\n", fan, point_count);
+
+	writes[point_count].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_NUM_FAN_CONTROL_POINTS,
+					      fan);
+	writes[point_count].data = point_count;
+
+	ret = xe_pcode_write_batch(xe_device_get_root_tile(hwmon->xe), writes, point_count + 1);
+	if (ret) {
+		xe_dbg(hwmon->xe,
+		       "failed to write fan %d user table count to %d, ret=%d\n", fan, point_count,
+		       ret);
+		return ret;
+	}
+
+	/* Verify if the user fan table was accepted correctly */
+	ret = xe_hwmon_get_fan_point_count(hwmon, fan, &accepted_count, USER_FAN_TABLE);
+	if (ret)
+		return ret;
+
+	if (accepted_count != point_count) {
+		xe_err(hwmon->xe, "fan %d table count mismatch after commit, expected %u, got %u\n",
+		       fan, point_count, accepted_count);
+		return -EIO;
+	}
+
+	xe_dbg(hwmon->xe, "fan %d user table committed successfully with %d points\n", fan,
+	       point_count);
+	return 0;
+}
+
 static int xe_hwmon_activate_user_fan_table(struct xe_hwmon *hwmon, u8 fan,
 					    bool is_full_speed, enum fan_table_type table_source)
 {
@@ -1264,6 +1341,8 @@ static int xe_hwmon_activate_user_fan_table(struct xe_hwmon *hwmon, u8 fan,
 	}
 
 	fi->fan_table[USER_FAN_TABLE].point_count = point_count;
+	fi->fan_table[USER_FAN_TABLE].temp_staged = 0;
+	fi->fan_table[USER_FAN_TABLE].speed_staged = 0;
 	fi->pwm_enable_mode = XE_FAN_PWM_MANUAL_USER_TABLE;
 	fi->is_full_speed = is_full_speed;
 
@@ -1328,12 +1407,622 @@ static int xe_hwmon_set_user_fan_pwm(struct xe_hwmon *hwmon, u8 fan, u8 pwm, boo
 			  fi->fan_table[USER_FAN_TABLE].fcp[i].speed);
 	}
 	fi->fan_table[USER_FAN_TABLE].point_count = MIN_FAN_CONTROL_POINTS;
+	fi->fan_table[USER_FAN_TABLE].temp_staged = 0;
+	fi->fan_table[USER_FAN_TABLE].speed_staged = 0;
 
 	fi->pwm_enable_mode = XE_FAN_PWM_MANUAL_USER_TABLE;
 	fi->is_full_speed = full_speed;
 	return 0;
 }
 
+#define XE_CURVE_IDX(fan, point)	(((fan) << 8) | (point))
+#define XE_CURVE_FAN(idx)		((u8)(((idx) >> 8) & 0xff))
+#define XE_CURVE_POINT(idx)		((u8)((idx) & 0xff))
+
+static int
+xe_hwmon_decode_curve_index(u32 index, u8 *fan, u8 *point)
+{
+	u8 local_fan = XE_CURVE_FAN(index);
+	u8 local_point = XE_CURVE_POINT(index);
+
+	if (local_fan >= FAN_MAX || local_point >= MAX_FAN_CONTROL_POINTS)
+		return -EINVAL;
+
+	*fan = local_fan;
+	*point = local_point;
+
+	return 0;
+}
+
+static inline enum fan_table_type xe_hwmon_get_active_fan_table(struct xe_hwmon *hwmon, u8 fan)
+{
+	if (hwmon->fi[fan].pwm_enable_mode == XE_FAN_PWM_AUTO_STOCK_TABLE)
+		return STOCK_FAN_TABLE;
+	else
+		return USER_FAN_TABLE;
+}
+
+static ssize_t
+xe_hwmon_pwm_auto_point_temp_show(struct device *dev,
+				  struct device_attribute *attr, char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct xe_hwmon *hwmon = dev_get_drvdata(dev);
+	struct xe_hwmon_fan_info *fi;
+	u32 point_count;
+	u8 fan;
+	u8 point;
+	u8 temp;
+	int ret;
+	enum fan_table_type active_table;
+
+	ret = xe_hwmon_decode_curve_index(sattr->index, &fan, &point);
+	if (ret)
+		return ret;
+
+	guard(xe_pm_runtime)(hwmon->xe);
+
+	mutex_lock(&hwmon->hwmon_lock);
+
+	fi = &hwmon->fi[fan];
+	active_table = xe_hwmon_get_active_fan_table(hwmon, fan);
+
+	ret = xe_hwmon_get_fan_point_count(hwmon, fan, &point_count, active_table);
+	if (ret)
+		goto unlock;
+
+	/* Slots beyond the active curve can still be staged for the next curve. */
+	if (point >= point_count &&
+	    (active_table != USER_FAN_TABLE ||
+	    !(fi->fan_table[USER_FAN_TABLE].temp_staged & BIT(point))))
+		temp = 0;
+	else if (point >= point_count)
+		temp = fi->fan_table[USER_FAN_TABLE].staged_fcp[point].temp;
+	else
+		temp = fi->fan_table[active_table].fcp[point].temp;
+	ret = sysfs_emit(buf, "%u\n", temp * MILLIDEGREE_PER_DEGREE);
+
+unlock:
+	mutex_unlock(&hwmon->hwmon_lock);
+
+	return ret;
+}
+
+static int xe_hwmon_update_user_fan_point(struct xe_hwmon *hwmon, u8 fan, u32 point,
+					  bool is_temp, u8 value)
+{
+	struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
+	struct fan_table *table;
+	u32 point_count;
+	int ret;
+
+	table = &fi->fan_table[USER_FAN_TABLE];
+
+	if (is_temp) {
+		table->staged_fcp[point].temp = value;
+		table->temp_staged |= BIT(point);
+	} else {
+		table->staged_fcp[point].speed = value;
+		table->speed_staged |= BIT(point);
+	}
+
+	/* Wait for a complete prefix; (0, 0) ends the curve without becoming a point. */
+	for (point_count = 0; point_count < MAX_FAN_CONTROL_POINTS; point_count++) {
+		if (!(table->temp_staged & BIT(point_count)) ||
+		    !(table->speed_staged & BIT(point_count)))
+			return 0;
+		if (!table->staged_fcp[point_count].temp &&
+		    !table->staged_fcp[point_count].speed)
+			break;
+	}
+
+	if (point_count < MIN_FAN_CONTROL_POINTS)
+		return -EINVAL;
+
+	ret = xe_hwmon_commit_user_fan_table(hwmon, fan, table->staged_fcp, point_count);
+	if (ret)
+		return ret;
+
+	/* Publish the new curve only after firmware accepts its point count. */
+	memcpy(table->fcp, table->staged_fcp, point_count * sizeof(table->fcp[0]));
+	table->point_count = point_count;
+	table->temp_staged = 0;
+	table->speed_staged = 0;
+	fi->pwm_enable_mode = XE_FAN_PWM_MANUAL_USER_TABLE;
+	fi->is_full_speed = false;
+	return 0;
+}
+
+static int xe_hwmon_get_u8_from_sysfs(long val, bool is_temp, u8 *out)
+{
+	long hw_val;
+
+	if (is_temp)
+		hw_val = DIV_ROUND_CLOSEST(val, MILLIDEGREE_PER_DEGREE);
+	else
+		hw_val = DIV_ROUND_CLOSEST(val * 100, U8_MAX);
+
+	if (hw_val < 0 || hw_val > U8_MAX)
+		return -EINVAL;
+
+	*out = hw_val;
+
+	return 0;
+}
+
+static ssize_t
+xe_hwmon_pwm_auto_point_temp_store(struct device *dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct xe_hwmon *hwmon = dev_get_drvdata(dev);
+	struct xe_hwmon_fan_info *fi;
+	u8 fan;
+	u8 point;
+	u8 temp;
+	long val;
+	int ret;
+
+	ret = xe_hwmon_decode_curve_index(sattr->index, &fan, &point);
+	if (ret)
+		return ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	ret = xe_hwmon_get_u8_from_sysfs(val, true, &temp);
+	if (ret)
+		return ret;
+
+	guard(xe_pm_runtime)(hwmon->xe);
+
+	mutex_lock(&hwmon->hwmon_lock);
+	fi = &hwmon->fi[fan];
+
+	if (fi->pwm_enable_mode != XE_FAN_PWM_MANUAL_USER_TABLE) {
+		drm_err(&hwmon->xe->drm,
+			"pwm%d_enable not in manual mode; cannot update temp point %d\n",
+			fan, point);
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	drm_dbg(&hwmon->xe->drm,
+		"staging fan %d point %d temp to %u\n", fan, point, temp);
+	ret = xe_hwmon_update_user_fan_point(hwmon, fan, point, true, temp);
+
+unlock:
+	mutex_unlock(&hwmon->hwmon_lock);
+
+	return ret ? ret : count;
+}
+
+static ssize_t
+xe_hwmon_pwm_auto_point_pwm_show(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct xe_hwmon *hwmon = dev_get_drvdata(dev);
+	struct xe_hwmon_fan_info *fi;
+	u8 fan;
+	u8 point;
+	u32 point_count;
+	int ret;
+	enum fan_table_type active_table;
+
+	ret = xe_hwmon_decode_curve_index(sattr->index, &fan, &point);
+	if (ret)
+		return ret;
+
+	guard(xe_pm_runtime)(hwmon->xe);
+
+	mutex_lock(&hwmon->hwmon_lock);
+
+	fi = &hwmon->fi[fan];
+	active_table = xe_hwmon_get_active_fan_table(hwmon, fan);
+
+	ret = xe_hwmon_get_fan_point_count(hwmon, fan, &point_count, active_table);
+	if (ret)
+		goto unlock;
+
+	if (point >= point_count &&
+	    (active_table != USER_FAN_TABLE ||
+	    !(fi->fan_table[USER_FAN_TABLE].speed_staged & BIT(point))))
+		ret = sysfs_emit(buf, "0\n");
+	else
+		ret = sysfs_emit(buf, "%u\n",
+				 DIV_ROUND_CLOSEST((point >= point_count ?
+						    fi->fan_table[USER_FAN_TABLE].staged_fcp[point].speed :
+						    fi->fan_table[active_table].fcp[point].speed) * U8_MAX,
+						    100));
+
+unlock:
+	mutex_unlock(&hwmon->hwmon_lock);
+
+	return ret;
+}
+
+static ssize_t
+xe_hwmon_pwm_auto_point_pwm_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+	struct xe_hwmon *hwmon = dev_get_drvdata(dev);
+	struct xe_hwmon_fan_info *fi;
+	long val;
+	u8 point;
+	u8 fan;
+	u8 pwm;
+	int ret;
+
+	ret = xe_hwmon_decode_curve_index(sattr->index, &fan, &point);
+	if (ret)
+		return ret;
+
+	ret = kstrtol(buf, 10, &val);
+	if (ret)
+		return ret;
+
+	ret = xe_hwmon_get_u8_from_sysfs(val, false, &pwm);
+	if (ret)
+		return ret;
+
+	guard(xe_pm_runtime)(hwmon->xe);
+
+	mutex_lock(&hwmon->hwmon_lock);
+	fi = &hwmon->fi[fan];
+
+	if (fi->pwm_enable_mode != XE_FAN_PWM_MANUAL_USER_TABLE) {
+		drm_err(&hwmon->xe->drm,
+			"pwm%d_enable is not in manual user mode, cannot update pwm point %d\n",
+			fan, point);
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	/* Preserve zero for the (0, 0) end marker instead of clamping it. */
+	if (pwm)
+		pwm = max_t(u8, pwm, min_t(u32, fi->min_pwm, U8_MAX));
+
+	drm_dbg(&hwmon->xe->drm, "staging fan %d point %d pwm to %u\n",
+		fan, point, pwm);
+	ret = xe_hwmon_update_user_fan_point(hwmon, fan, point, false, pwm);
+
+unlock:
+	mutex_unlock(&hwmon->hwmon_lock);
+
+	return ret ? ret : count;
+}
+
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(0, 0));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(0, 0));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(0, 1));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(0, 1));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(0, 2));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(0, 2));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(0, 3));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(0, 3));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(0, 4));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(0, 4));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(0, 5));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(0, 5));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(0, 6));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(0, 6));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(0, 7));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(0, 7));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(0, 8));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(0, 8));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(0, 9));
+static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(0, 9));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(1, 0));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(1, 0));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(1, 1));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(1, 1));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point3_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(1, 2));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point3_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(1, 2));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point4_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(1, 3));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point4_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(1, 3));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point5_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(1, 4));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point5_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(1, 4));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point6_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(1, 5));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point6_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(1, 5));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point7_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(1, 6));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point7_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(1, 6));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point8_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(1, 7));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point8_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(1, 7));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point9_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(1, 8));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point9_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(1, 8));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point10_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(1, 9));
+static SENSOR_DEVICE_ATTR(pwm2_auto_point10_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(1, 9));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(2, 0));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(2, 0));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(2, 1));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(2, 1));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point3_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(2, 2));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point3_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(2, 2));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point4_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(2, 3));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point4_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(2, 3));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point5_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(2, 4));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point5_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(2, 4));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point6_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(2, 5));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point6_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(2, 5));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point7_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(2, 6));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point7_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(2, 6));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point8_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(2, 7));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point8_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(2, 7));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point9_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(2, 8));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point9_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(2, 8));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point10_temp, 0644,
+			  xe_hwmon_pwm_auto_point_temp_show,
+			  xe_hwmon_pwm_auto_point_temp_store,
+			  XE_CURVE_IDX(2, 9));
+static SENSOR_DEVICE_ATTR(pwm3_auto_point10_pwm, 0644,
+			  xe_hwmon_pwm_auto_point_pwm_show,
+			  xe_hwmon_pwm_auto_point_pwm_store,
+			  XE_CURVE_IDX(2, 9));
+
+static struct attribute *hwmon_curve_attributes[] = {
+	&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point9_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point10_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point9_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm1_auto_point10_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point5_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point6_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point7_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point8_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point9_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point10_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point5_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point6_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point7_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point8_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point9_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm2_auto_point10_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point5_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point6_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point7_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point8_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point9_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point10_temp.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point5_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point6_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point7_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point8_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point9_pwm.dev_attr.attr,
+	&sensor_dev_attr_pwm3_auto_point10_pwm.dev_attr.attr,
+	NULL
+};
+
+static umode_t xe_hwmon_curve_attributes_visible(struct kobject *kobj,
+						 struct attribute *attr, int index)
+{
+	struct device *dev = kobj_to_dev(kobj);
+	struct xe_hwmon *hwmon = dev_get_drvdata(dev);
+	u32 attrs_per_fan = 2 * MAX_FAN_CONTROL_POINTS;
+	u32 fan = index / attrs_per_fan;
+
+	if (!hwmon->xe->info.has_fan_control || !IS_FAN_ENABLED(fan))
+		return 0;
+
+	/* All slots must exist at registration, before the user curve has been staged. */
+	return attr->mode;
+}
+
+static const struct attribute_group hwmon_curve_attrgroup = {
+	.attrs = hwmon_curve_attributes,
+	.is_visible = xe_hwmon_curve_attributes_visible,
+};
+
 static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
 {
 	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
@@ -2051,7 +2740,7 @@ xe_hwmon_pwm_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
 		xe_dbg(hwmon->xe, "pwm read for fan %d: %ld\n", channel, *val);
 		break;
 	case hwmon_pwm_enable:
-		*val = fi->pwm_enable_mode;
+		*val = fi->is_full_speed ? XE_FAN_PWM_FULL_SPEED : fi->pwm_enable_mode;
 		break;
 	default:
 		ret = -EOPNOTSUPP;
@@ -2127,6 +2816,8 @@ xe_hwmon_pwm_write(struct xe_hwmon *hwmon, u32 attr, int channel, long val)
 			       channel);
 			fi->pwm_enable_mode = XE_FAN_PWM_AUTO_STOCK_TABLE;
 			fi->is_full_speed = false;
+			fi->fan_table[USER_FAN_TABLE].temp_staged = 0;
+			fi->fan_table[USER_FAN_TABLE].speed_staged = 0;
 		} else {
 			ret = -EINVAL;
 		}
-- 
2.25.1


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

* [PATCH v3 7/9] drm/xe/hwmon: Add kernel-doc for fan control
  2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
                   ` (5 preceding siblings ...)
  2026-10-15 19:07 ` [PATCH v3 6/9] drm/xe/hwmon: Enable fan curve control support Karthik Poosa
@ 2026-10-15 19:07 ` Karthik Poosa
  2026-10-15 19:07 ` [PATCH v3 8/9] drm/xe/hwmon: preserve fan user table across suspend resume Karthik Poosa
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 26+ messages in thread
From: Karthik Poosa @ 2026-10-15 19:07 UTC (permalink / raw)
  To: intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi, soham.purkait,
	ravi.kishore.koppuravuri, Karthik Poosa

Add kernel-doc for xe hwmon fan control and describe the fan control
model built around firmware stock tables and driver-managed user tables.

Document the exposed sysfs files for fan speed, maximum speed, pwm
control, pwm mode selection, and per-point fan curve temperature/PWM
programming.

This makes the hwmon fan control userspace interface easier to discover
and understand.

Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
Assisted-by: LLM
---
 drivers/gpu/drm/xe/xe_hwmon.c | 43 +++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
index de2adb56d15b..aa3c921407b5 100644
--- a/drivers/gpu/drm/xe/xe_hwmon.c
+++ b/drivers/gpu/drm/xe/xe_hwmon.c
@@ -139,6 +139,49 @@ struct xe_hwmon_energy_info {
 	long accum_energy;
 };
 
+/**
+ * DOC: Xe fan control
+ *
+ * Xe fan control is exposed through the hwmon pwm and fan interfaces when the
+ * platform advertises PCODE-backed fan management support.
+ *
+ * The implementation tracks two fan tables per fan:
+ *
+ * - A stock table read from firmware through PCODE.
+ * - A user table cached in the driver and programmed back through PCODE.
+ *
+ * The pwmN_enable sysfs mode selects how those tables are used:
+ *
+ * - ``XE_FAN_PWM_AUTO_STOCK_TABLE`` restores automatic control using the stock
+ *   firmware table.
+ * - ``XE_FAN_PWM_MANUAL_USER_TABLE`` enables the user table for manual control.
+ * - ``XE_FAN_PWM_FULL_SPEED`` reuses the user table path but programs every
+ *   point to 100 percent duty cycle as a full-speed override.
+ *
+ * The fan-control sysfs files are:
+ *
+ * - ``fanN_input`` reports the measured fan speed in RPM.
+ * - ``fanN_max`` reports the maximum supported fan speed in RPM.
+ * - ``pwmN`` reads or sets the manual PWM duty cycle in the hwmon 0..255
+ *   range. Manual writes are accepted only while ``pwmN_enable`` is set to
+ *   ``XE_FAN_PWM_MANUAL_USER_TABLE``.
+ * - ``pwmN_enable`` selects stock automatic mode, manual user-table mode, or
+ *   full-speed override.
+ * - ``pwmN_auto_pointM_temp`` exposes the temperature threshold for user-table
+ *   point ``M`` in millidegrees Celsius.
+ * - ``pwmN_auto_pointM_pwm`` exposes the PWM value for user-table point ``M``
+ *   in the hwmon 0..255 range.
+ *
+ * Writes to pwmN_auto_pointM_temp and pwmN_auto_pointM_pwm update the cached
+ * user table entries. The driver commits the full user table once the last
+ * point has both temperature and PWM values, which keeps intermediate sysfs
+ * writes from pushing partially updated curves to firmware.
+ *
+ * Writes to pwmN provide a constant manual duty cycle by rewriting every point
+ * in the active user table to the same PWM value, clamped against the minimum
+ * duty cycle reported by firmware for that fan.
+ */
+
 enum xe_fan_pwm_enable_mode {
 	/** @XE_FAN_PWM_FULL_SPEED: force all user table points to full speed */
 	XE_FAN_PWM_FULL_SPEED = 0,
-- 
2.25.1


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

* [PATCH v3 8/9] drm/xe/hwmon: preserve fan user table across suspend resume
  2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
                   ` (6 preceding siblings ...)
  2026-10-15 19:07 ` [PATCH v3 7/9] drm/xe/hwmon: Add kernel-doc for fan control Karthik Poosa
@ 2026-10-15 19:07 ` Karthik Poosa
  2026-10-15 19:07 ` [PATCH v3 9/9] drm/xe/hwmon: Update fan info after late binding Karthik Poosa
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 26+ messages in thread
From: Karthik Poosa @ 2026-10-15 19:07 UTC (permalink / raw)
  To: intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi, soham.purkait,
	ravi.kishore.koppuravuri, Karthik Poosa

Save and restore active fan user tables over suspend/resume via new
xe_hwmon PM hooks, and run restore, only when d3cold is allowed.

v2: Use xe_pcode_read() instead of xe_pcode_read_timeout().

Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
Assisted-by: LLM
---
 drivers/gpu/drm/xe/xe_hwmon.c | 136 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_hwmon.h |   4 +
 drivers/gpu/drm/xe/xe_pm.c    |   9 +++
 3 files changed, 149 insertions(+)

diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
index aa3c921407b5..d9f6cc9c81f6 100644
--- a/drivers/gpu/drm/xe/xe_hwmon.c
+++ b/drivers/gpu/drm/xe/xe_hwmon.c
@@ -251,6 +251,8 @@ struct xe_hwmon_fan_info {
 	u8 pwm_enable_mode;
 	/** @is_full_speed: flag indicating if fan is in full speed */
 	bool is_full_speed;
+	/** @restore_user_table: restore user fan table on next resume */
+	bool restore_user_table;
 };
 
 /**
@@ -3122,4 +3124,138 @@ int xe_hwmon_register(struct xe_device *xe)
 	xe->hwmon = NULL;
 	return ret;
 }
+
+/**
+ * xe_hwmon_suspend - Save hwmon state before suspend
+ * @xe: xe device instance
+ *
+ * Save any hwmon runtime state that must survive PM suspend transitions.
+ */
+void xe_hwmon_suspend(struct xe_device *xe)
+{
+	struct xe_hwmon *hwmon = xe->hwmon;
+	struct xe_tile *root_tile;
+	int fan;
+
+	if (!hwmon || !xe->info.has_fan_control)
+		return;
+
+	/*
+	 * User fan-table restore is limited to d3cold flows, so skip snapshot
+	 * work when d3cold is not allowed for this device.
+	 */
+	if (!xe->d3cold.allowed) {
+		xe_dbg(xe, "d3cold not allowed, skipping fan user-table snapshot\n");
+		return;
+	}
+
+	root_tile = xe_device_get_root_tile(hwmon->xe);
+
+	mutex_lock(&hwmon->hwmon_lock);
+
+	for (fan = 0; fan < FAN_MAX; fan++) {
+		struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
+		struct fan_control_point points[MAX_FAN_CONTROL_POINTS];
+		u32 point_count = 0;
+		int point;
+		int ret;
+
+		if (!IS_FAN_ENABLED(fan))
+			continue;
+
+		fi->restore_user_table = false;
+		if (fi->pwm_enable_mode == XE_FAN_PWM_AUTO_STOCK_TABLE)
+			continue;
+
+		ret = xe_hwmon_get_fan_point_count(hwmon, fan, &point_count, USER_FAN_TABLE);
+		if (ret || point_count < MIN_FAN_CONTROL_POINTS) {
+			xe_warn(hwmon->xe,
+				"fan %d point count before suspend invalid, ret=%d, count=%u\n",
+				fan, ret, point_count);
+			continue;
+		}
+
+		for (point = 0; point < point_count; point++) {
+			u32 fcp = FCP_INDEX(USER_FAN_TABLE, point);
+
+			ret = xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL,
+								  FSC_READ_FAN_TABLE, fan),
+					    &fcp, NULL);
+			if (ret) {
+				xe_warn(hwmon->xe,
+					"fan %d user point %d before suspend failed, ret=%d\n",
+					fan, point, ret);
+				break;
+			}
+
+			points[point].temp =
+				REG_FIELD_GET(FAN_CONTROL_POINT_TEMP_MASK, fcp);
+			points[point].speed =
+				REG_FIELD_GET(FAN_CONTROL_POINT_SPEED_MASK, fcp);
+		}
+		if (ret)
+			continue;
+
+		memcpy(fi->fan_table[USER_FAN_TABLE].fcp, points,
+		       point_count * sizeof(points[0]));
+		fi->fan_table[USER_FAN_TABLE].point_count = point_count;
+		fi->restore_user_table = true;
+		xe_dbg(hwmon->xe,
+		       "fan %d user table snapshot taken before suspend, point_count=%u\n", fan,
+		       point_count);
+	}
+
+	mutex_unlock(&hwmon->hwmon_lock);
+}
+
+/**
+ * xe_hwmon_resume - Restore hwmon state after resume
+ * @xe: xe device instance
+ *
+ * Restore any hwmon runtime state that was saved across suspend.
+ */
+void xe_hwmon_resume(struct xe_device *xe)
+{
+	struct xe_hwmon *hwmon = xe->hwmon;
+	int fan;
+
+	if (!hwmon || !xe->info.has_fan_control)
+		return;
+
+	if (!xe->d3cold.allowed) {
+		xe_dbg(xe, "d3cold not allowed, skipping fan user-table restore\n");
+		return;
+	}
+
+	mutex_lock(&hwmon->hwmon_lock);
+
+	for (fan = 0; fan < FAN_MAX; fan++) {
+		struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
+		int ret;
+
+		if (!IS_FAN_ENABLED(fan))
+			continue;
+
+		if (!fi->restore_user_table) {
+			xe_dbg(xe, "fan %d user table restore not required\n", fan);
+			continue;
+		}
+
+		/* Re-program cached user-table settings for fans active before suspend. */
+		ret = xe_hwmon_activate_user_fan_table(hwmon, fan,
+						       fi->is_full_speed,
+						       USER_FAN_TABLE);
+		if (ret) {
+			xe_warn(xe, "failed to restore fan %d user table after resume, ret=%d\n",
+				fan, ret);
+			continue;
+		}
+
+		xe_dbg(xe, "fan %d user table restored\n", fan);
+		fi->restore_user_table = false;
+	}
+
+	mutex_unlock(&hwmon->hwmon_lock);
+}
+
 MODULE_IMPORT_NS("INTEL_PMT_TELEMETRY");
diff --git a/drivers/gpu/drm/xe/xe_hwmon.h b/drivers/gpu/drm/xe/xe_hwmon.h
index d02c1bfe8c0a..6c6f30208508 100644
--- a/drivers/gpu/drm/xe/xe_hwmon.h
+++ b/drivers/gpu/drm/xe/xe_hwmon.h
@@ -12,8 +12,12 @@ struct xe_device;
 
 #if IS_REACHABLE(CONFIG_HWMON)
 int xe_hwmon_register(struct xe_device *xe);
+void xe_hwmon_suspend(struct xe_device *xe);
+void xe_hwmon_resume(struct xe_device *xe);
 #else
 static inline int xe_hwmon_register(struct xe_device *xe) { return 0; };
+static inline void xe_hwmon_suspend(struct xe_device *xe) {}
+static inline void xe_hwmon_resume(struct xe_device *xe) {}
 #endif
 
 #endif /* _XE_HWMON_H_ */
diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c
index 4a745c3a933b..e5697b3893af 100644
--- a/drivers/gpu/drm/xe/xe_pm.c
+++ b/drivers/gpu/drm/xe/xe_pm.c
@@ -23,6 +23,7 @@
 #include "xe_i2c.h"
 #include "xe_irq.h"
 #include "xe_late_bind_fw.h"
+#include "xe_hwmon.h"
 #include "xe_pcode.h"
 #include "xe_printk.h"
 #include "xe_pxp.h"
@@ -189,6 +190,8 @@ int xe_pm_suspend(struct xe_device *xe)
 	for_each_gt(gt, xe, id)
 		xe_gt_suspend_prepare(gt);
 
+	xe_hwmon_suspend(xe);
+
 	xe_display_pm_suspend(xe);
 
 	/* FIXME: Super racey... */
@@ -290,6 +293,8 @@ int xe_pm_resume(struct xe_device *xe)
 
 	xe_late_bind_fw_load(&xe->late_bind);
 
+	xe_hwmon_resume(xe);
+
 	drm_dbg(&xe->drm, "Device resumed\n");
 	xe_pm_block_end_signalling();
 	return 0;
@@ -615,6 +620,8 @@ int xe_pm_runtime_suspend(struct xe_device *xe)
 	if (err)
 		goto out;
 
+	xe_hwmon_suspend(xe);
+
 	/*
 	 * Applying lock for entire list op as xe_ttm_bo_destroy and xe_bo_move_notify
 	 * also checks and deletes bo entry from user fault list.
@@ -726,6 +733,8 @@ int xe_pm_runtime_resume(struct xe_device *xe)
 
 	xe_pxp_pm_resume(xe->pxp);
 
+	xe_hwmon_resume(xe);
+
 	if (IS_VF_CCS_READY(xe))
 		xe_sriov_vf_ccs_register_context(xe);
 
-- 
2.25.1


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

* [PATCH v3 9/9] drm/xe/hwmon: Update fan info after late binding
  2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
                   ` (7 preceding siblings ...)
  2026-10-15 19:07 ` [PATCH v3 8/9] drm/xe/hwmon: preserve fan user table across suspend resume Karthik Poosa
@ 2026-10-15 19:07 ` Karthik Poosa
  2026-10-15 19:46 ` ✗ CI.checkpatch: warning for Add fan control support Patchwork
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 26+ messages in thread
From: Karthik Poosa @ 2026-10-15 19:07 UTC (permalink / raw)
  To: intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi, soham.purkait,
	ravi.kishore.koppuravuri, Karthik Poosa

Add xe_hwmon_fan_update_post_lb() to update fan info after late binding.
Add param is_init into xe_hwmon_read_fan_control_info() to avoid
resetting user pwm mode post-LB.
Call init path with is_init=true from preregistration.

Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
Assisted-by: LLM
---
 drivers/gpu/drm/xe/xe_hwmon.c        | 41 +++++++++++++++++++++++++---
 drivers/gpu/drm/xe/xe_hwmon.h        |  2 ++
 drivers/gpu/drm/xe/xe_late_bind_fw.c |  3 ++
 3 files changed, 42 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
index d9f6cc9c81f6..e91bcacdfe93 100644
--- a/drivers/gpu/drm/xe/xe_hwmon.c
+++ b/drivers/gpu/drm/xe/xe_hwmon.c
@@ -2068,7 +2068,7 @@ static const struct attribute_group hwmon_curve_attrgroup = {
 	.is_visible = xe_hwmon_curve_attributes_visible,
 };
 
-static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
+static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon, bool is_init)
 {
 	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
 	int point;
@@ -2129,8 +2129,13 @@ static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
 			       fi->fan_table[STOCK_FAN_TABLE].fcp[point].speed);
 		}
 
-		/* Set PWM enable mode to automatic i.e stock table in use. */
-		fi->pwm_enable_mode = XE_FAN_PWM_AUTO_STOCK_TABLE;
+		/*
+		 * Set PWM enable mode to automatic i.e stock table in use, only during init.
+		 * For late binding, the mode is already set by the user and should not be
+		 * overridden.
+		 */
+		if (is_init)
+			fi->pwm_enable_mode = XE_FAN_PWM_AUTO_STOCK_TABLE;
 
 		/* Read minimum fan PWM */
 		ret = xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_FAN_MIN_PWM, fan,
@@ -3070,7 +3075,7 @@ xe_hwmon_get_preregistration_info(struct xe_hwmon *hwmon)
 				xe_hwmon_fan_input_read(hwmon, channel, &fan_speed);
 
 		/* Fan control tables initialization */
-		if (xe_hwmon_read_fan_control_info(hwmon))
+		if (xe_hwmon_read_fan_control_info(hwmon, true))
 			xe_warn(hwmon->xe, "Fan control tables are not available\n");
 	}
 	return xe_hwmon_init_temp_info(hwmon);
@@ -3258,4 +3263,32 @@ void xe_hwmon_resume(struct xe_device *xe)
 	mutex_unlock(&hwmon->hwmon_lock);
 }
 
+/**
+ * xe_hwmon_fan_update_post_lb - Update fan info after late binding
+ * @xe: xe device instance
+ *
+ * This function reads the number of fans and their stock table after late binding.
+ */
+void xe_hwmon_fan_update_post_lb(struct xe_device *xe)
+{
+	struct xe_hwmon *hwmon = xe->hwmon;
+
+	if (!hwmon || !xe->info.has_fan_control)
+		return;
+
+	mutex_lock(&hwmon->hwmon_lock);
+
+	if (xe_hwmon_get_fan_enable_mask(hwmon)) {
+		xe_warn(hwmon->xe, "Failed to read fan enable mask after LB\n");
+		goto unlock;
+	}
+
+	/* Read stock tables. */
+	if (xe_hwmon_read_fan_control_info(hwmon, false))
+		xe_warn(hwmon->xe, "Failed to read stock fan tables after LB\n");
+
+unlock:
+	mutex_unlock(&hwmon->hwmon_lock);
+}
+
 MODULE_IMPORT_NS("INTEL_PMT_TELEMETRY");
diff --git a/drivers/gpu/drm/xe/xe_hwmon.h b/drivers/gpu/drm/xe/xe_hwmon.h
index 6c6f30208508..7198d7a4a1be 100644
--- a/drivers/gpu/drm/xe/xe_hwmon.h
+++ b/drivers/gpu/drm/xe/xe_hwmon.h
@@ -14,10 +14,12 @@ struct xe_device;
 int xe_hwmon_register(struct xe_device *xe);
 void xe_hwmon_suspend(struct xe_device *xe);
 void xe_hwmon_resume(struct xe_device *xe);
+void xe_hwmon_fan_update_post_lb(struct xe_device *xe);
 #else
 static inline int xe_hwmon_register(struct xe_device *xe) { return 0; };
 static inline void xe_hwmon_suspend(struct xe_device *xe) {}
 static inline void xe_hwmon_resume(struct xe_device *xe) {}
+static inline void xe_hwmon_fan_update_post_lb(struct xe_device *xe) {}
 #endif
 
 #endif /* _XE_HWMON_H_ */
diff --git a/drivers/gpu/drm/xe/xe_late_bind_fw.c b/drivers/gpu/drm/xe/xe_late_bind_fw.c
index 768442ca7da6..34295418ef50 100644
--- a/drivers/gpu/drm/xe/xe_late_bind_fw.c
+++ b/drivers/gpu/drm/xe/xe_late_bind_fw.c
@@ -13,6 +13,7 @@
 #include <drm/drm_print.h>
 
 #include "xe_device.h"
+#include "xe_hwmon.h"
 #include "xe_late_bind_fw.h"
 #include "xe_pcode.h"
 #include "xe_pcode_api.h"
@@ -252,6 +253,8 @@ static void xe_late_bind_work(struct work_struct *work)
 	if (!ret) {
 		drm_dbg(&xe->drm, "Load %s firmware successful\n",
 			fw_id_to_name[lbfw->id]);
+		if (fw_id_to_name[lbfw->id] == XE_LB_FW_FAN_CONTROL)
+			xe_hwmon_fan_update_post_lb(late_bind_to_xe(late_bind));
 		goto out;
 	}
 
-- 
2.25.1


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

* ✗ CI.checkpatch: warning for Add fan control support
  2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
                   ` (8 preceding siblings ...)
  2026-10-15 19:07 ` [PATCH v3 9/9] drm/xe/hwmon: Update fan info after late binding Karthik Poosa
@ 2026-10-15 19:46 ` Patchwork
  2026-10-15 19:48 ` ✓ CI.KUnit: success " Patchwork
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 26+ messages in thread
From: Patchwork @ 2026-10-15 19:46 UTC (permalink / raw)
  To: Karthik Poosa; +Cc: intel-xe

== Series Details ==

Series: Add fan control support
URL   : https://patchwork.freedesktop.org/series/176241/
State : warning

== Summary ==

+ KERNEL=/kernel
+ git clone https://gitlab.freedesktop.org/drm/maintainer-tools mt
Cloning into 'mt'...
warning: redirecting to https://gitlab.freedesktop.org/drm/maintainer-tools.git/
+ git -C mt rev-list -n1 origin/master
6bef5ce5c74dc76b4ee69ab2832c0d1fd63c91c7
+ cd /kernel
+ git config --global --add safe.directory /kernel
+ git log -n1
commit effc9af214bf8274978b2a2a9b1272a2f1552bad
Author: Karthik Poosa <karthik.poosa@intel.com>
Date:   Fri Oct 16 00:37:51 2026 +0530

    drm/xe/hwmon: Update fan info after late binding
    
    Add xe_hwmon_fan_update_post_lb() to update fan info after late binding.
    Add param is_init into xe_hwmon_read_fan_control_info() to avoid
    resetting user pwm mode post-LB.
    Call init path with is_init=true from preregistration.
    
    Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
    Assisted-by: LLM
+ /mt/dim checkpatch 551605da81c33c1a2352b6a6116360609798f171 drm-intel
98c07dc5f32f drm/xe/hwmon: initialize fan-control backend and table cache
316637a3ace5 drm/xe/hwmon: expose fanN_max
59834ef7e36a drm/xe/pcode: add ordered write batch helper
57c23068adf1 drm/xe/hwmon: expose pwm[1-3]
8d1201dfe031 drm/xe/hwmon: expose pwm[1-3]_enable
7867a5423a8e drm/xe/hwmon: Enable fan curve control support
-:376: WARNING:LONG_LINE: line length of 107 exceeds 100 columns
#376: FILE: drivers/gpu/drm/xe/xe_hwmon.c:1638:
+						    fi->fan_table[USER_FAN_TABLE].staged_fcp[point].speed :

-:377: WARNING:LONG_LINE: line length of 107 exceeds 100 columns
#377: FILE: drivers/gpu/drm/xe/xe_hwmon.c:1639:
+						    fi->fan_table[active_table].fcp[point].speed) * U8_MAX,

total: 0 errors, 2 warnings, 0 checks, 743 lines checked
9c8f93cb247b drm/xe/hwmon: Add kernel-doc for fan control
450139e452cf drm/xe/hwmon: preserve fan user table across suspend resume
effc9af214bf drm/xe/hwmon: Update fan info after late binding



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

* ✓ CI.KUnit: success for Add fan control support
  2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
                   ` (9 preceding siblings ...)
  2026-10-15 19:46 ` ✗ CI.checkpatch: warning for Add fan control support Patchwork
@ 2026-10-15 19:48 ` Patchwork
  2026-10-15 21:01 ` ✗ Xe.CI.BAT: failure " Patchwork
  2026-10-16  7:56 ` ✗ Xe.CI.FULL: " Patchwork
  12 siblings, 0 replies; 26+ messages in thread
From: Patchwork @ 2026-10-15 19:48 UTC (permalink / raw)
  To: Karthik Poosa; +Cc: intel-xe

== Series Details ==

Series: Add fan control support
URL   : https://patchwork.freedesktop.org/series/176241/
State : success

== Summary ==

+ trap cleanup EXIT
+ kunitconfigs=('/kernel/drivers/gpu/tests/.kunitconfig' '/kernel/drivers/gpu/drm/xe/.kunitconfig' '/kernel/drivers/gpu/drm/tests/.kunitconfig' '/kernel/drivers/gpu/drm/ttm/tests/.kunitconfig' '/kernel/drivers/dma-buf/.kunitconfig')
+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/gpu/tests/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/tests/.kunitconfig
[19:46:50] Configuring KUnit Kernel ...
Generating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[19:46:54] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[19:47:14] Starting KUnit Kernel (1/1)...
[19:47:14] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[19:47:15] ================= gpu_buddy (14 subtests) ==================
[19:47:15] [PASSED] gpu_test_buddy_alloc_limit
[19:47:15] [PASSED] gpu_test_buddy_alloc_optimistic
[19:47:15] [PASSED] gpu_test_buddy_alloc_pessimistic
[19:47:15] [PASSED] gpu_test_buddy_alloc_pathological
[19:47:15] [PASSED] gpu_test_buddy_alloc_contiguous
[19:47:15] [PASSED] gpu_test_buddy_alloc_clear
[19:47:15] [PASSED] gpu_test_buddy_alloc_range
[19:47:15] [PASSED] gpu_test_buddy_alloc_range_bias
[19:47:16] [PASSED] gpu_test_buddy_fragmentation_performance
[19:47:16] [PASSED] gpu_test_buddy_dirty_tracker_performance
[19:47:16] [PASSED] gpu_test_buddy_alloc_exceeds_max_order
[19:47:16] [PASSED] gpu_test_buddy_offset_aligned_allocation
[19:47:16] [PASSED] gpu_test_buddy_subtree_offset_alignment_stress
[19:47:16] [PASSED] gpu_test_buddy_addr_to_block
[19:47:16] ==================== [PASSED] gpu_buddy ====================
[19:47:16] ============================================================
[19:47:16] Testing complete. Ran 14 tests: passed: 14
[19:47:16] Elapsed time: 26.789s total, 4.426s configuring, 20.395s building, 1.899s running

+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/gpu/drm/xe/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/xe/.kunitconfig
[19:47:17] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[19:47:18] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[19:47:57] Starting KUnit Kernel (1/1)...
[19:47:57] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[19:47:58] ================== guc_buf (11 subtests) ===================
[19:47:58] [PASSED] test_smallest
[19:47:58] [PASSED] test_largest
[19:47:58] [PASSED] test_granular
[19:47:58] [PASSED] test_unique
[19:47:58] [PASSED] test_overlap
[19:47:58] [PASSED] test_reusable
[19:47:58] [PASSED] test_too_big
[19:47:58] [PASSED] test_flush
[19:47:58] [PASSED] test_lookup
[19:47:58] [PASSED] test_data
[19:47:58] [PASSED] test_class
[19:47:58] ===================== [PASSED] guc_buf =====================
[19:47:58] =================== guc_dbm (7 subtests) ===================
[19:47:58] [PASSED] test_empty
[19:47:58] [PASSED] test_default
[19:47:58] ======================== test_size  ========================
[19:47:58] [PASSED] 4
[19:47:58] [PASSED] 8
[19:47:58] [PASSED] 32
[19:47:58] [PASSED] 256
[19:47:58] ==================== [PASSED] test_size ====================
[19:47:58] ======================= test_reuse  ========================
[19:47:58] [PASSED] 4
[19:47:58] [PASSED] 8
[19:47:58] [PASSED] 32
[19:47:58] [PASSED] 256
[19:47:58] =================== [PASSED] test_reuse ====================
[19:47:58] =================== test_range_overlap  ====================
[19:47:58] [PASSED] 4
[19:47:58] [PASSED] 8
[19:47:58] [PASSED] 32
[19:47:58] [PASSED] 256
[19:47:58] =============== [PASSED] test_range_overlap ================
[19:47:58] =================== test_range_compact  ====================
[19:47:58] [PASSED] 4
[19:47:58] [PASSED] 8
[19:47:58] [PASSED] 32
[19:47:58] [PASSED] 256
[19:47:58] =============== [PASSED] test_range_compact ================
[19:47:58] ==================== test_range_spare  =====================
[19:47:58] [PASSED] 4
[19:47:58] [PASSED] 8
[19:47:58] [PASSED] 32
[19:47:58] [PASSED] 256
[19:47:58] ================ [PASSED] test_range_spare =================
[19:47:58] ===================== [PASSED] guc_dbm =====================
[19:47:58] =================== guc_idm (6 subtests) ===================
[19:47:58] [PASSED] bad_init
[19:47:58] [PASSED] no_init
[19:47:58] [PASSED] init_fini
[19:47:58] [PASSED] check_used
[19:47:58] [PASSED] check_quota
[19:47:58] [PASSED] check_all
[19:47:58] ===================== [PASSED] guc_idm =====================
[19:47:58] ============== guc_klv_helpers (13 subtests) ===============
[19:47:58] [PASSED] test_count
[19:47:58] [PASSED] test_encode_u32
[19:47:58] [PASSED] test_encode_u64
[19:47:58] [PASSED] test_encode_string
[19:47:58] [PASSED] test_encode_object_raw
[19:47:58] [PASSED] test_encode_object_klv
[19:47:58] [PASSED] test_encode_object_nested
[19:47:58] [PASSED] test_encode_object_basic
[19:47:58] ===================== test_decode_u16  =====================
[19:47:58] [PASSED] empty
[19:47:58] [PASSED] valid
[19:47:58] [PASSED] max
[19:47:58] [PASSED] big
[19:47:58] [PASSED] long
[19:47:58] ================= [PASSED] test_decode_u16 =================
[19:47:58] ===================== test_decode_u32  =====================
[19:47:58] [PASSED] empty
[19:47:58] [PASSED] valid
[19:47:58] [PASSED] max
[19:47:58] [PASSED] long
[19:47:58] ================= [PASSED] test_decode_u32 =================
[19:47:58] ===================== test_decode_u64  =====================
[19:47:58] [PASSED] empty
[19:47:58] [PASSED] short
[19:47:58] [PASSED] valid
[19:47:58] [PASSED] max
[19:47:58] [PASSED] long
[19:47:58] ================= [PASSED] test_decode_u64 =================
[19:47:58] ===================== test_decode_str  =====================
[19:47:58] [PASSED] empty
[19:47:58] [PASSED] one
[19:47:58] [PASSED] one_trash
[19:47:58] [PASSED] two
[19:47:58] [PASSED] two_trash
[19:47:58] [PASSED] three
[19:47:58] [PASSED] dword
[19:47:58] [PASSED] four
[19:47:58] [PASSED] five
[19:47:58] [PASSED] six
[19:47:58] [PASSED] seven
[19:47:58] [PASSED] qword
[19:47:58] ================= [PASSED] test_decode_str =================
[19:47:58] [PASSED] test_print
[19:47:58] ================= [PASSED] guc_klv_helpers =================
[19:47:58] =================== xe_log (4 subtests) ====================
[19:47:58] [PASSED] demo_cper
[19:47:58] [PASSED] demo_dmesg
[19:47:58] ======================= test_dmesg  ========================
[19:47:58] [PASSED] test_fatal
[19:47:58] [PASSED] test_fatal_tile
[19:47:58] [PASSED] test_fatal_gt
[19:47:58] [PASSED] test_fatal_comp
[19:47:58] [PASSED] test_fatal_comp_tile
[19:47:58] [PASSED] test_fatal_comp_gt
[19:47:58] [PASSED] test_fatal_all
[19:47:58] [PASSED] test_recoverable
[19:47:58] [PASSED] test_recoverable_tile
[19:47:58] [PASSED] test_recoverable_gt
[19:47:58] [PASSED] test_recoverable_comp
[19:47:58] [PASSED] test_recoverable_comp_tile
[19:47:58] [PASSED] test_recoverable_comp_gt
[19:47:58] [PASSED] test_recoverable_all
[19:47:58] [PASSED] test_info
[19:47:58] [PASSED] test_info_tile
[19:47:58] [PASSED] test_info_gt
[19:47:58] [PASSED] test_info_err
[19:47:58] [PASSED] test_info_comp
[19:47:58] [PASSED] test_info_comp_tile
[19:47:58] [PASSED] test_info_comp_gt
[19:47:58] [PASSED] test_info_all
[19:47:58] [PASSED] test_hw_fatal
[19:47:58] [PASSED] test_hw_recoverable
[19:47:58] [PASSED] test_hw_corrected
[19:47:58] [PASSED] test_hw_informational
[19:47:58] =================== [PASSED] test_dmesg ====================
[19:47:58] ====================== test_invalid  =======================
[19:47:58] [SKIPPED] no-component no-location no-warn (requires CONFIG_DRM_XE_DEBUG)
[19:47:58] [SKIPPED] reserved location (requires CONFIG_DRM_XE_DEBUG)
[19:47:58] [SKIPPED] unknown location (requires CONFIG_DRM_XE_DEBUG)
[19:47:58] [SKIPPED] nonzero-device-id location (requires CONFIG_DRM_XE_DEBUG)
[19:47:58] [SKIPPED] invalid-tile-id location (requires CONFIG_DRM_XE_DEBUG)
[19:47:58] [SKIPPED] invalid-gt-id location (requires CONFIG_DRM_XE_DEBUG)
[19:47:58] [SKIPPED] unknown component class (requires CONFIG_DRM_XE_DEBUG)
[19:47:58] [SKIPPED] unknown system component (requires CONFIG_DRM_XE_DEBUG)
[19:47:58] [SKIPPED] unknown hardware component (requires CONFIG_DRM_XE_DEBUG)
[19:47:58] [SKIPPED] unknown component and location (requires CONFIG_DRM_XE_DEBUG)
[19:47:58] ================== [SKIPPED] test_invalid ==================
[19:47:58] ===================== [PASSED] xe_log ======================
[19:47:58] ================== no_relay (3 subtests) ===================
[19:47:58] [PASSED] xe_drops_guc2pf_if_not_ready
[19:47:58] [PASSED] xe_drops_guc2vf_if_not_ready
[19:47:58] [PASSED] xe_rejects_send_if_not_ready
[19:47:58] ==================== [PASSED] no_relay =====================
[19:47:58] ================== pf_relay (14 subtests) ==================
[19:47:58] [PASSED] pf_rejects_guc2pf_too_short
[19:47:58] [PASSED] pf_rejects_guc2pf_too_long
[19:47:58] [PASSED] pf_rejects_guc2pf_no_payload
[19:47:58] [PASSED] pf_fails_no_payload
[19:47:58] [PASSED] pf_fails_bad_origin
[19:47:58] [PASSED] pf_fails_bad_type
[19:47:58] [PASSED] pf_txn_reports_error
[19:47:58] [PASSED] pf_txn_sends_pf2guc
[19:47:58] [PASSED] pf_sends_pf2guc
[19:47:58] [SKIPPED] pf_loopback_nop (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[19:47:58] [SKIPPED] pf_loopback_echo (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[19:47:58] [SKIPPED] pf_loopback_fail (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[19:47:58] [SKIPPED] pf_loopback_busy (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[19:47:58] [SKIPPED] pf_loopback_retry (requires CONFIG_DRM_XE_DEBUG_SRIOV)
[19:47:58] ==================== [PASSED] pf_relay =====================
[19:47:58] ================== vf_relay (3 subtests) ===================
[19:47:58] [PASSED] vf_rejects_guc2vf_too_short
[19:47:58] [PASSED] vf_rejects_guc2vf_too_long
[19:47:58] [PASSED] vf_rejects_guc2vf_no_payload
[19:47:58] ==================== [PASSED] vf_relay =====================
[19:47:58] ================ pf_gt_config (9 subtests) =================
[19:47:58] [PASSED] fair_contexts_1vf
[19:47:58] [PASSED] fair_doorbells_1vf
[19:47:58] [PASSED] fair_ggtt_1vf
[19:47:58] ====================== fair_vram_1vf  ======================
[19:47:58] [PASSED] 3.50 GiB
[19:47:58] [PASSED] 11.5 GiB
[19:47:58] [PASSED] 15.5 GiB
[19:47:58] [PASSED] 31.5 GiB
[19:47:58] [PASSED] 63.5 GiB
[19:47:58] [PASSED] 1.91 GiB
[19:47:58] ================== [PASSED] fair_vram_1vf ==================
[19:47:58] ================ fair_vram_1vf_admin_only  =================
[19:47:58] [PASSED] 3.50 GiB
[19:47:58] [PASSED] 11.5 GiB
[19:47:58] [PASSED] 15.5 GiB
[19:47:58] [PASSED] 31.5 GiB
[19:47:58] [PASSED] 63.5 GiB
[19:47:58] [PASSED] 1.91 GiB
[19:47:58] ============ [PASSED] fair_vram_1vf_admin_only =============
[19:47:58] ====================== fair_contexts  ======================
[19:47:58] [PASSED] 1 VF
[19:47:58] [PASSED] 2 VFs
[19:47:58] [PASSED] 3 VFs
[19:47:58] [PASSED] 4 VFs
[19:47:58] [PASSED] 5 VFs
[19:47:58] [PASSED] 6 VFs
[19:47:58] [PASSED] 7 VFs
[19:47:58] [PASSED] 8 VFs
[19:47:58] [PASSED] 9 VFs
[19:47:58] [PASSED] 10 VFs
[19:47:58] [PASSED] 11 VFs
[19:47:58] [PASSED] 12 VFs
[19:47:58] [PASSED] 13 VFs
[19:47:58] [PASSED] 14 VFs
[19:47:58] [PASSED] 15 VFs
[19:47:58] [PASSED] 16 VFs
[19:47:58] [PASSED] 17 VFs
[19:47:58] [PASSED] 18 VFs
[19:47:58] [PASSED] 19 VFs
[19:47:58] [PASSED] 20 VFs
[19:47:58] [PASSED] 21 VFs
[19:47:58] [PASSED] 22 VFs
[19:47:58] [PASSED] 23 VFs
[19:47:58] [PASSED] 24 VFs
[19:47:58] [PASSED] 25 VFs
[19:47:58] [PASSED] 26 VFs
[19:47:58] [PASSED] 27 VFs
[19:47:58] [PASSED] 28 VFs
[19:47:58] [PASSED] 29 VFs
[19:47:58] [PASSED] 30 VFs
[19:47:58] [PASSED] 31 VFs
[19:47:58] [PASSED] 32 VFs
[19:47:58] [PASSED] 33 VFs
[19:47:58] [PASSED] 34 VFs
[19:47:58] [PASSED] 35 VFs
[19:47:58] [PASSED] 36 VFs
[19:47:58] [PASSED] 37 VFs
[19:47:58] [PASSED] 38 VFs
[19:47:58] [PASSED] 39 VFs
[19:47:58] [PASSED] 40 VFs
[19:47:58] [PASSED] 41 VFs
[19:47:58] [PASSED] 42 VFs
[19:47:58] [PASSED] 43 VFs
[19:47:58] [PASSED] 44 VFs
[19:47:58] [PASSED] 45 VFs
[19:47:58] [PASSED] 46 VFs
[19:47:58] [PASSED] 47 VFs
[19:47:58] [PASSED] 48 VFs
[19:47:58] [PASSED] 49 VFs
[19:47:58] [PASSED] 50 VFs
[19:47:58] [PASSED] 51 VFs
[19:47:58] [PASSED] 52 VFs
[19:47:58] [PASSED] 53 VFs
[19:47:58] [PASSED] 54 VFs
[19:47:58] [PASSED] 55 VFs
[19:47:58] [PASSED] 56 VFs
[19:47:58] [PASSED] 57 VFs
[19:47:58] [PASSED] 58 VFs
[19:47:58] [PASSED] 59 VFs
[19:47:58] [PASSED] 60 VFs
[19:47:58] [PASSED] 61 VFs
[19:47:58] [PASSED] 62 VFs
[19:47:58] [PASSED] 63 VFs
[19:47:58] ================== [PASSED] fair_contexts ==================
[19:47:58] ===================== fair_doorbells  ======================
[19:47:58] [PASSED] 1 VF
[19:47:58] [PASSED] 2 VFs
[19:47:58] [PASSED] 3 VFs
[19:47:58] [PASSED] 4 VFs
[19:47:58] [PASSED] 5 VFs
[19:47:58] [PASSED] 6 VFs
[19:47:58] [PASSED] 7 VFs
[19:47:58] [PASSED] 8 VFs
[19:47:58] [PASSED] 9 VFs
[19:47:58] [PASSED] 10 VFs
[19:47:58] [PASSED] 11 VFs
[19:47:58] [PASSED] 12 VFs
[19:47:58] [PASSED] 13 VFs
[19:47:58] [PASSED] 14 VFs
[19:47:58] [PASSED] 15 VFs
[19:47:58] [PASSED] 16 VFs
[19:47:58] [PASSED] 17 VFs
[19:47:58] [PASSED] 18 VFs
[19:47:58] [PASSED] 19 VFs
[19:47:58] [PASSED] 20 VFs
[19:47:58] [PASSED] 21 VFs
[19:47:58] [PASSED] 22 VFs
[19:47:58] [PASSED] 23 VFs
[19:47:58] [PASSED] 24 VFs
[19:47:58] [PASSED] 25 VFs
[19:47:58] [PASSED] 26 VFs
[19:47:58] [PASSED] 27 VFs
[19:47:58] [PASSED] 28 VFs
[19:47:58] [PASSED] 29 VFs
[19:47:58] [PASSED] 30 VFs
[19:47:58] [PASSED] 31 VFs
[19:47:58] [PASSED] 32 VFs
[19:47:58] [PASSED] 33 VFs
[19:47:58] [PASSED] 34 VFs
[19:47:58] [PASSED] 35 VFs
[19:47:58] [PASSED] 36 VFs
[19:47:58] [PASSED] 37 VFs
[19:47:58] [PASSED] 38 VFs
[19:47:58] [PASSED] 39 VFs
[19:47:58] [PASSED] 40 VFs
[19:47:58] [PASSED] 41 VFs
[19:47:58] [PASSED] 42 VFs
[19:47:58] [PASSED] 43 VFs
[19:47:58] [PASSED] 44 VFs
[19:47:58] [PASSED] 45 VFs
[19:47:58] [PASSED] 46 VFs
[19:47:58] [PASSED] 47 VFs
[19:47:58] [PASSED] 48 VFs
[19:47:58] [PASSED] 49 VFs
[19:47:58] [PASSED] 50 VFs
[19:47:58] [PASSED] 51 VFs
[19:47:58] [PASSED] 52 VFs
[19:47:58] [PASSED] 53 VFs
[19:47:58] [PASSED] 54 VFs
[19:47:58] [PASSED] 55 VFs
[19:47:58] [PASSED] 56 VFs
[19:47:58] [PASSED] 57 VFs
[19:47:58] [PASSED] 58 VFs
[19:47:58] [PASSED] 59 VFs
[19:47:58] [PASSED] 60 VFs
[19:47:58] [PASSED] 61 VFs
[19:47:58] [PASSED] 62 VFs
[19:47:58] [PASSED] 63 VFs
[19:47:58] ================= [PASSED] fair_doorbells ==================
[19:47:58] ======================== fair_ggtt  ========================
[19:47:58] [PASSED] 1 VF
[19:47:58] [PASSED] 2 VFs
[19:47:58] [PASSED] 3 VFs
[19:47:58] [PASSED] 4 VFs
[19:47:58] [PASSED] 5 VFs
[19:47:58] [PASSED] 6 VFs
[19:47:58] [PASSED] 7 VFs
[19:47:58] [PASSED] 8 VFs
[19:47:58] [PASSED] 9 VFs
[19:47:58] [PASSED] 10 VFs
[19:47:58] [PASSED] 11 VFs
[19:47:58] [PASSED] 12 VFs
[19:47:58] [PASSED] 13 VFs
[19:47:58] [PASSED] 14 VFs
[19:47:58] [PASSED] 15 VFs
[19:47:58] [PASSED] 16 VFs
[19:47:58] [PASSED] 17 VFs
[19:47:58] [PASSED] 18 VFs
[19:47:58] [PASSED] 19 VFs
[19:47:58] [PASSED] 20 VFs
[19:47:58] [PASSED] 21 VFs
[19:47:58] [PASSED] 22 VFs
[19:47:58] [PASSED] 23 VFs
[19:47:58] [PASSED] 24 VFs
[19:47:58] [PASSED] 25 VFs
[19:47:58] [PASSED] 26 VFs
[19:47:58] [PASSED] 27 VFs
[19:47:58] [PASSED] 28 VFs
[19:47:58] [PASSED] 29 VFs
[19:47:58] [PASSED] 30 VFs
[19:47:58] [PASSED] 31 VFs
[19:47:58] [PASSED] 32 VFs
[19:47:58] [PASSED] 33 VFs
[19:47:58] [PASSED] 34 VFs
[19:47:58] [PASSED] 35 VFs
[19:47:58] [PASSED] 36 VFs
[19:47:58] [PASSED] 37 VFs
[19:47:58] [PASSED] 38 VFs
[19:47:58] [PASSED] 39 VFs
[19:47:58] [PASSED] 40 VFs
[19:47:58] [PASSED] 41 VFs
[19:47:58] [PASSED] 42 VFs
[19:47:58] [PASSED] 43 VFs
[19:47:58] [PASSED] 44 VFs
[19:47:58] [PASSED] 45 VFs
[19:47:58] [PASSED] 46 VFs
[19:47:58] [PASSED] 47 VFs
[19:47:58] [PASSED] 48 VFs
[19:47:58] [PASSED] 49 VFs
[19:47:58] [PASSED] 50 VFs
[19:47:58] [PASSED] 51 VFs
[19:47:58] [PASSED] 52 VFs
[19:47:58] [PASSED] 53 VFs
[19:47:58] [PASSED] 54 VFs
[19:47:58] [PASSED] 55 VFs
[19:47:58] [PASSED] 56 VFs
[19:47:58] [PASSED] 57 VFs
[19:47:58] [PASSED] 58 VFs
[19:47:58] [PASSED] 59 VFs
[19:47:58] [PASSED] 60 VFs
[19:47:58] [PASSED] 61 VFs
[19:47:58] [PASSED] 62 VFs
[19:47:58] [PASSED] 63 VFs
[19:47:58] ==================== [PASSED] fair_ggtt ====================
[19:47:58] ======================== fair_vram  ========================
[19:47:58] [PASSED] 1 VF
[19:47:58] [PASSED] 2 VFs
[19:47:58] [PASSED] 3 VFs
[19:47:58] [PASSED] 4 VFs
[19:47:58] [PASSED] 5 VFs
[19:47:58] [PASSED] 6 VFs
[19:47:58] [PASSED] 7 VFs
[19:47:58] [PASSED] 8 VFs
[19:47:58] [PASSED] 9 VFs
[19:47:58] [PASSED] 10 VFs
[19:47:58] [PASSED] 11 VFs
[19:47:58] [PASSED] 12 VFs
[19:47:58] [PASSED] 13 VFs
[19:47:58] [PASSED] 14 VFs
[19:47:58] [PASSED] 15 VFs
[19:47:58] [PASSED] 16 VFs
[19:47:58] [PASSED] 17 VFs
[19:47:58] [PASSED] 18 VFs
[19:47:58] [PASSED] 19 VFs
[19:47:58] [PASSED] 20 VFs
[19:47:58] [PASSED] 21 VFs
[19:47:58] [PASSED] 22 VFs
[19:47:58] [PASSED] 23 VFs
[19:47:58] [PASSED] 24 VFs
[19:47:58] [PASSED] 25 VFs
[19:47:58] [PASSED] 26 VFs
[19:47:58] [PASSED] 27 VFs
[19:47:58] [PASSED] 28 VFs
[19:47:58] [PASSED] 29 VFs
[19:47:58] [PASSED] 30 VFs
[19:47:58] [PASSED] 31 VFs
[19:47:58] [PASSED] 32 VFs
[19:47:58] [PASSED] 33 VFs
[19:47:58] [PASSED] 34 VFs
[19:47:58] [PASSED] 35 VFs
[19:47:58] [PASSED] 36 VFs
[19:47:58] [PASSED] 37 VFs
[19:47:58] [PASSED] 38 VFs
[19:47:58] [PASSED] 39 VFs
[19:47:58] [PASSED] 40 VFs
[19:47:58] [PASSED] 41 VFs
[19:47:58] [PASSED] 42 VFs
[19:47:58] [PASSED] 43 VFs
[19:47:58] [PASSED] 44 VFs
[19:47:58] [PASSED] 45 VFs
[19:47:58] [PASSED] 46 VFs
[19:47:58] [PASSED] 47 VFs
[19:47:58] [PASSED] 48 VFs
[19:47:58] [PASSED] 49 VFs
[19:47:58] [PASSED] 50 VFs
[19:47:58] [PASSED] 51 VFs
[19:47:58] [PASSED] 52 VFs
[19:47:58] [PASSED] 53 VFs
[19:47:58] [PASSED] 54 VFs
[19:47:58] [PASSED] 55 VFs
[19:47:58] [PASSED] 56 VFs
[19:47:58] [PASSED] 57 VFs
[19:47:58] [PASSED] 58 VFs
[19:47:58] [PASSED] 59 VFs
[19:47:58] [PASSED] 60 VFs
[19:47:58] [PASSED] 61 VFs
[19:47:58] [PASSED] 62 VFs
[19:47:58] [PASSED] 63 VFs
[19:47:58] ==================== [PASSED] fair_vram ====================
[19:47:58] ================== [PASSED] pf_gt_config ===================
[19:47:58] ===================== lmtt (1 subtest) =====================
[19:47:58] ======================== test_ops  =========================
[19:47:58] [PASSED] 2-level
[19:47:58] [PASSED] multi-level
[19:47:58] ==================== [PASSED] test_ops =====================
[19:47:58] ====================== [PASSED] lmtt =======================
[19:47:58] ================= sriov_packet (1 subtest) =================
[19:47:58] [PASSED] test_descriptor_init
[19:47:58] ================== [PASSED] sriov_packet ===================
[19:47:58] ================= pf_service (11 subtests) =================
[19:47:58] [PASSED] pf_negotiate_any
[19:47:58] [PASSED] pf_negotiate_base_match
[19:47:58] [PASSED] pf_negotiate_base_newer
[19:47:58] [PASSED] pf_negotiate_base_next
[19:47:58] [SKIPPED] pf_negotiate_base_older (no older minor)
[19:47:58] [PASSED] pf_negotiate_base_prev
[19:47:58] [PASSED] pf_negotiate_latest_match
[19:47:58] [PASSED] pf_negotiate_latest_newer
[19:47:58] [PASSED] pf_negotiate_latest_next
[19:47:58] [SKIPPED] pf_negotiate_latest_older (no older minor)
[19:47:58] [SKIPPED] pf_negotiate_latest_prev (no prev major)
[19:47:58] =================== [PASSED] pf_service ====================
[19:47:58] ================= xe_guc_g2g (2 subtests) ==================
[19:47:58] ============== xe_live_guc_g2g_kunit_default  ==============
[19:47:58] ========= [SKIPPED] xe_live_guc_g2g_kunit_default ==========
[19:47:58] ============== xe_live_guc_g2g_kunit_allmem  ===============
[19:47:58] ========== [SKIPPED] xe_live_guc_g2g_kunit_allmem ==========
[19:47:58] =================== [SKIPPED] xe_guc_g2g ===================
[19:47:58] =================== xe_mocs (2 subtests) ===================
[19:47:58] ================ xe_live_mocs_kernel_kunit  ================
[19:47:58] =========== [SKIPPED] xe_live_mocs_kernel_kunit ============
[19:47:58] ================ xe_live_mocs_reset_kunit  =================
[19:47:58] ============ [SKIPPED] xe_live_mocs_reset_kunit ============
[19:47:58] ==================== [SKIPPED] xe_mocs =====================
[19:47:58] ================= xe_migrate (2 subtests) ==================
[19:47:58] ================= xe_migrate_sanity_kunit  =================
[19:47:58] ============ [SKIPPED] xe_migrate_sanity_kunit =============
[19:47:58] ================== xe_validate_ccs_kunit  ==================
[19:47:58] ============= [SKIPPED] xe_validate_ccs_kunit ==============
[19:47:58] =================== [SKIPPED] xe_migrate ===================
[19:47:58] ================== xe_dma_buf (1 subtest) ==================
[19:47:58] ==================== xe_dma_buf_kunit  =====================
[19:47:58] ================ [SKIPPED] xe_dma_buf_kunit ================
[19:47:58] =================== [SKIPPED] xe_dma_buf ===================
[19:47:58] ================= xe_bo_shrink (1 subtest) =================
[19:47:58] =================== xe_bo_shrink_kunit  ====================
[19:47:58] =============== [SKIPPED] xe_bo_shrink_kunit ===============
[19:47:58] ================== [SKIPPED] xe_bo_shrink ==================
[19:47:58] ==================== xe_bo (2 subtests) ====================
[19:47:58] ================== xe_ccs_migrate_kunit  ===================
[19:47:58] ============== [SKIPPED] xe_ccs_migrate_kunit ==============
[19:47:58] ==================== xe_bo_evict_kunit  ====================
[19:47:58] =============== [SKIPPED] xe_bo_evict_kunit ================
[19:47:58] ===================== [SKIPPED] xe_bo ======================
[19:47:58] =================== xe_any (9 subtests) ====================
[19:47:58] [PASSED] test_to_xe
[19:47:58] [PASSED] test_to_dev
[19:47:58] [PASSED] test_to_pdev
[19:47:58] [PASSED] test_to_drm
[19:47:58] [PASSED] test_if_pdev
[19:47:58] [PASSED] test_if_xe
[19:47:58] [PASSED] test_if_tile
[19:47:58] [PASSED] test_if_gt
[19:47:58] [PASSED] test_to_id
[19:47:58] ===================== [PASSED] xe_any ======================
[19:47:58] ==================== args (13 subtests) ====================
[19:47:58] [PASSED] count_args_test
[19:47:58] [PASSED] call_args_example
[19:47:58] [PASSED] call_args_test
[19:47:58] [PASSED] drop_first_arg_example
[19:47:58] [PASSED] drop_first_arg_test
[19:47:58] [PASSED] first_arg_example
[19:47:58] [PASSED] first_arg_test
[19:47:58] [PASSED] last_arg_example
[19:47:58] [PASSED] last_arg_test
[19:47:58] [PASSED] pick_arg_example
[19:47:58] [PASSED] if_args_example
[19:47:58] [PASSED] if_args_test
[19:47:58] [PASSED] sep_comma_example
[19:47:58] ====================== [PASSED] args =======================
[19:47:58] =================== xe_pci (3 subtests) ====================
[19:47:58] ==================== check_graphics_ip  ====================
[19:47:58] [PASSED] 12.00 Xe_LP
[19:47:58] [PASSED] 12.10 Xe_LP+
[19:47:58] [PASSED] 12.55 Xe_HPG
[19:47:58] [PASSED] 12.60 Xe_HPC
[19:47:58] [PASSED] 12.70 Xe_LPG
[19:47:58] [PASSED] 12.71 Xe_LPG
[19:47:58] [PASSED] 12.74 Xe_LPG+
[19:47:58] [PASSED] 20.01 Xe2_HPG
[19:47:58] [PASSED] 20.02 Xe2_HPG
[19:47:58] [PASSED] 20.04 Xe2_LPG
[19:47:58] [PASSED] 30.00 Xe3_LPG
[19:47:58] [PASSED] 30.01 Xe3_LPG
[19:47:58] [PASSED] 30.03 Xe3_LPG
[19:47:58] [PASSED] 30.04 Xe3_LPG
[19:47:58] [PASSED] 30.05 Xe3_LPG
[19:47:58] [PASSED] 35.10 Xe3p_LPG
[19:47:58] [PASSED] 35.11 Xe3p_XPC
[19:47:58] ================ [PASSED] check_graphics_ip ================
[19:47:58] ===================== check_media_ip  ======================
[19:47:58] [PASSED] 12.00 Xe_M
[19:47:58] [PASSED] 12.55 Xe_HPM
[19:47:58] [PASSED] 13.00 Xe_LPM+
[19:47:58] [PASSED] 13.01 Xe2_HPM
[19:47:58] [PASSED] 20.00 Xe2_LPM
[19:47:58] [PASSED] 30.00 Xe3_LPM
[19:47:58] [PASSED] 30.02 Xe3_LPM
[19:47:58] [PASSED] 35.00 Xe3p_LPM
[19:47:58] [PASSED] 35.03 Xe3p_HPM
[19:47:58] ================= [PASSED] check_media_ip ==================
[19:47:58] =================== check_platform_desc  ===================
[19:47:58] [PASSED] 0x9A60 (TIGERLAKE)
[19:47:58] [PASSED] 0x9A68 (TIGERLAKE)
[19:47:58] [PASSED] 0x9A70 (TIGERLAKE)
[19:47:58] [PASSED] 0x9A40 (TIGERLAKE)
[19:47:58] [PASSED] 0x9A49 (TIGERLAKE)
[19:47:58] [PASSED] 0x9A59 (TIGERLAKE)
[19:47:58] [PASSED] 0x9A78 (TIGERLAKE)
[19:47:58] [PASSED] 0x9AC0 (TIGERLAKE)
[19:47:58] [PASSED] 0x9AC9 (TIGERLAKE)
[19:47:58] [PASSED] 0x9AD9 (TIGERLAKE)
[19:47:58] [PASSED] 0x9AF8 (TIGERLAKE)
[19:47:58] [PASSED] 0x4C80 (ROCKETLAKE)
[19:47:58] [PASSED] 0x4C8A (ROCKETLAKE)
[19:47:58] [PASSED] 0x4C8B (ROCKETLAKE)
[19:47:58] [PASSED] 0x4C8C (ROCKETLAKE)
[19:47:58] [PASSED] 0x4C90 (ROCKETLAKE)
[19:47:58] [PASSED] 0x4C9A (ROCKETLAKE)
[19:47:58] [PASSED] 0x4680 (ALDERLAKE_S)
[19:47:58] [PASSED] 0x4682 (ALDERLAKE_S)
[19:47:58] [PASSED] 0x4688 (ALDERLAKE_S)
[19:47:58] [PASSED] 0x468A (ALDERLAKE_S)
[19:47:58] [PASSED] 0x468B (ALDERLAKE_S)
[19:47:58] [PASSED] 0x4690 (ALDERLAKE_S)
[19:47:58] [PASSED] 0x4692 (ALDERLAKE_S)
[19:47:58] [PASSED] 0x4693 (ALDERLAKE_S)
[19:47:58] [PASSED] 0x46A0 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46A1 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46A2 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46A3 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46A6 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46A8 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46AA (ALDERLAKE_P)
[19:47:58] [PASSED] 0x462A (ALDERLAKE_P)
[19:47:58] [PASSED] 0x4626 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x4628 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46B0 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46B1 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46B2 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46B3 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46C0 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46C1 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46C2 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46C3 (ALDERLAKE_P)
[19:47:58] [PASSED] 0x46D0 (ALDERLAKE_N)
[19:47:58] [PASSED] 0x46D1 (ALDERLAKE_N)
[19:47:58] [PASSED] 0x46D2 (ALDERLAKE_N)
[19:47:58] [PASSED] 0x46D3 (ALDERLAKE_N)
[19:47:58] [PASSED] 0x46D4 (ALDERLAKE_N)
[19:47:58] [PASSED] 0xA721 (ALDERLAKE_P)
[19:47:58] [PASSED] 0xA7A1 (ALDERLAKE_P)
[19:47:58] [PASSED] 0xA7A9 (ALDERLAKE_P)
[19:47:58] [PASSED] 0xA7AC (ALDERLAKE_P)
[19:47:58] [PASSED] 0xA7AD (ALDERLAKE_P)
[19:47:58] [PASSED] 0xA720 (ALDERLAKE_P)
[19:47:58] [PASSED] 0xA7A0 (ALDERLAKE_P)
[19:47:58] [PASSED] 0xA7A8 (ALDERLAKE_P)
[19:47:58] [PASSED] 0xA7AA (ALDERLAKE_P)
[19:47:58] [PASSED] 0xA7AB (ALDERLAKE_P)
[19:47:58] [PASSED] 0xA780 (ALDERLAKE_S)
[19:47:58] [PASSED] 0xA781 (ALDERLAKE_S)
[19:47:58] [PASSED] 0xA782 (ALDERLAKE_S)
[19:47:58] [PASSED] 0xA783 (ALDERLAKE_S)
[19:47:58] [PASSED] 0xA788 (ALDERLAKE_S)
[19:47:58] [PASSED] 0xA789 (ALDERLAKE_S)
[19:47:58] [PASSED] 0xA78A (ALDERLAKE_S)
[19:47:58] [PASSED] 0xA78B (ALDERLAKE_S)
[19:47:58] [PASSED] 0x4905 (DG1)
[19:47:58] [PASSED] 0x4906 (DG1)
[19:47:58] [PASSED] 0x4907 (DG1)
[19:47:58] [PASSED] 0x4908 (DG1)
[19:47:58] [PASSED] 0x4909 (DG1)
[19:47:58] [PASSED] 0x56C0 (DG2)
[19:47:58] [PASSED] 0x56C2 (DG2)
[19:47:58] [PASSED] 0x56C1 (DG2)
[19:47:58] [PASSED] 0x7D51 (METEORLAKE)
[19:47:58] [PASSED] 0x7DD1 (METEORLAKE)
[19:47:58] [PASSED] 0x7D41 (METEORLAKE)
[19:47:58] [PASSED] 0x7D67 (METEORLAKE)
[19:47:58] [PASSED] 0xB640 (METEORLAKE)
[19:47:58] [PASSED] 0x56A0 (DG2)
[19:47:58] [PASSED] 0x56A1 (DG2)
[19:47:58] [PASSED] 0x56A2 (DG2)
[19:47:58] [PASSED] 0x56BE (DG2)
[19:47:58] [PASSED] 0x56BF (DG2)
[19:47:58] [PASSED] 0x5690 (DG2)
[19:47:58] [PASSED] 0x5691 (DG2)
[19:47:58] [PASSED] 0x5692 (DG2)
[19:47:58] [PASSED] 0x56A5 (DG2)
[19:47:58] [PASSED] 0x56A6 (DG2)
[19:47:58] [PASSED] 0x56B0 (DG2)
[19:47:58] [PASSED] 0x56B1 (DG2)
[19:47:58] [PASSED] 0x56BA (DG2)
[19:47:58] [PASSED] 0x56BB (DG2)
[19:47:58] [PASSED] 0x56BC (DG2)
[19:47:58] [PASSED] 0x56BD (DG2)
[19:47:58] [PASSED] 0x5693 (DG2)
[19:47:58] [PASSED] 0x5694 (DG2)
[19:47:58] [PASSED] 0x5695 (DG2)
[19:47:58] [PASSED] 0x56A3 (DG2)
[19:47:58] [PASSED] 0x56A4 (DG2)
[19:47:58] [PASSED] 0x56B2 (DG2)
[19:47:58] [PASSED] 0x56B3 (DG2)
[19:47:58] [PASSED] 0x5696 (DG2)
[19:47:58] [PASSED] 0x5697 (DG2)
[19:47:58] [PASSED] 0xB69 (PVC)
[19:47:58] [PASSED] 0xB6E (PVC)
[19:47:58] [PASSED] 0xBD4 (PVC)
[19:47:58] [PASSED] 0xBD5 (PVC)
[19:47:58] [PASSED] 0xBD6 (PVC)
[19:47:58] [PASSED] 0xBD7 (PVC)
[19:47:58] [PASSED] 0xBD8 (PVC)
[19:47:58] [PASSED] 0xBD9 (PVC)
[19:47:58] [PASSED] 0xBDA (PVC)
[19:47:58] [PASSED] 0xBDB (PVC)
[19:47:58] [PASSED] 0xBE0 (PVC)
[19:47:58] [PASSED] 0xBE1 (PVC)
[19:47:58] [PASSED] 0xBE5 (PVC)
[19:47:58] [PASSED] 0x7D40 (METEORLAKE)
[19:47:58] [PASSED] 0x7D45 (METEORLAKE)
[19:47:58] [PASSED] 0x7D55 (METEORLAKE)
[19:47:58] [PASSED] 0x7D60 (METEORLAKE)
[19:47:58] [PASSED] 0x7DD5 (METEORLAKE)
[19:47:58] [PASSED] 0x6420 (LUNARLAKE)
[19:47:58] [PASSED] 0x64A0 (LUNARLAKE)
[19:47:58] [PASSED] 0x64B0 (LUNARLAKE)
[19:47:58] [PASSED] 0xE202 (BATTLEMAGE)
[19:47:58] [PASSED] 0xE209 (BATTLEMAGE)
[19:47:58] [PASSED] 0xE20B (BATTLEMAGE)
[19:47:58] [PASSED] 0xE20C (BATTLEMAGE)
[19:47:58] [PASSED] 0xE20D (BATTLEMAGE)
[19:47:58] [PASSED] 0xE210 (BATTLEMAGE)
[19:47:58] [PASSED] 0xE211 (BATTLEMAGE)
[19:47:58] [PASSED] 0xE212 (BATTLEMAGE)
[19:47:58] [PASSED] 0xE216 (BATTLEMAGE)
[19:47:58] [PASSED] 0xE220 (BATTLEMAGE)
[19:47:58] [PASSED] 0xE221 (BATTLEMAGE)
[19:47:58] [PASSED] 0xE222 (BATTLEMAGE)
[19:47:58] [PASSED] 0xE223 (BATTLEMAGE)
[19:47:58] [PASSED] 0xB080 (PANTHERLAKE)
[19:47:58] [PASSED] 0xB081 (PANTHERLAKE)
[19:47:58] [PASSED] 0xB082 (PANTHERLAKE)
[19:47:58] [PASSED] 0xB083 (PANTHERLAKE)
[19:47:58] [PASSED] 0xB084 (PANTHERLAKE)
[19:47:58] [PASSED] 0xB085 (PANTHERLAKE)
[19:47:58] [PASSED] 0xB086 (PANTHERLAKE)
[19:47:58] [PASSED] 0xB087 (PANTHERLAKE)
[19:47:58] [PASSED] 0xB08F (PANTHERLAKE)
[19:47:58] [PASSED] 0xB090 (PANTHERLAKE)
[19:47:58] [PASSED] 0xB0A0 (PANTHERLAKE)
[19:47:58] [PASSED] 0xB0A1 (PANTHERLAKE)
[19:47:58] [PASSED] 0xB0B0 (PANTHERLAKE)
[19:47:58] [PASSED] 0xFD80 (PANTHERLAKE)
[19:47:58] [PASSED] 0xFD81 (PANTHERLAKE)
[19:47:58] [PASSED] 0xD740 (NOVALAKE_S)
[19:47:58] [PASSED] 0xD741 (NOVALAKE_S)
[19:47:58] [PASSED] 0xD742 (NOVALAKE_S)
[19:47:58] [PASSED] 0xD743 (NOVALAKE_S)
[19:47:58] [PASSED] 0xD745 (NOVALAKE_S)
[19:47:58] [PASSED] 0xD74A (NOVALAKE_S)
[19:47:58] [PASSED] 0xD74B (NOVALAKE_S)
[19:47:58] [PASSED] 0x674C (CRESCENTISLAND)
[19:47:58] [PASSED] 0x674D (CRESCENTISLAND)
[19:47:58] [PASSED] 0x674E (CRESCENTISLAND)
[19:47:58] [PASSED] 0x674F (CRESCENTISLAND)
[19:47:58] [PASSED] 0x6750 (CRESCENTISLAND)
[19:47:58] [PASSED] 0x6751 (CRESCENTISLAND)
[19:47:58] [PASSED] 0xD750 (NOVALAKE_P)
[19:47:58] [PASSED] 0xD751 (NOVALAKE_P)
[19:47:58] [PASSED] 0xD752 (NOVALAKE_P)
[19:47:58] [PASSED] 0xD753 (NOVALAKE_P)
[19:47:58] [PASSED] 0xD754 (NOVALAKE_P)
[19:47:58] [PASSED] 0xD755 (NOVALAKE_P)
[19:47:58] [PASSED] 0xD756 (NOVALAKE_P)
[19:47:58] [PASSED] 0xD757 (NOVALAKE_P)
[19:47:58] [PASSED] 0xD75F (NOVALAKE_P)
[19:47:58] =============== [PASSED] check_platform_desc ===============
[19:47:58] ===================== [PASSED] xe_pci ======================
[19:47:58] ============= xe_rtp_tables_test (5 subtests) ==============
[19:47:58] ================== xe_rtp_table_gt_test  ===================
[19:47:58] [PASSED] gt_was/14011060649
[19:47:58] [PASSED] gt_was/14011059788
[19:47:58] [PASSED] gt_was/14015795083
[19:47:58] [PASSED] gt_was/16021867713
[19:47:58] [PASSED] gt_was/14019449301
[19:47:58] [PASSED] gt_was/16028005424
[19:47:58] [PASSED] gt_was/14026578760
[19:47:58] [PASSED] gt_was/1409420604
[19:47:58] [PASSED] gt_was/1408615072
[19:47:58] [PASSED] gt_was/22010523718
[19:47:58] [PASSED] gt_was/14011006942
[19:47:58] [PASSED] gt_was/14014830051
[19:47:58] [PASSED] gt_was/18018781329
[19:47:58] [PASSED] gt_was/1509235366
[19:47:58] [PASSED] gt_was/18018781329
[19:47:58] [PASSED] gt_was/16016694945
[19:47:58] [PASSED] gt_was/14018575942
[19:47:58] [PASSED] gt_was/22016670082
[19:47:58] [PASSED] gt_was/22016670082
[19:47:58] [PASSED] gt_was/14017421178
[19:47:58] [PASSED] gt_was/16025250150
[19:47:58] [PASSED] gt_was/14021871409
[19:47:58] [PASSED] gt_was/16021865536
[19:47:58] [PASSED] gt_was/14021486841
[19:47:58] [PASSED] gt_was/14025160223
[19:47:58] [PASSED] gt_was/14026144927, 16029437861, 14026127056
[19:47:58] [PASSED] gt_was/14025635424
[19:47:58] [PASSED] gt_was/16028005424
[19:47:58] ============== [PASSED] xe_rtp_table_gt_test ===============
[19:47:58] ================== xe_rtp_table_gt_test  ===================
[19:47:58] [PASSED] gt_tunings/Tuning: Blend Fill Caching Optimization Disable
[19:47:58] [PASSED] gt_tunings/Tuning: 32B Access Enable
[19:47:58] [PASSED] gt_tunings/Tuning: L3 cache
[19:47:58] [PASSED] gt_tunings/Tuning: L3 cache - media
[19:47:58] [PASSED] gt_tunings/Tuning: Compression Overfetch
[19:47:58] [PASSED] gt_tunings/Tuning: Compression Overfetch - media
[19:47:58] [PASSED] gt_tunings/Tuning: Enable compressible partial write overfetch in L3
[19:47:58] [PASSED] gt_tunings/Tuning: Enable compressible partial write overfetch in L3 - media
[19:47:58] [PASSED] gt_tunings/Tuning: L2 Overfetch Compressible Only
[19:47:58] [PASSED] gt_tunings/Tuning: L2 Overfetch Compressible Only - media
[19:47:58] [PASSED] gt_tunings/Tuning: Stateless compression control
[19:47:58] [PASSED] gt_tunings/Tuning: Stateless compression control - media
[19:47:58] [PASSED] gt_tunings/Tuning: L3 RW flush all Cache
[19:47:58] [PASSED] gt_tunings/Tuning: L3 RW flush all cache - media
[19:47:58] [PASSED] gt_tunings/Tuning: Set STLB Bank Hash Mode to 4KB
[19:47:58] [PASSED] gt_tunings/Tuning: Force All Non-Compressible Memory Reads to be 256B Overfetches
[19:47:58] ============== [PASSED] xe_rtp_table_gt_test ===============
[19:47:58] ================== xe_rtp_table_oob_test  ==================
[19:47:58] [PASSED] oob_was/1607983814
[19:47:58] [PASSED] oob_was/16010904313
[19:47:58] [PASSED] oob_was/18022495364
[19:47:58] [PASSED] oob_was/22012773006
[19:47:58] [PASSED] oob_was/14014475959
[19:47:58] [PASSED] oob_was/22011391025
[19:47:58] [PASSED] oob_was/22012727170
[19:47:58] [PASSED] oob_was/22012727685
[19:47:58] [PASSED] oob_was/22016596838
[19:47:58] [PASSED] oob_was/18020744125
[19:47:58] [PASSED] oob_was/1409600907
[19:47:58] [PASSED] oob_was/22014953428
[19:47:58] [PASSED] oob_was/16017236439
[19:47:58] [PASSED] oob_was/14019821291
[19:47:58] [PASSED] oob_was/14015076503
[19:47:58] [PASSED] oob_was/22016122933
[19:47:58] [PASSED] oob_was/14018913170
[19:47:58] [PASSED] oob_was/14018094691
[19:47:58] [PASSED] oob_was/18024947630
[19:47:58] [PASSED] oob_was/16022287689
[19:47:58] [PASSED] oob_was/13011645652
[19:47:58] [PASSED] oob_was/14022293748
[19:47:58] [PASSED] oob_was/22019794406
[19:47:58] [PASSED] oob_was/22019338487
[19:47:58] [PASSED] oob_was/16023588340
[19:47:58] [PASSED] oob_was/14019789679
[19:47:58] [PASSED] oob_was/14022866841
[19:47:58] [PASSED] oob_was/16021333562
[19:47:58] [PASSED] oob_was/14016712196
[19:47:58] [PASSED] oob_was/14015568240
[19:47:58] [PASSED] oob_was/18013179988
[19:47:58] [PASSED] oob_was/1508761755
[19:47:58] [PASSED] oob_was/16023105232
[19:47:58] [PASSED] oob_was/16026508708
[19:47:58] [PASSED] oob_was/14020001231
[19:47:58] [PASSED] oob_was/16023683509
[19:47:58] [PASSED] oob_was/14025515070
[19:47:58] [PASSED] oob_was/15015404425_disable
[19:47:58] [PASSED] oob_was/16026007364
[19:47:58] [PASSED] oob_was/14020316580
[19:47:58] [PASSED] oob_was/14025883347
[19:47:58] [PASSED] oob_was/16029380221
[19:47:58] [PASSED] oob_was/22022079272
[19:47:58] [PASSED] oob_was/16029897822
[19:47:58] [PASSED] oob_was/14027054324
[19:47:58] [PASSED] oob_was/14025941587
[19:47:58] [PASSED] oob_was/16030224309
[19:47:58] ============== [PASSED] xe_rtp_table_oob_test ==============
[19:47:58] ================ xe_rtp_table_dev_oob_test  ================
[19:47:58] [PASSED] device_oob_was/22010954014
[19:47:58] [PASSED] device_oob_was/15015404425
[19:47:58] [PASSED] device_oob_was/22019338487_display
[19:47:58] [PASSED] device_oob_was/14022085890
[19:47:58] [PASSED] device_oob_was/14026539277
[19:47:58] [PASSED] device_oob_was/14026633728
[19:47:58] [PASSED] device_oob_was/14026746987
[19:47:58] [PASSED] device_oob_was/14026779378
[19:47:58] ============ [PASSED] xe_rtp_table_dev_oob_test ============
[19:47:58] ========== xe_rtp_table_missing_upper_bound_test  ==========
[19:47:58] [PASSED] register_whitelist/WaAllowPMDepthAndInvocationCountAccessFromUMD, 1408556865
[19:47:58] [PASSED] register_whitelist/1508744258, 14012131227, 1808121037
[19:47:58] [PASSED] register_whitelist/1806527549
[19:47:58] [PASSED] register_whitelist/allow_read_ctx_timestamp
[19:47:58] [PASSED] register_whitelist/allow_read_queue_timestamp
[19:47:58] [PASSED] register_whitelist/16014440446
[19:47:58] [PASSED] register_whitelist/16017236439
[19:47:58] [PASSED] register_whitelist/16020183090
[19:47:58] [PASSED] register_whitelist/14024997852
[19:47:58] [PASSED] register_whitelist/14024997852
[19:47:58] ====== [PASSED] xe_rtp_table_missing_upper_bound_test ======
[19:47:58] =============== [PASSED] xe_rtp_tables_test ================
[19:47:58] =================== xe_rtp (3 subtests) ====================
[19:47:58] =================== xe_rtp_rules_tests  ====================
[19:47:58] [PASSED] no
[19:47:58] [PASSED] yes
[19:47:58] [PASSED] no-and-no
[19:47:58] [PASSED] no-and-yes
[19:47:58] [PASSED] yes-and-no
[19:47:58] [PASSED] yes-and-yes
[19:47:58] [PASSED] no-or-no
[19:47:58] [PASSED] no-or-yes
[19:47:58] [PASSED] yes-or-no
[19:47:58] [PASSED] yes-or-yes
[19:47:58] [PASSED] no-yes-or-yes-no
[19:47:58] [PASSED] no-yes-or-yes-yes
[19:47:58] [PASSED] yes-yes-or-no-yes
[19:47:58] [PASSED] yes-yes-or-yes-yes
[19:47:58] [PASSED] no-no-or-yes-or-no
[19:47:58] [PASSED] or
[19:47:58] [PASSED] or-yes
[19:47:58] [PASSED] or-no
[19:47:58] [PASSED] yes-or
[19:47:58] [PASSED] no-or
[19:47:58] [PASSED] no-or-or-yes
[19:47:58] [PASSED] yes-or-or-no
[19:47:58] [PASSED] no-or-or-no
[19:47:58] [PASSED] missing-context-engine-class
[19:47:58] [PASSED] missing-context-engine-class-or-yes
[19:47:58] [PASSED] missing-context-engine-class-or-or-yes
[19:47:58] =============== [PASSED] xe_rtp_rules_tests ================
[19:47:58] =============== xe_rtp_process_to_sr_tests  ================
[19:47:58] [PASSED] coalesce-same-reg
[19:47:58] [PASSED] coalesce-same-reg-literal-and-func
[19:47:58] [PASSED] no-match-no-add
[19:47:58] [PASSED] two-regs-two-entries
[19:47:58] [PASSED] clr-one-set-other
[19:47:58] [PASSED] set-field
[19:47:58] [PASSED] conflict-duplicate
[19:47:58] [PASSED] conflict-not-disjoint
[19:47:58] [PASSED] conflict-not-disjoint-literal-and-func
[19:47:58] [PASSED] conflict-reg-type
[19:47:58] [PASSED] bad-mcr-reg-forced-to-regular
[19:47:58] [PASSED] bad-regular-reg-forced-to-mcr
[19:47:58] =========== [PASSED] xe_rtp_process_to_sr_tests ============
[19:47:58] ================== xe_rtp_process_tests  ===================
[19:47:58] [PASSED] active1
[19:47:58] [PASSED] active2
[19:47:58] [PASSED] active-inactive
[19:47:58] [PASSED] inactive-active
[19:47:58] [PASSED] inactive-active-inactive
[19:47:58] [PASSED] inactive-inactive-inactive
[19:47:58] ============== [PASSED] xe_rtp_process_tests ===============
[19:47:58] ===================== [PASSED] xe_rtp ======================
[19:47:58] ==================== xe_wa (1 subtest) =====================
[19:47:58] ======================== xe_wa_gt  =========================
[19:47:58] [PASSED] TIGERLAKE B0
[19:47:58] [PASSED] DG1 A0
[19:47:58] [PASSED] DG1 B0
[19:47:58] [PASSED] ALDERLAKE_S A0
[19:47:58] [PASSED] ALDERLAKE_S B0
[19:47:58] [PASSED] ALDERLAKE_S C0
[19:47:58] [PASSED] ALDERLAKE_S D0
[19:47:58] [PASSED] ALDERLAKE_P A0
[19:47:58] [PASSED] ALDERLAKE_P B0
[19:47:58] [PASSED] ALDERLAKE_P C0
[19:47:58] [PASSED] ALDERLAKE_S RPLS D0
[19:47:58] [PASSED] ALDERLAKE_P RPLU E0
[19:47:58] [PASSED] DG2 G10 C0
[19:47:58] [PASSED] DG2 G11 B1
[19:47:58] [PASSED] DG2 G12 A1
[19:47:58] [PASSED] METEORLAKE 12.70(Xe_LPG) A0 13.00(Xe_LPM+) A0
[19:47:58] [PASSED] METEORLAKE 12.71(Xe_LPG) A0 13.00(Xe_LPM+) A0
[19:47:58] [PASSED] METEORLAKE 12.74(Xe_LPG+) A0 13.00(Xe_LPM+) A0
[19:47:58] [PASSED] LUNARLAKE 20.04(Xe2_LPG) A0 20.00(Xe2_LPM) A0
[19:47:58] [PASSED] LUNARLAKE 20.04(Xe2_LPG) B0 20.00(Xe2_LPM) A0
[19:47:58] [PASSED] BATTLEMAGE 20.01(Xe2_HPG) A0 13.01(Xe2_HPM) A1
[19:47:58] [PASSED] PANTHERLAKE 30.00(Xe3_LPG) A0 30.00(Xe3_LPM) A0
[19:47:58] ==================== [PASSED] xe_wa_gt =====================
[19:47:58] ====================== [PASSED] xe_wa ======================
[19:47:58] ============================================================
[19:47:58] Testing complete. Ran 821 tests: passed: 793, skipped: 28
[19:47:58] Elapsed time: 41.565s total, 1.803s configuring, 39.046s building, 0.695s running

+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/gpu/drm/tests/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/tests/.kunitconfig
[19:47:58] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[19:48:00] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[19:48:25] Starting KUnit Kernel (1/1)...
[19:48:25] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[19:48:25] ============ drm_test_pick_cmdline (2 subtests) ============
[19:48:25] [PASSED] drm_test_pick_cmdline_res_1920_1080_60
[19:48:25] =============== drm_test_pick_cmdline_named  ===============
[19:48:25] [PASSED] NTSC
[19:48:25] [PASSED] NTSC-J
[19:48:25] [PASSED] PAL
[19:48:25] [PASSED] PAL-M
[19:48:25] =========== [PASSED] drm_test_pick_cmdline_named ===========
[19:48:25] ============== [PASSED] drm_test_pick_cmdline ==============
[19:48:25] == drm_test_atomic_get_connector_for_encoder (1 subtest) ===
[19:48:25] [PASSED] drm_test_drm_atomic_get_connector_for_encoder
[19:48:25] ==== [PASSED] drm_test_atomic_get_connector_for_encoder ====
[19:48:25] =========== drm_validate_clone_mode (2 subtests) ===========
[19:48:25] ============== drm_test_check_in_clone_mode  ===============
[19:48:25] [PASSED] in_clone_mode
[19:48:25] [PASSED] not_in_clone_mode
[19:48:25] ========== [PASSED] drm_test_check_in_clone_mode ===========
[19:48:25] =============== drm_test_check_valid_clones  ===============
[19:48:25] [PASSED] not_in_clone_mode
[19:48:25] [PASSED] valid_clone
[19:48:25] [PASSED] invalid_clone
[19:48:25] =========== [PASSED] drm_test_check_valid_clones ===========
[19:48:25] ============= [PASSED] drm_validate_clone_mode =============
[19:48:25] ============= drm_validate_modeset (1 subtest) =============
[19:48:25] [PASSED] drm_test_check_connector_changed_modeset
[19:48:25] ============== [PASSED] drm_validate_modeset ===============
[19:48:25] ====== drm_test_bridge_get_current_state (1 subtest) =======
[19:48:25] [PASSED] drm_test_drm_bridge_get_current_state_atomic
[19:48:25] ======== [PASSED] drm_test_bridge_get_current_state ========
[19:48:25] ====== drm_test_bridge_helper_reset_crtc (3 subtests) ======
[19:48:25] [PASSED] drm_test_drm_bridge_helper_reset_crtc_atomic
[19:48:25] [PASSED] drm_test_drm_bridge_helper_reset_crtc_atomic_disabled
[19:48:25] [PASSED] drm_test_drm_bridge_helper_hdmi_output_bus_fmts
[19:48:25] ======== [PASSED] drm_test_bridge_helper_reset_crtc ========
[19:48:25] ============== drm_bridge_alloc (2 subtests) ===============
[19:48:25] [PASSED] drm_test_drm_bridge_alloc_basic
[19:48:25] [PASSED] drm_test_drm_bridge_alloc_get_put
[19:48:25] ================ [PASSED] drm_bridge_alloc =================
[19:48:25] ============= drm_bridge_bus_fmt (5 subtests) ==============
[19:48:25] [PASSED] drm_test_bridge_rgb_yuv_rgb
[19:48:25] [PASSED] drm_test_bridge_must_convert_to_yuv444
[19:48:25] [PASSED] drm_test_bridge_hdmi_auto_rgb
[19:48:25] [PASSED] drm_test_bridge_auto_first
[19:48:25] [PASSED] drm_test_bridge_rgb_yuv_no_path
[19:48:25] =============== [PASSED] drm_bridge_bus_fmt ================
[19:48:25] ============= drm_cmdline_parser (40 subtests) =============
[19:48:25] [PASSED] drm_test_cmdline_force_d_only
[19:48:25] [PASSED] drm_test_cmdline_force_D_only_dvi
[19:48:25] [PASSED] drm_test_cmdline_force_D_only_hdmi
[19:48:25] [PASSED] drm_test_cmdline_force_D_only_not_digital
[19:48:25] [PASSED] drm_test_cmdline_force_e_only
[19:48:25] [PASSED] drm_test_cmdline_res
[19:48:25] [PASSED] drm_test_cmdline_res_vesa
[19:48:25] [PASSED] drm_test_cmdline_res_vesa_rblank
[19:48:25] [PASSED] drm_test_cmdline_res_rblank
[19:48:25] [PASSED] drm_test_cmdline_res_bpp
[19:48:25] [PASSED] drm_test_cmdline_res_refresh
[19:48:25] [PASSED] drm_test_cmdline_res_bpp_refresh
[19:48:25] [PASSED] drm_test_cmdline_res_bpp_refresh_interlaced
[19:48:25] [PASSED] drm_test_cmdline_res_bpp_refresh_margins
[19:48:25] [PASSED] drm_test_cmdline_res_bpp_refresh_force_off
[19:48:25] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on
[19:48:25] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on_analog
[19:48:25] [PASSED] drm_test_cmdline_res_bpp_refresh_force_on_digital
[19:48:25] [PASSED] drm_test_cmdline_res_bpp_refresh_interlaced_margins_force_on
[19:48:25] [PASSED] drm_test_cmdline_res_margins_force_on
[19:48:25] [PASSED] drm_test_cmdline_res_vesa_margins
[19:48:25] [PASSED] drm_test_cmdline_name
[19:48:25] [PASSED] drm_test_cmdline_name_bpp
[19:48:25] [PASSED] drm_test_cmdline_name_option
[19:48:25] [PASSED] drm_test_cmdline_name_bpp_option
[19:48:25] [PASSED] drm_test_cmdline_rotate_0
[19:48:25] [PASSED] drm_test_cmdline_rotate_90
[19:48:25] [PASSED] drm_test_cmdline_rotate_180
[19:48:25] [PASSED] drm_test_cmdline_rotate_270
[19:48:25] [PASSED] drm_test_cmdline_hmirror
[19:48:25] [PASSED] drm_test_cmdline_vmirror
[19:48:25] [PASSED] drm_test_cmdline_margin_options
[19:48:25] [PASSED] drm_test_cmdline_multiple_options
[19:48:25] [PASSED] drm_test_cmdline_bpp_extra_and_option
[19:48:25] [PASSED] drm_test_cmdline_extra_and_option
[19:48:25] [PASSED] drm_test_cmdline_freestanding_options
[19:48:25] [PASSED] drm_test_cmdline_freestanding_force_e_and_options
[19:48:25] [PASSED] drm_test_cmdline_panel_orientation
[19:48:25] ================ drm_test_cmdline_invalid  =================
[19:48:25] [PASSED] margin_only
[19:48:25] [PASSED] interlace_only
[19:48:25] [PASSED] res_missing_x
[19:48:25] [PASSED] res_missing_y
[19:48:25] [PASSED] res_bad_y
[19:48:25] [PASSED] res_missing_y_bpp
[19:48:25] [PASSED] res_bad_bpp
[19:48:25] [PASSED] res_bad_refresh
[19:48:25] [PASSED] res_bpp_refresh_force_on_off
[19:48:25] [PASSED] res_invalid_mode
[19:48:25] [PASSED] res_bpp_wrong_place_mode
[19:48:25] [PASSED] name_bpp_refresh
[19:48:25] [PASSED] name_refresh
[19:48:25] [PASSED] name_refresh_wrong_mode
[19:48:25] [PASSED] name_refresh_invalid_mode
[19:48:25] [PASSED] rotate_multiple
[19:48:25] [PASSED] rotate_invalid_val
[19:48:25] [PASSED] rotate_truncated
[19:48:25] [PASSED] invalid_option
[19:48:25] [PASSED] invalid_tv_option
[19:48:25] [PASSED] truncated_tv_option
[19:48:25] ============ [PASSED] drm_test_cmdline_invalid =============
[19:48:25] =============== drm_test_cmdline_tv_options  ===============
[19:48:25] [PASSED] NTSC
[19:48:25] [PASSED] NTSC_443
[19:48:25] [PASSED] NTSC_J
[19:48:25] [PASSED] PAL
[19:48:25] [PASSED] PAL_M
[19:48:25] [PASSED] PAL_N
[19:48:25] [PASSED] SECAM
[19:48:25] [PASSED] MONO_525
[19:48:25] [PASSED] MONO_625
[19:48:25] =========== [PASSED] drm_test_cmdline_tv_options ===========
[19:48:25] =============== [PASSED] drm_cmdline_parser ================
[19:48:25] ========== drmm_connector_hdmi_init (20 subtests) ==========
[19:48:25] [PASSED] drm_test_connector_hdmi_init_valid
[19:48:25] [PASSED] drm_test_connector_hdmi_init_bpc_8
[19:48:25] [PASSED] drm_test_connector_hdmi_init_bpc_10
[19:48:25] [PASSED] drm_test_connector_hdmi_init_bpc_12
[19:48:25] [PASSED] drm_test_connector_hdmi_init_bpc_invalid
[19:48:25] [PASSED] drm_test_connector_hdmi_init_bpc_null
[19:48:25] [PASSED] drm_test_connector_hdmi_init_formats_empty
[19:48:25] [PASSED] drm_test_connector_hdmi_init_formats_no_rgb
[19:48:25] === drm_test_connector_hdmi_init_formats_yuv420_allowed  ===
[19:48:25] [PASSED] supported_formats=0x9 yuv420_allowed=1
[19:48:25] [PASSED] supported_formats=0x9 yuv420_allowed=0
[19:48:25] [PASSED] supported_formats=0x5 yuv420_allowed=1
[19:48:25] [PASSED] supported_formats=0x5 yuv420_allowed=0
[19:48:25] === [PASSED] drm_test_connector_hdmi_init_formats_yuv420_allowed ===
[19:48:25] [PASSED] drm_test_connector_hdmi_init_null_ddc
[19:48:25] [PASSED] drm_test_connector_hdmi_init_null_product
[19:48:25] [PASSED] drm_test_connector_hdmi_init_null_vendor
[19:48:25] [PASSED] drm_test_connector_hdmi_init_product_length_exact
[19:48:25] [PASSED] drm_test_connector_hdmi_init_product_length_too_long
[19:48:25] [PASSED] drm_test_connector_hdmi_init_product_valid
[19:48:25] [PASSED] drm_test_connector_hdmi_init_vendor_length_exact
[19:48:25] [PASSED] drm_test_connector_hdmi_init_vendor_length_too_long
[19:48:25] [PASSED] drm_test_connector_hdmi_init_vendor_valid
[19:48:25] ========= drm_test_connector_hdmi_init_type_valid  =========
[19:48:25] [PASSED] HDMI-A
[19:48:25] [PASSED] HDMI-B
[19:48:25] ===== [PASSED] drm_test_connector_hdmi_init_type_valid =====
[19:48:25] ======== drm_test_connector_hdmi_init_type_invalid  ========
[19:48:25] [PASSED] Unknown
[19:48:25] [PASSED] VGA
[19:48:25] [PASSED] DVI-I
[19:48:25] [PASSED] DVI-D
[19:48:25] [PASSED] DVI-A
[19:48:25] [PASSED] Composite
[19:48:25] [PASSED] SVIDEO
[19:48:25] [PASSED] LVDS
[19:48:25] [PASSED] Component
[19:48:25] [PASSED] DIN
[19:48:25] [PASSED] DP
[19:48:25] [PASSED] TV
[19:48:25] [PASSED] eDP
[19:48:25] [PASSED] Virtual
[19:48:25] [PASSED] DSI
[19:48:25] [PASSED] DPI
[19:48:25] [PASSED] Writeback
[19:48:25] [PASSED] SPI
[19:48:25] [PASSED] USB
[19:48:25] ==== [PASSED] drm_test_connector_hdmi_init_type_invalid ====
[19:48:25] ============ [PASSED] drmm_connector_hdmi_init =============
[19:48:25] ============= drmm_connector_init (3 subtests) =============
[19:48:25] [PASSED] drm_test_drmm_connector_init
[19:48:25] [PASSED] drm_test_drmm_connector_init_null_ddc
[19:48:25] ========= drm_test_drmm_connector_init_type_valid  =========
[19:48:25] [PASSED] Unknown
[19:48:25] [PASSED] VGA
[19:48:25] [PASSED] DVI-I
[19:48:25] [PASSED] DVI-D
[19:48:25] [PASSED] DVI-A
[19:48:25] [PASSED] Composite
[19:48:25] [PASSED] SVIDEO
[19:48:25] [PASSED] LVDS
[19:48:25] [PASSED] Component
[19:48:25] [PASSED] DIN
[19:48:25] [PASSED] DP
[19:48:25] [PASSED] HDMI-A
[19:48:25] [PASSED] HDMI-B
[19:48:25] [PASSED] TV
[19:48:25] [PASSED] eDP
[19:48:25] [PASSED] Virtual
[19:48:25] [PASSED] DSI
[19:48:25] [PASSED] DPI
[19:48:25] [PASSED] Writeback
[19:48:25] [PASSED] SPI
[19:48:25] [PASSED] USB
[19:48:25] ===== [PASSED] drm_test_drmm_connector_init_type_valid =====
[19:48:25] =============== [PASSED] drmm_connector_init ===============
[19:48:25] ========= drm_connector_dynamic_init (6 subtests) ==========
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_init
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_init_null_ddc
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_init_not_added
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_init_properties
[19:48:25] ===== drm_test_drm_connector_dynamic_init_type_valid  ======
[19:48:25] [PASSED] Unknown
[19:48:25] [PASSED] VGA
[19:48:25] [PASSED] DVI-I
[19:48:25] [PASSED] DVI-D
[19:48:25] [PASSED] DVI-A
[19:48:25] [PASSED] Composite
[19:48:25] [PASSED] SVIDEO
[19:48:25] [PASSED] LVDS
[19:48:25] [PASSED] Component
[19:48:25] [PASSED] DIN
[19:48:25] [PASSED] DP
[19:48:25] [PASSED] HDMI-A
[19:48:25] [PASSED] HDMI-B
[19:48:25] [PASSED] TV
[19:48:25] [PASSED] eDP
[19:48:25] [PASSED] Virtual
[19:48:25] [PASSED] DSI
[19:48:25] [PASSED] DPI
[19:48:25] [PASSED] Writeback
[19:48:25] [PASSED] SPI
[19:48:25] [PASSED] USB
[19:48:25] = [PASSED] drm_test_drm_connector_dynamic_init_type_valid ==
[19:48:25] ======== drm_test_drm_connector_dynamic_init_name  =========
[19:48:25] [PASSED] Unknown
[19:48:25] [PASSED] VGA
[19:48:25] [PASSED] DVI-I
[19:48:25] [PASSED] DVI-D
[19:48:25] [PASSED] DVI-A
[19:48:25] [PASSED] Composite
[19:48:25] [PASSED] SVIDEO
[19:48:25] [PASSED] LVDS
[19:48:25] [PASSED] Component
[19:48:25] [PASSED] DIN
[19:48:25] [PASSED] DP
[19:48:25] [PASSED] HDMI-A
[19:48:25] [PASSED] HDMI-B
[19:48:25] [PASSED] TV
[19:48:25] [PASSED] eDP
[19:48:25] [PASSED] Virtual
[19:48:25] [PASSED] DSI
[19:48:25] [PASSED] DPI
[19:48:25] [PASSED] Writeback
[19:48:25] [PASSED] SPI
[19:48:25] [PASSED] USB
[19:48:25] ==== [PASSED] drm_test_drm_connector_dynamic_init_name =====
[19:48:25] =========== [PASSED] drm_connector_dynamic_init ============
[19:48:25] ==== drm_connector_dynamic_register_early (4 subtests) =====
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_register_early_on_list
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_register_early_defer
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_register_early_no_init
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_register_early_no_mode_object
[19:48:25] ====== [PASSED] drm_connector_dynamic_register_early =======
[19:48:25] ======= drm_connector_dynamic_register (7 subtests) ========
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_register_on_list
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_register_no_defer
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_register_no_init
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_register_mode_object
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_register_sysfs
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_register_sysfs_name
[19:48:25] [PASSED] drm_test_drm_connector_dynamic_register_debugfs
[19:48:25] ========= [PASSED] drm_connector_dynamic_register ==========
[19:48:25] = drm_connector_attach_broadcast_rgb_property (2 subtests) =
[19:48:25] [PASSED] drm_test_drm_connector_attach_broadcast_rgb_property
[19:48:25] [PASSED] drm_test_drm_connector_attach_broadcast_rgb_property_hdmi_connector
[19:48:25] === [PASSED] drm_connector_attach_broadcast_rgb_property ===
[19:48:25] ========== drm_get_tv_mode_from_name (2 subtests) ==========
[19:48:25] ========== drm_test_get_tv_mode_from_name_valid  ===========
[19:48:25] [PASSED] NTSC
[19:48:25] [PASSED] NTSC-443
[19:48:25] [PASSED] NTSC-J
[19:48:25] [PASSED] PAL
[19:48:25] [PASSED] PAL-M
[19:48:25] [PASSED] PAL-N
[19:48:25] [PASSED] SECAM
[19:48:25] [PASSED] Mono
[19:48:25] ====== [PASSED] drm_test_get_tv_mode_from_name_valid =======
[19:48:25] [PASSED] drm_test_get_tv_mode_from_name_truncated
[19:48:25] ============ [PASSED] drm_get_tv_mode_from_name ============
[19:48:25] = drm_test_connector_hdmi_compute_mode_clock (12 subtests) =
[19:48:25] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb
[19:48:25] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc
[19:48:25] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_10bpc_vic_1
[19:48:25] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc
[19:48:25] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_12bpc_vic_1
[19:48:25] [PASSED] drm_test_drm_hdmi_compute_mode_clock_rgb_double
[19:48:25] = drm_test_connector_hdmi_compute_mode_clock_yuv420_valid  =
[19:48:25] [PASSED] VIC 96
[19:48:25] [PASSED] VIC 97
[19:48:25] [PASSED] VIC 101
[19:48:25] [PASSED] VIC 102
[19:48:25] [PASSED] VIC 106
[19:48:25] [PASSED] VIC 107
[19:48:25] === [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_valid ===
[19:48:25] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_10_bpc
[19:48:25] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv420_12_bpc
[19:48:25] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_8_bpc
[19:48:25] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_10_bpc
[19:48:25] [PASSED] drm_test_connector_hdmi_compute_mode_clock_yuv422_12_bpc
[19:48:25] === [PASSED] drm_test_connector_hdmi_compute_mode_clock ====
[19:48:25] == drm_hdmi_connector_get_broadcast_rgb_name (2 subtests) ==
[19:48:25] === drm_test_drm_hdmi_connector_get_broadcast_rgb_name  ====
[19:48:25] [PASSED] Automatic
[19:48:25] [PASSED] Full
[19:48:25] [PASSED] Limited 16:235
[19:48:25] === [PASSED] drm_test_drm_hdmi_connector_get_broadcast_rgb_name ===
[19:48:25] [PASSED] drm_test_drm_hdmi_connector_get_broadcast_rgb_name_invalid
[19:48:25] ==== [PASSED] drm_hdmi_connector_get_broadcast_rgb_name ====
[19:48:25] == drm_hdmi_connector_get_output_format_name (2 subtests) ==
[19:48:25] === drm_test_drm_hdmi_connector_get_output_format_name  ====
[19:48:25] [PASSED] RGB
[19:48:25] [PASSED] YUV 4:2:0
[19:48:25] [PASSED] YUV 4:2:2
[19:48:25] [PASSED] YUV 4:4:4
[19:48:25] === [PASSED] drm_test_drm_hdmi_connector_get_output_format_name ===
[19:48:25] [PASSED] drm_test_drm_hdmi_connector_get_output_format_name_invalid
[19:48:25] ==== [PASSED] drm_hdmi_connector_get_output_format_name ====
[19:48:25] ============= drm_damage_helper (21 subtests) ==============
[19:48:25] [PASSED] drm_test_damage_iter_no_damage
[19:48:25] [PASSED] drm_test_damage_iter_no_damage_fractional_src
[19:48:25] [PASSED] drm_test_damage_iter_no_damage_src_moved
[19:48:25] [PASSED] drm_test_damage_iter_no_damage_fractional_src_moved
[19:48:25] [PASSED] drm_test_damage_iter_no_damage_not_visible
[19:48:25] [PASSED] drm_test_damage_iter_no_damage_no_crtc
[19:48:25] [PASSED] drm_test_damage_iter_no_damage_no_fb
[19:48:25] [PASSED] drm_test_damage_iter_simple_damage
[19:48:25] [PASSED] drm_test_damage_iter_single_damage
[19:48:25] [PASSED] drm_test_damage_iter_single_damage_intersect_src
[19:48:25] [PASSED] drm_test_damage_iter_single_damage_outside_src
[19:48:25] [PASSED] drm_test_damage_iter_single_damage_fractional_src
[19:48:25] [PASSED] drm_test_damage_iter_single_damage_intersect_fractional_src
[19:48:25] [PASSED] drm_test_damage_iter_single_damage_outside_fractional_src
[19:48:25] [PASSED] drm_test_damage_iter_single_damage_src_moved
[19:48:25] [PASSED] drm_test_damage_iter_single_damage_fractional_src_moved
[19:48:25] [PASSED] drm_test_damage_iter_damage
[19:48:25] [PASSED] drm_test_damage_iter_damage_one_intersect
[19:48:25] [PASSED] drm_test_damage_iter_damage_one_outside
[19:48:25] [PASSED] drm_test_damage_iter_damage_src_moved
[19:48:25] [PASSED] drm_test_damage_iter_damage_not_visible
[19:48:25] ================ [PASSED] drm_damage_helper ================
[19:48:25] ============== drm_dp_mst_helper (3 subtests) ==============
[19:48:25] ============== drm_test_dp_mst_calc_pbn_mode  ==============
[19:48:25] [PASSED] Clock 154000 BPP 30 DSC disabled
[19:48:25] [PASSED] Clock 234000 BPP 30 DSC disabled
[19:48:25] [PASSED] Clock 297000 BPP 24 DSC disabled
[19:48:25] [PASSED] Clock 332880 BPP 24 DSC enabled
[19:48:25] [PASSED] Clock 324540 BPP 24 DSC enabled
[19:48:25] ========== [PASSED] drm_test_dp_mst_calc_pbn_mode ==========
[19:48:25] ============== drm_test_dp_mst_calc_pbn_div  ===============
[19:48:25] [PASSED] Link rate 2000000 lane count 4
[19:48:25] [PASSED] Link rate 2000000 lane count 2
[19:48:25] [PASSED] Link rate 2000000 lane count 1
[19:48:25] [PASSED] Link rate 1350000 lane count 4
[19:48:25] [PASSED] Link rate 1350000 lane count 2
[19:48:25] [PASSED] Link rate 1350000 lane count 1
[19:48:25] [PASSED] Link rate 1000000 lane count 4
[19:48:25] [PASSED] Link rate 1000000 lane count 2
[19:48:25] [PASSED] Link rate 1000000 lane count 1
[19:48:25] [PASSED] Link rate 810000 lane count 4
[19:48:25] [PASSED] Link rate 810000 lane count 2
[19:48:25] [PASSED] Link rate 810000 lane count 1
[19:48:25] [PASSED] Link rate 540000 lane count 4
[19:48:25] [PASSED] Link rate 540000 lane count 2
[19:48:25] [PASSED] Link rate 540000 lane count 1
[19:48:25] [PASSED] Link rate 270000 lane count 4
[19:48:25] [PASSED] Link rate 270000 lane count 2
[19:48:25] [PASSED] Link rate 270000 lane count 1
[19:48:25] [PASSED] Link rate 162000 lane count 4
[19:48:25] [PASSED] Link rate 162000 lane count 2
[19:48:25] [PASSED] Link rate 162000 lane count 1
[19:48:25] ========== [PASSED] drm_test_dp_mst_calc_pbn_div ===========
[19:48:25] ========= drm_test_dp_mst_sideband_msg_req_decode  =========
[19:48:25] [PASSED] DP_ENUM_PATH_RESOURCES with port number
[19:48:25] [PASSED] DP_POWER_UP_PHY with port number
[19:48:25] [PASSED] DP_POWER_DOWN_PHY with port number
[19:48:25] [PASSED] DP_ALLOCATE_PAYLOAD with SDP stream sinks
[19:48:25] [PASSED] DP_ALLOCATE_PAYLOAD with port number
[19:48:25] [PASSED] DP_ALLOCATE_PAYLOAD with VCPI
[19:48:25] [PASSED] DP_ALLOCATE_PAYLOAD with PBN
[19:48:25] [PASSED] DP_QUERY_PAYLOAD with port number
[19:48:25] [PASSED] DP_QUERY_PAYLOAD with VCPI
[19:48:25] [PASSED] DP_REMOTE_DPCD_READ with port number
[19:48:25] [PASSED] DP_REMOTE_DPCD_READ with DPCD address
[19:48:25] [PASSED] DP_REMOTE_DPCD_READ with max number of bytes
[19:48:25] [PASSED] DP_REMOTE_DPCD_WRITE with port number
[19:48:25] [PASSED] DP_REMOTE_DPCD_WRITE with DPCD address
[19:48:25] [PASSED] DP_REMOTE_DPCD_WRITE with data array
[19:48:25] [PASSED] DP_REMOTE_I2C_READ with port number
[19:48:25] [PASSED] DP_REMOTE_I2C_READ with I2C device ID
[19:48:25] [PASSED] DP_REMOTE_I2C_READ with transactions array
[19:48:25] [PASSED] DP_REMOTE_I2C_WRITE with port number
[19:48:25] [PASSED] DP_REMOTE_I2C_WRITE with I2C device ID
[19:48:25] [PASSED] DP_REMOTE_I2C_WRITE with data array
[19:48:25] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream ID
[19:48:25] [PASSED] DP_QUERY_STREAM_ENC_STATUS with client ID
[19:48:25] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream event
[19:48:25] [PASSED] DP_QUERY_STREAM_ENC_STATUS with valid stream event
[19:48:25] [PASSED] DP_QUERY_STREAM_ENC_STATUS with stream behavior
[19:48:25] [PASSED] DP_QUERY_STREAM_ENC_STATUS with a valid stream behavior
[19:48:25] ===== [PASSED] drm_test_dp_mst_sideband_msg_req_decode =====
[19:48:25] ================ [PASSED] drm_dp_mst_helper ================
[19:48:25] ================== drm_exec (7 subtests) ===================
[19:48:25] [PASSED] sanitycheck
[19:48:25] [PASSED] test_lock
[19:48:25] [PASSED] test_lock_unlock
[19:48:25] [PASSED] test_duplicates
[19:48:25] [PASSED] test_prepare
[19:48:25] [PASSED] test_prepare_array
[19:48:25] [PASSED] test_multiple_loops
[19:48:25] ==================== [PASSED] drm_exec =====================
[19:48:25] =========== drm_format_helper_test (17 subtests) ===========
[19:48:25] ============== drm_test_fb_xrgb8888_to_gray8  ==============
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ========== [PASSED] drm_test_fb_xrgb8888_to_gray8 ==========
[19:48:25] ============= drm_test_fb_xrgb8888_to_rgb332  ==============
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb332 ==========
[19:48:25] ============= drm_test_fb_xrgb8888_to_rgb565  ==============
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb565 ==========
[19:48:25] ============ drm_test_fb_xrgb8888_to_xrgb1555  =============
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ======== [PASSED] drm_test_fb_xrgb8888_to_xrgb1555 =========
[19:48:25] ============ drm_test_fb_xrgb8888_to_argb1555  =============
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ======== [PASSED] drm_test_fb_xrgb8888_to_argb1555 =========
[19:48:25] ============ drm_test_fb_xrgb8888_to_rgba5551  =============
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ======== [PASSED] drm_test_fb_xrgb8888_to_rgba5551 =========
[19:48:25] ============= drm_test_fb_xrgb8888_to_rgb888  ==============
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ========= [PASSED] drm_test_fb_xrgb8888_to_rgb888 ==========
[19:48:25] ============= drm_test_fb_xrgb8888_to_bgr888  ==============
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ========= [PASSED] drm_test_fb_xrgb8888_to_bgr888 ==========
[19:48:25] ============ drm_test_fb_xrgb8888_to_argb8888  =============
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ======== [PASSED] drm_test_fb_xrgb8888_to_argb8888 =========
[19:48:25] =========== drm_test_fb_xrgb8888_to_xrgb2101010  ===========
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ======= [PASSED] drm_test_fb_xrgb8888_to_xrgb2101010 =======
[19:48:25] =========== drm_test_fb_xrgb8888_to_argb2101010  ===========
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ======= [PASSED] drm_test_fb_xrgb8888_to_argb2101010 =======
[19:48:25] ============== drm_test_fb_xrgb8888_to_mono  ===============
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ========== [PASSED] drm_test_fb_xrgb8888_to_mono ===========
[19:48:25] ==================== drm_test_fb_swab  =====================
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ================ [PASSED] drm_test_fb_swab =================
[19:48:25] ============ drm_test_fb_xrgb8888_to_xbgr8888  =============
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ======== [PASSED] drm_test_fb_xrgb8888_to_xbgr8888 =========
[19:48:25] ============ drm_test_fb_xrgb8888_to_abgr8888  =============
[19:48:25] [PASSED] single_pixel_source_buffer
[19:48:25] [PASSED] single_pixel_clip_rectangle
[19:48:25] [PASSED] well_known_colors
[19:48:25] [PASSED] destination_pitch
[19:48:25] ======== [PASSED] drm_test_fb_xrgb8888_to_abgr8888 =========
[19:48:25] ================= drm_test_fb_clip_offset  =================
[19:48:25] [PASSED] pass through
[19:48:25] [PASSED] horizontal offset
[19:48:25] [PASSED] vertical offset
[19:48:25] [PASSED] horizontal and vertical offset
[19:48:25] [PASSED] horizontal offset (custom pitch)
[19:48:25] [PASSED] vertical offset (custom pitch)
[19:48:25] [PASSED] horizontal and vertical offset (custom pitch)
[19:48:25] ============= [PASSED] drm_test_fb_clip_offset =============
[19:48:25] =================== drm_test_fb_memcpy  ====================
[19:48:25] [PASSED] single_pixel_source_buffer: XR24 little-endian (0x34325258)
[19:48:25] [PASSED] single_pixel_source_buffer: XRA8 little-endian (0x38415258)
[19:48:25] [PASSED] single_pixel_source_buffer: YU24 little-endian (0x34325559)
[19:48:25] [PASSED] single_pixel_clip_rectangle: XB24 little-endian (0x34324258)
[19:48:25] [PASSED] single_pixel_clip_rectangle: XRA8 little-endian (0x38415258)
[19:48:25] [PASSED] single_pixel_clip_rectangle: YU24 little-endian (0x34325559)
[19:48:25] [PASSED] well_known_colors: XB24 little-endian (0x34324258)
[19:48:25] [PASSED] well_known_colors: XRA8 little-endian (0x38415258)
[19:48:25] [PASSED] well_known_colors: YU24 little-endian (0x34325559)
[19:48:25] [PASSED] destination_pitch: XB24 little-endian (0x34324258)
[19:48:25] [PASSED] destination_pitch: XRA8 little-endian (0x38415258)
[19:48:25] [PASSED] destination_pitch: YU24 little-endian (0x34325559)
[19:48:25] =============== [PASSED] drm_test_fb_memcpy ================
[19:48:25] ============= [PASSED] drm_format_helper_test ==============
[19:48:25] ================= drm_format (18 subtests) =================
[19:48:25] [PASSED] drm_test_format_block_width_invalid
[19:48:25] [PASSED] drm_test_format_block_width_one_plane
[19:48:25] [PASSED] drm_test_format_block_width_two_plane
[19:48:25] [PASSED] drm_test_format_block_width_three_plane
[19:48:25] [PASSED] drm_test_format_block_width_tiled
[19:48:25] [PASSED] drm_test_format_block_height_invalid
[19:48:25] [PASSED] drm_test_format_block_height_one_plane
[19:48:25] [PASSED] drm_test_format_block_height_two_plane
[19:48:25] [PASSED] drm_test_format_block_height_three_plane
[19:48:25] [PASSED] drm_test_format_block_height_tiled
[19:48:25] [PASSED] drm_test_format_min_pitch_invalid
[19:48:25] [PASSED] drm_test_format_min_pitch_one_plane_8bpp
[19:48:25] [PASSED] drm_test_format_min_pitch_one_plane_16bpp
[19:48:25] [PASSED] drm_test_format_min_pitch_one_plane_24bpp
[19:48:25] [PASSED] drm_test_format_min_pitch_one_plane_32bpp
[19:48:25] [PASSED] drm_test_format_min_pitch_two_plane
[19:48:25] [PASSED] drm_test_format_min_pitch_three_plane_8bpp
[19:48:25] [PASSED] drm_test_format_min_pitch_tiled
[19:48:25] =================== [PASSED] drm_format ====================
[19:48:25] ============== drm_framebuffer (10 subtests) ===============
[19:48:25] ========== drm_test_framebuffer_check_src_coords  ==========
[19:48:25] [PASSED] Success: source fits into fb
[19:48:25] [PASSED] Fail: overflowing fb with x-axis coordinate
[19:48:25] [PASSED] Fail: overflowing fb with y-axis coordinate
[19:48:25] [PASSED] Fail: overflowing fb with source width
[19:48:25] [PASSED] Fail: overflowing fb with source height
[19:48:25] ====== [PASSED] drm_test_framebuffer_check_src_coords ======
[19:48:25] [PASSED] drm_test_framebuffer_cleanup
[19:48:25] =============== drm_test_framebuffer_create  ===============
[19:48:25] [PASSED] ABGR8888 normal sizes
[19:48:25] [PASSED] ABGR8888 max sizes
[19:48:25] [PASSED] ABGR8888 pitch greater than min required
[19:48:25] [PASSED] ABGR8888 pitch less than min required
[19:48:25] [PASSED] ABGR8888 Invalid width
[19:48:25] [PASSED] ABGR8888 Invalid buffer handle
[19:48:25] [PASSED] No pixel format
[19:48:25] [PASSED] ABGR8888 Width 0
[19:48:25] [PASSED] ABGR8888 Height 0
[19:48:25] [PASSED] ABGR8888 Out of bound height * pitch combination
[19:48:25] [PASSED] ABGR8888 Large buffer offset
[19:48:25] [PASSED] ABGR8888 Buffer offset for inexistent plane
[19:48:25] [PASSED] ABGR8888 Invalid flag
[19:48:25] [PASSED] ABGR8888 Set DRM_MODE_FB_MODIFIERS without modifiers
[19:48:25] [PASSED] ABGR8888 Valid buffer modifier
[19:48:25] [PASSED] ABGR8888 Invalid buffer modifier(DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)
[19:48:25] [PASSED] ABGR8888 Extra pitches without DRM_MODE_FB_MODIFIERS
[19:48:25] [PASSED] ABGR8888 Extra pitches with DRM_MODE_FB_MODIFIERS
[19:48:25] [PASSED] NV12 Normal sizes
[19:48:25] [PASSED] NV12 Max sizes
[19:48:25] [PASSED] NV12 Invalid pitch
[19:48:25] [PASSED] NV12 Invalid modifier/missing DRM_MODE_FB_MODIFIERS flag
[19:48:25] [PASSED] NV12 different  modifier per-plane
[19:48:25] [PASSED] NV12 with DRM_FORMAT_MOD_SAMSUNG_64_32_TILE
[19:48:25] [PASSED] NV12 Valid modifiers without DRM_MODE_FB_MODIFIERS
[19:48:25] [PASSED] NV12 Modifier for inexistent plane
[19:48:25] [PASSED] NV12 Handle for inexistent plane
[19:48:25] [PASSED] NV12 Handle for inexistent plane without DRM_MODE_FB_MODIFIERS
[19:48:25] [PASSED] YVU420 DRM_MODE_FB_MODIFIERS set without modifier
[19:48:25] [PASSED] YVU420 Normal sizes
[19:48:25] [PASSED] YVU420 Max sizes
[19:48:25] [PASSED] YVU420 Invalid pitch
[19:48:25] [PASSED] YVU420 Different pitches
[19:48:25] [PASSED] YVU420 Different buffer offsets/pitches
[19:48:25] [PASSED] YVU420 Modifier set just for plane 0, without DRM_MODE_FB_MODIFIERS
[19:48:25] [PASSED] YVU420 Modifier set just for planes 0, 1, without DRM_MODE_FB_MODIFIERS
[19:48:25] [PASSED] YVU420 Modifier set just for plane 0, 1, with DRM_MODE_FB_MODIFIERS
[19:48:25] [PASSED] YVU420 Valid modifier
[19:48:25] [PASSED] YVU420 Different modifiers per plane
[19:48:25] [PASSED] YVU420 Modifier for inexistent plane
[19:48:25] [PASSED] YUV420_10BIT Invalid modifier(DRM_FORMAT_MOD_LINEAR)
[19:48:25] [PASSED] X0L2 Normal sizes
[19:48:25] [PASSED] X0L2 Max sizes
[19:48:25] [PASSED] X0L2 Invalid pitch
[19:48:25] [PASSED] X0L2 Pitch greater than minimum required
[19:48:25] [PASSED] X0L2 Handle for inexistent plane
[19:48:25] [PASSED] X0L2 Offset for inexistent plane, without DRM_MODE_FB_MODIFIERS set
[19:48:25] [PASSED] X0L2 Modifier without DRM_MODE_FB_MODIFIERS set
[19:48:25] [PASSED] X0L2 Valid modifier
[19:48:25] [PASSED] X0L2 Modifier for inexistent plane
[19:48:25] =========== [PASSED] drm_test_framebuffer_create ===========
[19:48:25] [PASSED] drm_test_framebuffer_free
[19:48:25] [PASSED] drm_test_framebuffer_init
[19:48:25] [PASSED] drm_test_framebuffer_init_bad_format
[19:48:25] [PASSED] drm_test_framebuffer_init_dev_mismatch
[19:48:25] [PASSED] drm_test_framebuffer_lookup
[19:48:25] [PASSED] drm_test_framebuffer_lookup_inexistent
[19:48:25] [PASSED] drm_test_framebuffer_modifiers_not_supported
[19:48:25] ================= [PASSED] drm_framebuffer =================
[19:48:25] ================ drm_gem_shmem (8 subtests) ================
[19:48:25] [PASSED] drm_gem_shmem_test_obj_create
[19:48:25] [PASSED] drm_gem_shmem_test_obj_create_private
[19:48:25] [PASSED] drm_gem_shmem_test_pin_pages
[19:48:25] [PASSED] drm_gem_shmem_test_vmap
[19:48:25] [PASSED] drm_gem_shmem_test_get_sg_table
[19:48:25] [PASSED] drm_gem_shmem_test_get_pages_sgt
[19:48:25] [PASSED] drm_gem_shmem_test_madvise
[19:48:25] [PASSED] drm_gem_shmem_test_purge
[19:48:25] ================== [PASSED] drm_gem_shmem ==================
[19:48:25] === drm_atomic_helper_connector_hdmi_check (29 subtests) ===
[19:48:25] [PASSED] drm_test_check_broadcast_rgb_auto_cea_mode
[19:48:25] [PASSED] drm_test_check_broadcast_rgb_auto_cea_mode_vic_1
[19:48:25] [PASSED] drm_test_check_broadcast_rgb_full_cea_mode
[19:48:25] [PASSED] drm_test_check_broadcast_rgb_full_cea_mode_vic_1
[19:48:25] [PASSED] drm_test_check_broadcast_rgb_limited_cea_mode
[19:48:25] [PASSED] drm_test_check_broadcast_rgb_limited_cea_mode_vic_1
[19:48:25] ====== drm_test_check_broadcast_rgb_cea_mode_yuv420  =======
[19:48:25] [PASSED] Automatic
[19:48:25] [PASSED] Full
[19:48:25] [PASSED] Limited 16:235
[19:48:25] == [PASSED] drm_test_check_broadcast_rgb_cea_mode_yuv420 ===
[19:48:25] [PASSED] drm_test_check_broadcast_rgb_crtc_mode_changed
[19:48:25] [PASSED] drm_test_check_broadcast_rgb_crtc_mode_not_changed
[19:48:25] [PASSED] drm_test_check_disable_connector
[19:48:25] [PASSED] drm_test_check_hdmi_funcs_reject_rate
[19:48:25] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_rgb
[19:48:25] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_yuv420
[19:48:25] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv422
[19:48:25] [PASSED] drm_test_check_max_tmds_rate_bpc_fallback_ignore_yuv420
[19:48:25] [PASSED] drm_test_check_driver_unsupported_fallback_yuv420
[19:48:25] [PASSED] drm_test_check_output_bpc_crtc_mode_changed
[19:48:25] [PASSED] drm_test_check_output_bpc_crtc_mode_not_changed
[19:48:25] [PASSED] drm_test_check_output_bpc_dvi
[19:48:25] [PASSED] drm_test_check_output_bpc_format_vic_1
[19:48:25] [PASSED] drm_test_check_output_bpc_format_display_8bpc_only
[19:48:25] [PASSED] drm_test_check_output_bpc_format_display_rgb_only
[19:48:25] [PASSED] drm_test_check_output_bpc_format_driver_8bpc_only
[19:48:25] [PASSED] drm_test_check_output_bpc_format_driver_rgb_only
[19:48:25] [PASSED] drm_test_check_tmds_char_rate_rgb_8bpc
[19:48:25] [PASSED] drm_test_check_tmds_char_rate_rgb_10bpc
[19:48:25] [PASSED] drm_test_check_tmds_char_rate_rgb_12bpc
[19:48:25] ============ drm_test_check_hdmi_color_format  =============
[19:48:25] [PASSED] AUTO -> RGB
[19:48:25] [PASSED] YCBCR422 -> YUV422
[19:48:25] [PASSED] YCBCR420 -> YUV420
[19:48:25] [PASSED] YCBCR444 -> YUV444
[19:48:25] [PASSED] RGB -> RGB
[19:48:25] ======== [PASSED] drm_test_check_hdmi_color_format =========
[19:48:25] ======== drm_test_check_hdmi_color_format_420_only  ========
[19:48:25] [PASSED] RGB should fail
[19:48:25] [PASSED] YUV444 should fail
[19:48:25] [PASSED] YUV422 should fail
[19:48:25] [PASSED] YUV420 should work
[19:48:25] ==== [PASSED] drm_test_check_hdmi_color_format_420_only ====
[19:48:25] ===== [PASSED] drm_atomic_helper_connector_hdmi_check ======
[19:48:25] === drm_atomic_helper_connector_hdmi_reset (6 subtests) ====
[19:48:25] [PASSED] drm_test_check_broadcast_rgb_value
[19:48:25] [PASSED] drm_test_check_bpc_8_value
[19:48:25] [PASSED] drm_test_check_bpc_10_value
[19:48:25] [PASSED] drm_test_check_bpc_12_value
[19:48:25] [PASSED] drm_test_check_format_value
[19:48:25] [PASSED] drm_test_check_tmds_char_value
[19:48:25] ===== [PASSED] drm_atomic_helper_connector_hdmi_reset ======
[19:48:25] = drm_atomic_helper_connector_hdmi_mode_valid (7 subtests) =
[19:48:25] [PASSED] drm_test_check_mode_valid
[19:48:25] [PASSED] drm_test_check_mode_valid_reject
[19:48:25] [PASSED] drm_test_check_mode_valid_reject_rate
[19:48:25] [PASSED] drm_test_check_mode_valid_reject_max_clock
[19:48:25] [PASSED] drm_test_check_mode_valid_yuv420_only_max_clock
[19:48:25] [PASSED] drm_test_check_mode_valid_reject_yuv420_only_connector
[19:48:25] [PASSED] drm_test_check_mode_valid_accept_yuv420_also_connector_rgb
[19:48:25] === [PASSED] drm_atomic_helper_connector_hdmi_mode_valid ===
[19:48:25] = drm_atomic_helper_connector_hdmi_infoframes (5 subtests) =
[19:48:25] [PASSED] drm_test_check_infoframes
[19:48:25] [PASSED] drm_test_check_reject_avi_infoframe
[19:48:25] [PASSED] drm_test_check_reject_hdr_infoframe_bpc_8
[19:48:25] [PASSED] drm_test_check_reject_hdr_infoframe_bpc_10
[19:48:25] [PASSED] drm_test_check_reject_audio_infoframe
[19:48:25] === [PASSED] drm_atomic_helper_connector_hdmi_infoframes ===
[19:48:25] ================= drm_managed (2 subtests) =================
[19:48:25] [PASSED] drm_test_managed_release_action
[19:48:25] [PASSED] drm_test_managed_run_action
[19:48:25] =================== [PASSED] drm_managed ===================
[19:48:25] =================== drm_mm (6 subtests) ====================
[19:48:25] [PASSED] drm_test_mm_init
[19:48:25] [PASSED] drm_test_mm_debug
[19:48:25] [PASSED] drm_test_mm_align32
[19:48:25] [PASSED] drm_test_mm_align64
[19:48:25] [PASSED] drm_test_mm_lowest
[19:48:25] [PASSED] drm_test_mm_highest
[19:48:25] ===================== [PASSED] drm_mm ======================
[19:48:25] ============= drm_modes_analog_tv (5 subtests) =============
[19:48:25] [PASSED] drm_test_modes_analog_tv_mono_576i
[19:48:25] [PASSED] drm_test_modes_analog_tv_ntsc_480i
[19:48:25] [PASSED] drm_test_modes_analog_tv_ntsc_480i_inlined
[19:48:25] [PASSED] drm_test_modes_analog_tv_pal_576i
[19:48:25] [PASSED] drm_test_modes_analog_tv_pal_576i_inlined
[19:48:25] =============== [PASSED] drm_modes_analog_tv ===============
[19:48:25] ============== drm_panic_helper (3 subtests) ===============
[19:48:25] ============= drm_test_panic_screen_user_map  ==============
[19:48:25] [PASSED] Panic screen user, mode: 1024 x 768 	XR24 little-endian (0x34325258)
[19:48:25] [PASSED] Panic screen user, mode: 494 x 494 	XR24 little-endian (0x34325258)
[19:48:25] [PASSED] Panic screen user, mode: 1920 x 1080 	XR24 little-endian (0x34325258)
[19:48:25] [PASSED] Panic screen user, mode: 1024 x 768 	RG16 little-endian (0x36314752)
[19:48:25] [PASSED] Panic screen user, mode: 1024 x 768 	RG24 little-endian (0x34324752)
[19:48:25] [PASSED] Panic screen kmsg, mode: 1024 x 768 	XR24 little-endian (0x34325258)
[19:48:25] [PASSED] Panic screen kmsg, mode: 494 x 494 	XR24 little-endian (0x34325258)
[19:48:25] [PASSED] Panic screen kmsg, mode: 1920 x 1080 	XR24 little-endian (0x34325258)
[19:48:25] [PASSED] Panic screen kmsg, mode: 1024 x 768 	RG16 little-endian (0x36314752)
[19:48:25] [PASSED] Panic screen kmsg, mode: 1024 x 768 	RG24 little-endian (0x34324752)
[19:48:25] ========= [PASSED] drm_test_panic_screen_user_map ==========
[19:48:25] ============= drm_test_panic_screen_user_page  =============
[19:48:25] [PASSED] Panic screen user, mode: 1024 x 768 	XR24 little-endian (0x34325258)
[19:48:25] [PASSED] Panic screen user, mode: 494 x 494 	XR24 little-endian (0x34325258)
[19:48:25] [PASSED] Panic screen user, mode: 1920 x 1080 	XR24 little-endian (0x34325258)
[19:48:25] [PASSED] Panic screen user, mode: 1024 x 768 	RG16 little-endian (0x36314752)
[19:48:25] [PASSED] Panic screen user, mode: 1024 x 768 	RG24 little-endian (0x34324752)
[19:48:25] [PASSED] Panic screen kmsg, mode: 1024 x 768 	XR24 little-endian (0x34325258)
[19:48:26] [PASSED] Panic screen kmsg, mode: 494 x 494 	XR24 little-endian (0x34325258)
[19:48:26] [PASSED] Panic screen kmsg, mode: 1920 x 1080 	XR24 little-endian (0x34325258)
[19:48:26] [PASSED] Panic screen kmsg, mode: 1024 x 768 	RG16 little-endian (0x36314752)
[19:48:26] [PASSED] Panic screen kmsg, mode: 1024 x 768 	RG24 little-endian (0x34324752)
[19:48:26] ========= [PASSED] drm_test_panic_screen_user_page =========
[19:48:26] ========== drm_test_panic_screen_user_set_pixel  ===========
[19:48:26] [PASSED] Panic screen user, mode: 1024 x 768 	XR24 little-endian (0x34325258)
[19:48:26] [PASSED] Panic screen user, mode: 494 x 494 	XR24 little-endian (0x34325258)
[19:48:26] [PASSED] Panic screen user, mode: 1920 x 1080 	XR24 little-endian (0x34325258)
[19:48:26] [PASSED] Panic screen user, mode: 1024 x 768 	RG16 little-endian (0x36314752)
[19:48:26] [PASSED] Panic screen user, mode: 1024 x 768 	RG24 little-endian (0x34324752)
[19:48:26] [PASSED] Panic screen kmsg, mode: 1024 x 768 	XR24 little-endian (0x34325258)
[19:48:26] [PASSED] Panic screen kmsg, mode: 494 x 494 	XR24 little-endian (0x34325258)
[19:48:26] [PASSED] Panic screen kmsg, mode: 1920 x 1080 	XR24 little-endian (0x34325258)
[19:48:26] [PASSED] Panic screen kmsg, mode: 1024 x 768 	RG16 little-endian (0x36314752)
[19:48:26] [PASSED] Panic screen kmsg, mode: 1024 x 768 	RG24 little-endian (0x34324752)
[19:48:26] ====== [PASSED] drm_test_panic_screen_user_set_pixel =======
[19:48:26] ================ [PASSED] drm_panic_helper =================
[19:48:26] ============== drm_plane_helper (2 subtests) ===============
[19:48:26] =============== drm_test_check_plane_state  ================
[19:48:26] [PASSED] clipping_simple
[19:48:26] [PASSED] clipping_rotate_reflect
[19:48:26] [PASSED] positioning_simple
[19:48:26] [PASSED] upscaling
[19:48:26] [PASSED] downscaling
[19:48:26] [PASSED] rounding1
[19:48:26] [PASSED] rounding2
[19:48:26] [PASSED] rounding3
[19:48:26] [PASSED] rounding4
[19:48:26] =========== [PASSED] drm_test_check_plane_state ============
[19:48:26] =========== drm_test_check_invalid_plane_state  ============
[19:48:26] [PASSED] positioning_invalid
[19:48:26] [PASSED] upscaling_invalid
[19:48:26] [PASSED] downscaling_invalid
[19:48:26] ======= [PASSED] drm_test_check_invalid_plane_state ========
[19:48:26] ================ [PASSED] drm_plane_helper =================
[19:48:26] ====== drm_connector_helper_tv_get_modes (1 subtest) =======
[19:48:26] ====== drm_test_connector_helper_tv_get_modes_check  =======
[19:48:26] [PASSED] None
[19:48:26] [PASSED] PAL
[19:48:26] [PASSED] NTSC
[19:48:26] [PASSED] Both, NTSC Default
[19:48:26] [PASSED] Both, PAL Default
[19:48:26] [PASSED] Both, NTSC Default, with PAL on command-line
[19:48:26] [PASSED] Both, PAL Default, with NTSC on command-line
[19:48:26] == [PASSED] drm_test_connector_helper_tv_get_modes_check ===
[19:48:26] ======== [PASSED] drm_connector_helper_tv_get_modes ========
[19:48:26] ================== drm_rect (9 subtests) ===================
[19:48:26] [PASSED] drm_test_rect_clip_scaled_div_by_zero
[19:48:26] [PASSED] drm_test_rect_clip_scaled_not_clipped
[19:48:26] [PASSED] drm_test_rect_clip_scaled_clipped
[19:48:26] [PASSED] drm_test_rect_clip_scaled_signed_vs_unsigned
[19:48:26] ================= drm_test_rect_intersect  =================
[19:48:26] [PASSED] top-left x bottom-right: 2x2+1+1 x 2x2+0+0
[19:48:26] [PASSED] top-right x bottom-left: 2x2+0+0 x 2x2+1-1
[19:48:26] [PASSED] bottom-left x top-right: 2x2+1-1 x 2x2+0+0
[19:48:26] [PASSED] bottom-right x top-left: 2x2+0+0 x 2x2+1+1
[19:48:26] [PASSED] right x left: 2x1+0+0 x 3x1+1+0
[19:48:26] [PASSED] left x right: 3x1+1+0 x 2x1+0+0
[19:48:26] [PASSED] up x bottom: 1x2+0+0 x 1x3+0-1
[19:48:26] [PASSED] bottom x up: 1x3+0-1 x 1x2+0+0
[19:48:26] [PASSED] touching corner: 1x1+0+0 x 2x2+1+1
[19:48:26] [PASSED] touching side: 1x1+0+0 x 1x1+1+0
[19:48:26] [PASSED] equal rects: 2x2+0+0 x 2x2+0+0
[19:48:26] [PASSED] inside another: 2x2+0+0 x 1x1+1+1
[19:48:26] [PASSED] far away: 1x1+0+0 x 1x1+3+6
[19:48:26] [PASSED] points intersecting: 0x0+5+10 x 0x0+5+10
[19:48:26] [PASSED] points not intersecting: 0x0+0+0 x 0x0+5+10
[19:48:26] ============= [PASSED] drm_test_rect_intersect =============
[19:48:26] ================ drm_test_rect_calc_hscale  ================
[19:48:26] [PASSED] normal use
[19:48:26] [PASSED] out of max range
[19:48:26] [PASSED] out of min range
[19:48:26] [PASSED] zero dst
[19:48:26] [PASSED] negative src
[19:48:26] [PASSED] negative dst
[19:48:26] ============ [PASSED] drm_test_rect_calc_hscale ============
[19:48:26] ================ drm_test_rect_calc_vscale  ================
[19:48:26] [PASSED] normal use
[19:48:26] [PASSED] out of max range
[19:48:26] [PASSED] out of min range
[19:48:26] [PASSED] zero dst
[19:48:26] [PASSED] negative src
[19:48:26] [PASSED] negative dst
[19:48:26] ============ [PASSED] drm_test_rect_calc_vscale ============
[19:48:26] ================== drm_test_rect_rotate  ===================
[19:48:26] [PASSED] reflect-x
[19:48:26] [PASSED] reflect-y
[19:48:26] [PASSED] rotate-0
[19:48:26] [PASSED] rotate-90
[19:48:26] [PASSED] rotate-180
[19:48:26] [PASSED] rotate-270
[19:48:26] ============== [PASSED] drm_test_rect_rotate ===============
[19:48:26] ================ drm_test_rect_rotate_inv  =================
[19:48:26] [PASSED] reflect-x
[19:48:26] [PASSED] reflect-y
[19:48:26] [PASSED] rotate-0
[19:48:26] [PASSED] rotate-90
[19:48:26] [PASSED] rotate-180
[19:48:26] [PASSED] rotate-270
[19:48:26] ============ [PASSED] drm_test_rect_rotate_inv =============
[19:48:26] ==================== [PASSED] drm_rect =====================
[19:48:26] ============ drm_sysfb_modeset_test (1 subtest) ============
[19:48:26] ============ drm_test_sysfb_build_fourcc_list  =============
[19:48:26] [PASSED] no native formats
[19:48:26] [PASSED] XRGB8888 as native format
[19:48:26] [PASSED] remove duplicates
[19:48:26] [PASSED] convert alpha formats
[19:48:26] [PASSED] random formats
[19:48:26] ======== [PASSED] drm_test_sysfb_build_fourcc_list =========
[19:48:26] ============= [PASSED] drm_sysfb_modeset_test ==============
[19:48:26] ================== drm_fixp (2 subtests) ===================
[19:48:26] [PASSED] drm_test_int2fixp
[19:48:26] [PASSED] drm_test_sm2fixp
[19:48:26] ==================== [PASSED] drm_fixp =====================
[19:48:26] ============================================================
[19:48:26] Testing complete. Ran 667 tests: passed: 667
[19:48:26] Elapsed time: 27.328s total, 1.840s configuring, 25.071s building, 0.409s running

+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/gpu/drm/ttm/tests/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/gpu/drm/ttm/tests/.kunitconfig
[19:48:26] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[19:48:28] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[19:48:38] Starting KUnit Kernel (1/1)...
[19:48:38] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[19:48:38] ================= ttm_device (5 subtests) ==================
[19:48:38] [PASSED] ttm_device_init_basic
[19:48:38] [PASSED] ttm_device_init_multiple
[19:48:38] [PASSED] ttm_device_fini_basic
[19:48:38] [PASSED] ttm_device_init_no_vma_man
[19:48:38] ================== ttm_device_init_pools  ==================
[19:48:38] [PASSED] No DMA allocations, no DMA32 required
[19:48:38] [PASSED] DMA allocations, DMA32 required
[19:48:38] [PASSED] No DMA allocations, DMA32 required
[19:48:38] [PASSED] DMA allocations, no DMA32 required
[19:48:38] ============== [PASSED] ttm_device_init_pools ==============
[19:48:38] =================== [PASSED] ttm_device ====================
[19:48:38] ================== ttm_pool (8 subtests) ===================
[19:48:38] ================== ttm_pool_alloc_basic  ===================
[19:48:38] [PASSED] One page
[19:48:38] [PASSED] More than one page
[19:48:38] [PASSED] Above the allocation limit
[19:48:38] [PASSED] One page, with coherent DMA mappings enabled
[19:48:38] [PASSED] Above the allocation limit, with coherent DMA mappings enabled
[19:48:38] ============== [PASSED] ttm_pool_alloc_basic ===============
[19:48:38] ============== ttm_pool_alloc_basic_dma_addr  ==============
[19:48:38] [PASSED] One page
[19:48:38] [PASSED] More than one page
[19:48:38] [PASSED] Above the allocation limit
[19:48:38] [PASSED] One page, with coherent DMA mappings enabled
[19:48:38] [PASSED] Above the allocation limit, with coherent DMA mappings enabled
[19:48:38] ========== [PASSED] ttm_pool_alloc_basic_dma_addr ==========
[19:48:38] [PASSED] ttm_pool_alloc_order_caching_match
[19:48:38] [PASSED] ttm_pool_alloc_caching_mismatch
[19:48:38] [PASSED] ttm_pool_alloc_order_mismatch
[19:48:38] [PASSED] ttm_pool_free_dma_alloc
[19:48:38] [PASSED] ttm_pool_free_no_dma_alloc
[19:48:38] [PASSED] ttm_pool_fini_basic
[19:48:38] ==================== [PASSED] ttm_pool =====================
[19:48:38] ================ ttm_resource (8 subtests) =================
[19:48:38] ================= ttm_resource_init_basic  =================
[19:48:38] [PASSED] Init resource in TTM_PL_SYSTEM
[19:48:38] [PASSED] Init resource in TTM_PL_VRAM
[19:48:38] [PASSED] Init resource in a private placement
[19:48:38] [PASSED] Init resource in TTM_PL_SYSTEM, set placement flags
[19:48:38] ============= [PASSED] ttm_resource_init_basic =============
[19:48:38] [PASSED] ttm_resource_init_pinned
[19:48:38] [PASSED] ttm_resource_fini_basic
[19:48:38] [PASSED] ttm_resource_manager_init_basic
[19:48:38] [PASSED] ttm_resource_manager_usage_basic
[19:48:38] [PASSED] ttm_resource_manager_set_used_basic
[19:48:38] [PASSED] ttm_sys_man_alloc_basic
[19:48:38] [PASSED] ttm_sys_man_free_basic
[19:48:38] ================== [PASSED] ttm_resource ===================
[19:48:38] =================== ttm_tt (15 subtests) ===================
[19:48:38] ==================== ttm_tt_init_basic  ====================
[19:48:38] [PASSED] Page-aligned size
[19:48:38] [PASSED] Extra pages requested
[19:48:38] ================ [PASSED] ttm_tt_init_basic ================
[19:48:38] [PASSED] ttm_tt_init_misaligned
[19:48:38] [PASSED] ttm_tt_fini_basic
[19:48:38] [PASSED] ttm_tt_fini_sg
[19:48:38] [PASSED] ttm_tt_fini_shmem
[19:48:38] [PASSED] ttm_tt_create_basic
[19:48:38] [PASSED] ttm_tt_create_invalid_bo_type
[19:48:38] [PASSED] ttm_tt_create_ttm_exists
[19:48:38] [PASSED] ttm_tt_create_failed
[19:48:38] [PASSED] ttm_tt_destroy_basic
[19:48:38] [PASSED] ttm_tt_populate_null_ttm
[19:48:38] [PASSED] ttm_tt_populate_populated_ttm
[19:48:38] [PASSED] ttm_tt_unpopulate_basic
[19:48:38] [PASSED] ttm_tt_unpopulate_empty_ttm
[19:48:38] [PASSED] ttm_tt_swapin_basic
[19:48:38] ===================== [PASSED] ttm_tt ======================
[19:48:38] =================== ttm_bo (14 subtests) ===================
[19:48:38] =========== ttm_bo_reserve_optimistic_no_ticket  ===========
[19:48:38] [PASSED] Cannot be interrupted and sleeps
[19:48:38] [PASSED] Cannot be interrupted, locks straight away
[19:48:38] [PASSED] Can be interrupted, sleeps
[19:48:38] ======= [PASSED] ttm_bo_reserve_optimistic_no_ticket =======
[19:48:38] [PASSED] ttm_bo_reserve_locked_no_sleep
[19:48:38] [PASSED] ttm_bo_reserve_no_wait_ticket
[19:48:38] [PASSED] ttm_bo_reserve_double_resv
[19:48:38] [PASSED] ttm_bo_reserve_interrupted
[19:48:38] [PASSED] ttm_bo_reserve_deadlock
[19:48:38] [PASSED] ttm_bo_unreserve_basic
[19:48:38] [PASSED] ttm_bo_unreserve_pinned
[19:48:38] [PASSED] ttm_bo_unreserve_bulk
[19:48:38] [PASSED] ttm_bo_fini_basic
[19:48:38] [PASSED] ttm_bo_fini_shared_resv
[19:48:38] [PASSED] ttm_bo_pin_basic
[19:48:38] [PASSED] ttm_bo_pin_unpin_resource
[19:48:38] [PASSED] ttm_bo_multiple_pin_one_unpin
[19:48:38] ===================== [PASSED] ttm_bo ======================
[19:48:38] ============== ttm_bo_validate (22 subtests) ===============
[19:48:38] ============== ttm_bo_init_reserved_sys_man  ===============
[19:48:38] [PASSED] Buffer object for userspace
[19:48:38] [PASSED] Kernel buffer object
[19:48:38] [PASSED] Shared buffer object
[19:48:38] ========== [PASSED] ttm_bo_init_reserved_sys_man ===========
[19:48:38] ============== ttm_bo_init_reserved_mock_man  ==============
[19:48:38] [PASSED] Buffer object for userspace
[19:48:38] [PASSED] Kernel buffer object
[19:48:38] [PASSED] Shared buffer object
[19:48:38] ========== [PASSED] ttm_bo_init_reserved_mock_man ==========
[19:48:38] [PASSED] ttm_bo_init_reserved_resv
[19:48:38] ================== ttm_bo_validate_basic  ==================
[19:48:38] [PASSED] Buffer object for userspace
[19:48:38] [PASSED] Kernel buffer object
[19:48:38] [PASSED] Shared buffer object
[19:48:38] ============== [PASSED] ttm_bo_validate_basic ==============
[19:48:38] [PASSED] ttm_bo_validate_invalid_placement
[19:48:38] ============= ttm_bo_validate_same_placement  ==============
[19:48:38] [PASSED] System manager
[19:48:38] [PASSED] VRAM manager
[19:48:38] ========= [PASSED] ttm_bo_validate_same_placement ==========
[19:48:38] [PASSED] ttm_bo_validate_failed_alloc
[19:48:38] [PASSED] ttm_bo_validate_pinned
[19:48:38] [PASSED] ttm_bo_validate_busy_placement
[19:48:38] ================ ttm_bo_validate_multihop  =================
[19:48:38] [PASSED] Buffer object for userspace
[19:48:38] [PASSED] Kernel buffer object
[19:48:38] [PASSED] Shared buffer object
[19:48:38] ============ [PASSED] ttm_bo_validate_multihop =============
[19:48:38] ========== ttm_bo_validate_no_placement_signaled  ==========
[19:48:38] [PASSED] Buffer object in system domain, no page vector
[19:48:38] [PASSED] Buffer object in system domain with an existing page vector
[19:48:38] ====== [PASSED] ttm_bo_validate_no_placement_signaled ======
[19:48:38] ======== ttm_bo_validate_no_placement_not_signaled  ========
[19:48:38] [PASSED] Buffer object for userspace
[19:48:38] [PASSED] Kernel buffer object
[19:48:38] [PASSED] Shared buffer object
[19:48:38] ==== [PASSED] ttm_bo_validate_no_placement_not_signaled ====
[19:48:38] [PASSED] ttm_bo_validate_move_fence_signaled
[19:48:38] ========= ttm_bo_validate_move_fence_not_signaled  =========
[19:48:38] [PASSED] Waits for GPU
[19:48:38] [PASSED] Tries to lock straight away
[19:48:38] ===== [PASSED] ttm_bo_validate_move_fence_not_signaled =====
[19:48:38] [PASSED] ttm_bo_validate_swapout
[19:48:38] [PASSED] ttm_bo_validate_happy_evict
[19:48:38] [PASSED] ttm_bo_validate_all_pinned_evict
[19:48:38] [PASSED] ttm_bo_validate_allowed_only_evict
[19:48:38] [PASSED] ttm_bo_validate_deleted_evict
[19:48:38] [PASSED] ttm_bo_validate_busy_domain_evict
[19:48:38] [PASSED] ttm_bo_validate_evict_gutting
[19:48:38] [PASSED] ttm_bo_validate_recrusive_evict
[19:48:38] ================= [PASSED] ttm_bo_validate =================
[19:48:38] ============================================================
[19:48:38] Testing complete. Ran 102 tests: passed: 102
[19:48:38] Elapsed time: 12.222s total, 1.878s configuring, 10.129s building, 0.169s running

+ for kcfg in "${kunitconfigs[@]}"
+ [[ ! -f /kernel/drivers/dma-buf/.kunitconfig ]]
+ /kernel/tools/testing/kunit/kunit.py run --kunitconfig /kernel/drivers/dma-buf/.kunitconfig
[19:48:38] Configuring KUnit Kernel ...
Regenerating .config ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
[19:48:40] Building KUnit Kernel ...
Populating config with:
$ make ARCH=um O=.kunit olddefconfig
Building with:
$ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=48
[19:48:49] Starting KUnit Kernel (1/1)...
[19:48:49] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[19:48:49] =============== dma-buf-fence (12 subtests) ================
[19:48:49] [PASSED] test_sanitycheck
[19:48:49] [PASSED] test_signaling
[19:48:49] [PASSED] test_add_callback
[19:48:49] [PASSED] test_late_add_callback
[19:48:49] [PASSED] test_rm_callback
[19:48:49] [PASSED] test_late_rm_callback
[19:48:49] [PASSED] test_status
[19:48:49] [PASSED] test_error
[19:48:49] [PASSED] test_wait
[19:48:49] [PASSED] test_wait_timeout
[19:48:49] [PASSED] test_stub
[19:48:49] [SKIPPED] test_race_signal_callback (requires at least 2 CPUs)
[19:48:49] ================== [PASSED] dma-buf-fence ==================
[19:48:49] ============ dma-buf-fence-chain (11 subtests) =============
[19:48:49] [PASSED] test_sanitycheck
[19:48:49] [PASSED] test_find_seqno
[19:48:49] [PASSED] test_find_signaled
[19:48:49] [PASSED] test_find_out_of_order
[19:48:54] [PASSED] test_find_gap
[19:48:54] [PASSED] test_find_race
[19:48:54] [PASSED] test_signal_forward
[19:48:54] [PASSED] test_signal_backward
[19:48:54] [PASSED] test_wait_forward
[19:48:54] [PASSED] test_wait_backward
[19:48:54] [PASSED] test_wait_random
[19:48:54] =============== [PASSED] dma-buf-fence-chain ===============
[19:48:54] ============ dma-buf-fence-unwrap (11 subtests) ============
[19:48:54] [PASSED] test_sanitycheck
[19:48:54] [PASSED] test_unwrap_array
[19:48:54] [PASSED] test_unwrap_chain
[19:48:54] [PASSED] test_unwrap_chain_array
[19:48:54] [PASSED] test_unwrap_merge
[19:48:54] [PASSED] test_unwrap_merge_duplicate
[19:48:54] [PASSED] test_unwrap_merge_seqno
[19:48:54] [PASSED] test_unwrap_merge_order
[19:48:54] [PASSED] test_unwrap_merge_complex
[19:48:54] [PASSED] test_unwrap_merge_complex_seqno
[19:48:54] [PASSED] test_dedup_empty
[19:48:54] ============== [PASSED] dma-buf-fence-unwrap ===============
[19:48:54] ================ dma-buf-resv (5 subtests) =================
[19:48:54] [PASSED] test_sanitycheck
[19:48:54] ===================== test_signaling  ======================
[19:48:54] [PASSED] kernel
[19:48:54] [PASSED] write
[19:48:54] [PASSED] read
[19:48:54] [PASSED] bookkeep
[19:48:54] ================= [PASSED] test_signaling ==================
[19:48:54] ====================== test_for_each  ======================
[19:48:54] [PASSED] kernel
[19:48:54] [PASSED] write
[19:48:54] [PASSED] read
[19:48:54] [PASSED] bookkeep
[19:48:54] ================== [PASSED] test_for_each ==================
[19:48:54] ================= test_for_each_unlocked  ==================
[19:48:54] [PASSED] kernel
[19:48:54] [PASSED] write
[19:48:54] [PASSED] read
[19:48:54] [PASSED] bookkeep
[19:48:54] ============= [PASSED] test_for_each_unlocked ==============
[19:48:54] ===================== test_get_fences  =====================
[19:48:54] [PASSED] kernel
[19:48:54] [PASSED] write
[19:48:54] [PASSED] read
[19:48:54] [PASSED] bookkeep
[19:48:54] ================= [PASSED] test_get_fences =================
[19:48:54] ================== [PASSED] dma-buf-resv ===================
[19:48:54] ============================================================
[19:48:54] Testing complete. Ran 51 tests: passed: 50, skipped: 1
[19:48:54] Elapsed time: 15.817s total, 1.853s configuring, 8.692s building, 5.265s running

+ cleanup
++ stat -c %u:%g /kernel
+ chown -R 1003:1003 /kernel



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

* ✗ Xe.CI.BAT: failure for Add fan control support
  2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
                   ` (10 preceding siblings ...)
  2026-10-15 19:48 ` ✓ CI.KUnit: success " Patchwork
@ 2026-10-15 21:01 ` Patchwork
  2026-10-16  7:56 ` ✗ Xe.CI.FULL: " Patchwork
  12 siblings, 0 replies; 26+ messages in thread
From: Patchwork @ 2026-10-15 21:01 UTC (permalink / raw)
  To: Karthik Poosa; +Cc: intel-xe

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

== Series Details ==

Series: Add fan control support
URL   : https://patchwork.freedesktop.org/series/176241/
State : failure

== Summary ==

CI Bug Log - changes from xe-5955-551605da81c33c1a2352b6a6116360609798f171_BAT -> xe-pw-176241v1_BAT
====================================================

Summary
-------

  **FAILURE**

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

  

Participating hosts (15 -> 15)
------------------------------

  No changes in participating hosts

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

  Here are the unknown changes that may have been introduced in xe-pw-176241v1_BAT:

### IGT changes ###

#### Possible regressions ####

  * igt@kms_pipe_crc_basic@read-crc-frame-sequence@pipe-d-hdmi-a-3:
    - bat-bmg-1:          [PASS][1] -> [DMESG-WARN][2] +17 other tests dmesg-warn
   [1]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/bat-bmg-1/igt@kms_pipe_crc_basic@read-crc-frame-sequence@pipe-d-hdmi-a-3.html
   [2]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/bat-bmg-1/igt@kms_pipe_crc_basic@read-crc-frame-sequence@pipe-d-hdmi-a-3.html

  * igt@xe_evict@evict-small:
    - bat-bmg-2:          [PASS][3] -> [DMESG-WARN][4] +9 other tests dmesg-warn
   [3]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/bat-bmg-2/igt@xe_evict@evict-small.html
   [4]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/bat-bmg-2/igt@xe_evict@evict-small.html

  * igt@xe_exec_basic@multigpu-many-execqueues-many-vm-null-defer-mmap:
    - bat-bmg-3:          [PASS][5] -> [DMESG-WARN][6] +1 other test dmesg-warn
   [5]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/bat-bmg-3/igt@xe_exec_basic@multigpu-many-execqueues-many-vm-null-defer-mmap.html
   [6]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/bat-bmg-3/igt@xe_exec_basic@multigpu-many-execqueues-many-vm-null-defer-mmap.html

  


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

  * IGT: IGT_9149 -> IGT_9150
  * Linux: xe-5955-551605da81c33c1a2352b6a6116360609798f171 -> xe-pw-176241v1

  IGT_9149: 157f243d73fb8c010db8c884db81ca2e558b4ab2 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  IGT_9150: 18811c476bfde62ffbb4c0af55cd6f57e36e0dca @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  xe-5955-551605da81c33c1a2352b6a6116360609798f171: 551605da81c33c1a2352b6a6116360609798f171
  xe-pw-176241v1: 176241v1

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/index.html

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

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

* ✗ Xe.CI.FULL: failure for Add fan control support
  2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
                   ` (11 preceding siblings ...)
  2026-10-15 21:01 ` ✗ Xe.CI.BAT: failure " Patchwork
@ 2026-10-16  7:56 ` Patchwork
  12 siblings, 0 replies; 26+ messages in thread
From: Patchwork @ 2026-10-16  7:56 UTC (permalink / raw)
  To: Karthik Poosa; +Cc: intel-xe

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

== Series Details ==

Series: Add fan control support
URL   : https://patchwork.freedesktop.org/series/176241/
State : failure

== Summary ==

CI Bug Log - changes from xe-5955-551605da81c33c1a2352b6a6116360609798f171_FULL -> xe-pw-176241v1_FULL
====================================================

Summary
-------

  **FAILURE**

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

  

Participating hosts (3 -> 3)
------------------------------

  No changes in participating hosts

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

  Here are the unknown changes that may have been introduced in xe-pw-176241v1_FULL:

### IGT changes ###

#### Possible regressions ####

  * igt@intel_hwmon@hwmon-write:
    - shard-bmg:          [PASS][1] -> [DMESG-FAIL][2] +1 other test dmesg-fail
   [1]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-8/igt@intel_hwmon@hwmon-write.html
   [2]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-5/igt@intel_hwmon@hwmon-write.html

  * igt@kms_content_protection@legacy:
    - shard-bmg:          NOTRUN -> [DMESG-FAIL][3] +3 other tests dmesg-fail
   [3]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-6/igt@kms_content_protection@legacy.html

  * igt@kms_flip@2x-nonexisting-fb:
    - shard-bmg:          [PASS][4] -> [DMESG-WARN][5] +740 other tests dmesg-warn
   [4]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-9/igt@kms_flip@2x-nonexisting-fb.html
   [5]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-10/igt@kms_flip@2x-nonexisting-fb.html

  * igt@kms_plane_lowres@tiling-none@pipe-b-hdmi-a-3:
    - shard-bmg:          NOTRUN -> [DMESG-WARN][6] +134 other tests dmesg-warn
   [6]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@kms_plane_lowres@tiling-none@pipe-b-hdmi-a-3.html

  * igt@kms_setmode@basic-no-cpu-idle@pipe-a-edp-1:
    - shard-ptl:          [PASS][7] -> [FAIL][8] +2 other tests fail
   [7]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-ptl-3/igt@kms_setmode@basic-no-cpu-idle@pipe-a-edp-1.html
   [8]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-8/igt@kms_setmode@basic-no-cpu-idle@pipe-a-edp-1.html

  
#### Warnings ####

  * igt@kms_content_protection@atomic-dpms-hdcp14:
    - shard-bmg:          [FAIL][9] ([Intel XE#3304] / [Intel XE#7374]) -> [DMESG-FAIL][10]
   [9]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-7/igt@kms_content_protection@atomic-dpms-hdcp14.html
   [10]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-10/igt@kms_content_protection@atomic-dpms-hdcp14.html

  * igt@kms_content_protection@atomic-hdcp14:
    - shard-bmg:          [FAIL][11] ([Intel XE#1178] / [Intel XE#3304] / [Intel XE#7374]) -> [DMESG-FAIL][12] +12 other tests dmesg-fail
   [11]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-9/igt@kms_content_protection@atomic-hdcp14.html
   [12]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-1/igt@kms_content_protection@atomic-hdcp14.html

  * igt@kms_content_protection@uevent-hdcp14:
    - shard-bmg:          [FAIL][13] ([Intel XE#6707] / [Intel XE#7439]) -> [DMESG-FAIL][14] +3 other tests dmesg-fail
   [13]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-6/igt@kms_content_protection@uevent-hdcp14.html
   [14]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-1/igt@kms_content_protection@uevent-hdcp14.html

  * igt@kms_cursor_legacy@flip-vs-cursor-atomic-transitions:
    - shard-bmg:          [FAIL][15] ([Intel XE#7809]) -> [DMESG-WARN][16]
   [15]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-8/igt@kms_cursor_legacy@flip-vs-cursor-atomic-transitions.html
   [16]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-10/igt@kms_cursor_legacy@flip-vs-cursor-atomic-transitions.html

  * igt@kms_hdmi_audio_bw@suspend-disk-audio-recovery:
    - shard-bmg:          [FAIL][17] ([Intel XE#9319] / [Intel XE#9346]) -> [DMESG-FAIL][18]
   [17]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-10/igt@kms_hdmi_audio_bw@suspend-disk-audio-recovery.html
   [18]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-1/igt@kms_hdmi_audio_bw@suspend-disk-audio-recovery.html

  * igt@xe_exec_threads@threads-hang-fd-userptr-invalidate-race:
    - shard-bmg:          [FAIL][19] ([Intel XE#9096]) -> [DMESG-WARN][20]
   [19]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-1/igt@xe_exec_threads@threads-hang-fd-userptr-invalidate-race.html
   [20]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@xe_exec_threads@threads-hang-fd-userptr-invalidate-race.html

  * igt@xe_pat@pat-sw-hw-suspend:
    - shard-bmg:          [FAIL][21] ([Intel XE#7695]) -> [DMESG-FAIL][22]
   [21]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-6/igt@xe_pat@pat-sw-hw-suspend.html
   [22]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-2/igt@xe_pat@pat-sw-hw-suspend.html

  
New tests
---------

  New tests have been introduced between xe-5955-551605da81c33c1a2352b6a6116360609798f171_FULL and xe-pw-176241v1_FULL:

### New IGT tests (2) ###

  * igt@kms_vblank:
    - Statuses :
    - Exec time: [None] s

  * igt@xe_oa@buffer-size@oag-0-2m:
    - Statuses : 1 pass(s)
    - Exec time: [0.19] s

  

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

  Here are the changes found in xe-pw-176241v1_FULL that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@kms_async_flips@alternate-sync-async-flip:
    - shard-bmg:          [PASS][23] -> [DMESG-WARN][24] ([Intel XE#9428]) +1 other test dmesg-warn
   [23]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-8/igt@kms_async_flips@alternate-sync-async-flip.html
   [24]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@kms_async_flips@alternate-sync-async-flip.html

  * igt@kms_big_fb@4-tiled-16bpp-rotate-270:
    - shard-ptl:          NOTRUN -> [SKIP][25] ([Intel XE#5901]) +1 other test skip
   [25]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-2/igt@kms_big_fb@4-tiled-16bpp-rotate-270.html

  * igt@kms_big_fb@4-tiled-64bpp-rotate-90:
    - shard-bmg:          NOTRUN -> [SKIP][26] ([Intel XE#2327]) +1 other test skip
   [26]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-9/igt@kms_big_fb@4-tiled-64bpp-rotate-90.html

  * igt@kms_big_fb@linear-max-hw-stride-32bpp-rotate-0-hflip:
    - shard-bmg:          NOTRUN -> [SKIP][27] ([Intel XE#7059] / [Intel XE#7085]) +1 other test skip
   [27]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-6/igt@kms_big_fb@linear-max-hw-stride-32bpp-rotate-0-hflip.html

  * igt@kms_big_fb@linear-max-hw-stride-32bpp-rotate-180-hflip:
    - shard-ptl:          NOTRUN -> [SKIP][28] ([Intel XE#7085]) +2 other tests skip
   [28]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-5/igt@kms_big_fb@linear-max-hw-stride-32bpp-rotate-180-hflip.html

  * igt@kms_big_fb@x-tiled-max-hw-stride-32bpp-rotate-0-hflip-async-flip:
    - shard-ptl:          NOTRUN -> [SKIP][29] ([Intel XE#5808]) +9 other tests skip
   [29]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-3/igt@kms_big_fb@x-tiled-max-hw-stride-32bpp-rotate-0-hflip-async-flip.html

  * igt@kms_big_fb@y-tiled-addfb-size-overflow:
    - shard-bmg:          NOTRUN -> [SKIP][30] ([Intel XE#610] / [Intel XE#7387])
   [30]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-2/igt@kms_big_fb@y-tiled-addfb-size-overflow.html

  * igt@kms_big_fb@yf-tiled-32bpp-rotate-0:
    - shard-bmg:          NOTRUN -> [SKIP][31] ([Intel XE#1124]) +6 other tests skip
   [31]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-7/igt@kms_big_fb@yf-tiled-32bpp-rotate-0.html

  * igt@kms_bw@connected-linear-tiling-3-displays-target-2160x1440p:
    - shard-ptl:          NOTRUN -> [SKIP][32] ([Intel XE#7679]) +1 other test skip
   [32]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-6/igt@kms_bw@connected-linear-tiling-3-displays-target-2160x1440p.html

  * igt@kms_bw@connected-linear-tiling-3-displays-target-3840x2160p:
    - shard-bmg:          NOTRUN -> [SKIP][33] ([Intel XE#7679])
   [33]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-3/igt@kms_bw@connected-linear-tiling-3-displays-target-3840x2160p.html

  * igt@kms_bw@linear-tiling-1-displays-target-3840x2160p:
    - shard-bmg:          [PASS][34] -> [SKIP][35] ([Intel XE#367])
   [34]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-7/igt@kms_bw@linear-tiling-1-displays-target-3840x2160p.html
   [35]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-5/igt@kms_bw@linear-tiling-1-displays-target-3840x2160p.html

  * igt@kms_bw@linear-tiling-3-displays-target-2160x1440p:
    - shard-bmg:          NOTRUN -> [SKIP][36] ([Intel XE#367])
   [36]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-9/igt@kms_bw@linear-tiling-3-displays-target-2160x1440p.html

  * igt@kms_bw@linear-tiling-4-displays-target-1920x1080p:
    - shard-ptl:          NOTRUN -> [SKIP][37] ([Intel XE#367]) +1 other test skip
   [37]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-2/igt@kms_bw@linear-tiling-4-displays-target-1920x1080p.html

  * igt@kms_ccs@crc-primary-basic-4-tiled-dg2-rc-ccs:
    - shard-bmg:          NOTRUN -> [SKIP][38] ([Intel XE#2887]) +6 other tests skip
   [38]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-6/igt@kms_ccs@crc-primary-basic-4-tiled-dg2-rc-ccs.html

  * igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-d-dp-2:
    - shard-bmg:          NOTRUN -> [INCOMPLETE][39] ([Intel XE#7084] / [Intel XE#8150])
   [39]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-6/igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-d-dp-2.html

  * igt@kms_ccs@crc-primary-suspend-4-tiled-lnl-ccs:
    - shard-ptl:          [PASS][40] -> [ABORT][41] ([Intel XE#7084] / [Intel XE#9362] / [Intel XE#9364])
   [40]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-ptl-4/igt@kms_ccs@crc-primary-suspend-4-tiled-lnl-ccs.html
   [41]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-7/igt@kms_ccs@crc-primary-suspend-4-tiled-lnl-ccs.html

  * igt@kms_ccs@crc-primary-suspend-4-tiled-lnl-ccs@pipe-a-edp-1:
    - shard-ptl:          [PASS][42] -> [ABORT][43] ([Intel XE#7084] / [Intel XE#9362])
   [42]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-ptl-4/igt@kms_ccs@crc-primary-suspend-4-tiled-lnl-ccs@pipe-a-edp-1.html
   [43]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-7/igt@kms_ccs@crc-primary-suspend-4-tiled-lnl-ccs@pipe-a-edp-1.html

  * igt@kms_ccs@crc-primary-suspend-4-tiled-lnl-ccs@pipe-c-edp-1:
    - shard-ptl:          [PASS][44] -> [DMESG-WARN][45] ([Intel XE#9389])
   [44]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-ptl-4/igt@kms_ccs@crc-primary-suspend-4-tiled-lnl-ccs@pipe-c-edp-1.html
   [45]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-7/igt@kms_ccs@crc-primary-suspend-4-tiled-lnl-ccs@pipe-c-edp-1.html

  * igt@kms_ccs@crc-sprite-planes-basic-4-tiled-lnl-ccs@pipe-d-hdmi-a-3:
    - shard-bmg:          NOTRUN -> [SKIP][46] ([Intel XE#2652]) +21 other tests skip
   [46]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-9/igt@kms_ccs@crc-sprite-planes-basic-4-tiled-lnl-ccs@pipe-d-hdmi-a-3.html

  * igt@kms_ccs@missing-ccs-buffer-y-tiled-gen12-rc-ccs-cc:
    - shard-ptl:          NOTRUN -> [SKIP][47] ([Intel XE#5822]) +6 other tests skip
   [47]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-1/igt@kms_ccs@missing-ccs-buffer-y-tiled-gen12-rc-ccs-cc.html

  * igt@kms_chamelium_color@degamma:
    - shard-bmg:          NOTRUN -> [SKIP][48] ([Intel XE#2325] / [Intel XE#7358]) +1 other test skip
   [48]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-3/igt@kms_chamelium_color@degamma.html
    - shard-ptl:          NOTRUN -> [SKIP][49] ([Intel XE#5824])
   [49]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-8/igt@kms_chamelium_color@degamma.html

  * igt@kms_chamelium_color_pipeline@plane-ctm3x4:
    - shard-ptl:          NOTRUN -> [SKIP][50] ([Intel XE#8391]) +4 other tests skip
   [50]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-1/igt@kms_chamelium_color_pipeline@plane-ctm3x4.html
    - shard-lnl:          NOTRUN -> [SKIP][51] ([Intel XE#7358])
   [51]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-3/igt@kms_chamelium_color_pipeline@plane-ctm3x4.html

  * igt@kms_chamelium_color_pipeline@plane-fixed-matrix-yuv-rgb-bt709-lim:
    - shard-bmg:          NOTRUN -> [SKIP][52] ([Intel XE#7358]) +1 other test skip
   [52]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-5/igt@kms_chamelium_color_pipeline@plane-fixed-matrix-yuv-rgb-bt709-lim.html

  * igt@kms_chamelium_frames@dp-crc-single:
    - shard-bmg:          NOTRUN -> [SKIP][53] ([Intel XE#2252]) +3 other tests skip
   [53]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@kms_chamelium_frames@dp-crc-single.html

  * igt@kms_chamelium_hpd@hdmi-hpd-with-enabled-mode:
    - shard-ptl:          NOTRUN -> [SKIP][54] ([Intel XE#2252]) +4 other tests skip
   [54]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-4/igt@kms_chamelium_hpd@hdmi-hpd-with-enabled-mode.html

  * igt@kms_content_protection@dp-mst-lic-type-0:
    - shard-ptl:          NOTRUN -> [SKIP][55] ([Intel XE#5832] / [Intel XE#6974])
   [55]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-3/igt@kms_content_protection@dp-mst-lic-type-0.html

  * igt@kms_content_protection@dp-mst-type-0-hdcp14:
    - shard-ptl:          NOTRUN -> [SKIP][56] ([Intel XE#6974])
   [56]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-6/igt@kms_content_protection@dp-mst-type-0-hdcp14.html

  * igt@kms_content_protection@dp-mst-type-1:
    - shard-bmg:          NOTRUN -> [SKIP][57] ([Intel XE#2390] / [Intel XE#6974]) +1 other test skip
   [57]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-9/igt@kms_content_protection@dp-mst-type-1.html

  * igt@kms_content_protection@legacy-hdcp14:
    - shard-ptl:          NOTRUN -> [SKIP][58] ([Intel XE#7642]) +1 other test skip
   [58]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-2/igt@kms_content_protection@legacy-hdcp14.html

  * igt@kms_cursor_crc@cursor-offscreen-512x512:
    - shard-ptl:          NOTRUN -> [SKIP][59] ([Intel XE#5846]) +1 other test skip
   [59]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-3/igt@kms_cursor_crc@cursor-offscreen-512x512.html

  * igt@kms_cursor_crc@cursor-onscreen-64x21:
    - shard-bmg:          NOTRUN -> [SKIP][60] ([Intel XE#2320]) +1 other test skip
   [60]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-2/igt@kms_cursor_crc@cursor-onscreen-64x21.html

  * igt@kms_cursor_crc@cursor-sliding-128x42:
    - shard-ptl:          NOTRUN -> [SKIP][61] ([Intel XE#5900]) +2 other tests skip
   [61]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-6/igt@kms_cursor_crc@cursor-sliding-128x42.html

  * igt@kms_cursor_crc@cursor-sliding-512x170:
    - shard-bmg:          NOTRUN -> [SKIP][62] ([Intel XE#2321] / [Intel XE#7355])
   [62]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-10/igt@kms_cursor_crc@cursor-sliding-512x170.html

  * igt@kms_cursor_crc@cursor-suspend:
    - shard-ptl:          [PASS][63] -> [ABORT][64] ([Intel XE#9375]) +1 other test abort
   [63]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-ptl-8/igt@kms_cursor_crc@cursor-suspend.html
   [64]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-1/igt@kms_cursor_crc@cursor-suspend.html

  * igt@kms_cursor_legacy@2x-nonblocking-modeset-vs-cursor-atomic:
    - shard-ptl:          NOTRUN -> [SKIP][65] ([Intel XE#5962]) +3 other tests skip
   [65]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-1/igt@kms_cursor_legacy@2x-nonblocking-modeset-vs-cursor-atomic.html

  * igt@kms_cursor_legacy@cursor-vs-flip-toggle:
    - shard-bmg:          [PASS][66] -> [DMESG-WARN][67] ([Intel XE#7935])
   [66]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-3/igt@kms_cursor_legacy@cursor-vs-flip-toggle.html
   [67]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@kms_cursor_legacy@cursor-vs-flip-toggle.html

  * igt@kms_cursor_legacy@cursora-vs-flipa-atomic-transitions-varying-size:
    - shard-bmg:          NOTRUN -> [DMESG-WARN][68] ([Intel XE#7935] / [Intel XE#9522])
   [68]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-2/igt@kms_cursor_legacy@cursora-vs-flipa-atomic-transitions-varying-size.html

  * igt@kms_cursor_legacy@cursora-vs-flipb-atomic-transitions-varying-size:
    - shard-bmg:          [PASS][69] -> [DMESG-WARN][70] ([Intel XE#9221] / [Intel XE#9522])
   [69]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-7/igt@kms_cursor_legacy@cursora-vs-flipb-atomic-transitions-varying-size.html
   [70]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-3/igt@kms_cursor_legacy@cursora-vs-flipb-atomic-transitions-varying-size.html

  * igt@kms_cursor_legacy@cursorb-vs-flipa-atomic-transitions-varying-size:
    - shard-bmg:          [PASS][71] -> [DMESG-WARN][72] ([Intel XE#9522]) +5 other tests dmesg-warn
   [71]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-5/igt@kms_cursor_legacy@cursorb-vs-flipa-atomic-transitions-varying-size.html
   [72]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-8/igt@kms_cursor_legacy@cursorb-vs-flipa-atomic-transitions-varying-size.html

  * igt@kms_cursor_legacy@cursorb-vs-flipa-toggle:
    - shard-bmg:          NOTRUN -> [DMESG-WARN][73] ([Intel XE#9522])
   [73]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@kms_cursor_legacy@cursorb-vs-flipa-toggle.html

  * igt@kms_cursor_legacy@cursorb-vs-flipb-atomic-transitions:
    - shard-bmg:          [PASS][74] -> [DMESG-WARN][75] ([Intel XE#7935] / [Intel XE#9522])
   [74]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-5/igt@kms_cursor_legacy@cursorb-vs-flipb-atomic-transitions.html
   [75]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-2/igt@kms_cursor_legacy@cursorb-vs-flipb-atomic-transitions.html

  * igt@kms_cursor_legacy@short-busy-flip-before-cursor-atomic-transitions:
    - shard-bmg:          NOTRUN -> [SKIP][76] ([Intel XE#2286] / [Intel XE#6035])
   [76]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-8/igt@kms_cursor_legacy@short-busy-flip-before-cursor-atomic-transitions.html

  * igt@kms_dirtyfb@drrs-dirtyfb-ioctl:
    - shard-ptl:          NOTRUN -> [SKIP][77] ([Intel XE#5958])
   [77]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-3/igt@kms_dirtyfb@drrs-dirtyfb-ioctl.html

  * igt@kms_dirtyfb@psr-dirtyfb-ioctl:
    - shard-bmg:          NOTRUN -> [SKIP][78] ([Intel XE#1508])
   [78]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-2/igt@kms_dirtyfb@psr-dirtyfb-ioctl.html

  * igt@kms_dsc@dsc-with-bpc-formats:
    - shard-ptl:          NOTRUN -> [SKIP][79] ([Intel XE#5907]) +3 other tests skip
   [79]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-2/igt@kms_dsc@dsc-with-bpc-formats.html
    - shard-bmg:          NOTRUN -> [SKIP][80] ([Intel XE#8265]) +1 other test skip
   [80]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@kms_dsc@dsc-with-bpc-formats.html

  * igt@kms_fbc_dirty_rect@fbc-dirty-rectangle-different-formats:
    - shard-bmg:          NOTRUN -> [SKIP][81] ([Intel XE#4422] / [Intel XE#7442])
   [81]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-1/igt@kms_fbc_dirty_rect@fbc-dirty-rectangle-different-formats.html

  * igt@kms_fbcon_fbt@psr:
    - shard-bmg:          NOTRUN -> [SKIP][82] ([Intel XE#8680])
   [82]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@kms_fbcon_fbt@psr.html

  * igt@kms_feature_discovery@display-4x:
    - shard-bmg:          NOTRUN -> [SKIP][83] ([Intel XE#1138] / [Intel XE#7344])
   [83]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@kms_feature_discovery@display-4x.html
    - shard-ptl:          NOTRUN -> [SKIP][84] ([Intel XE#7344])
   [84]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-1/igt@kms_feature_discovery@display-4x.html

  * igt@kms_feature_discovery@hdr:
    - shard-ptl:          NOTRUN -> [SKIP][85] ([Intel XE#9287])
   [85]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-7/igt@kms_feature_discovery@hdr.html

  * igt@kms_flip@2x-flip-vs-suspend-interruptible:
    - shard-ptl:          NOTRUN -> [SKIP][86] ([Intel XE#2316]) +8 other tests skip
   [86]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-8/igt@kms_flip@2x-flip-vs-suspend-interruptible.html

  * igt@kms_flip@flip-vs-expired-vblank-interruptible@b-edp1:
    - shard-lnl:          [PASS][87] -> [FAIL][88] ([Intel XE#301])
   [87]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-lnl-5/igt@kms_flip@flip-vs-expired-vblank-interruptible@b-edp1.html
   [88]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-6/igt@kms_flip@flip-vs-expired-vblank-interruptible@b-edp1.html

  * igt@kms_flip@flip-vs-suspend-interruptible:
    - shard-bmg:          [PASS][89] -> [ABORT][90] ([Intel XE#9362]) +2 other tests abort
   [89]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-10/igt@kms_flip@flip-vs-suspend-interruptible.html
   [90]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-8/igt@kms_flip@flip-vs-suspend-interruptible.html

  * igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling:
    - shard-bmg:          NOTRUN -> [SKIP][91] ([Intel XE#7178] / [Intel XE#7351]) +2 other tests skip
   [91]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-2/igt@kms_flip_scaled_crc@flip-32bpp-ytile-to-64bpp-ytile-downscaling.html

  * igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-16bpp-4tile-downscaling:
    - shard-ptl:          NOTRUN -> [SKIP][92] ([Intel XE#5828]) +1 other test skip
   [92]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-2/igt@kms_flip_scaled_crc@flip-64bpp-4tile-to-16bpp-4tile-downscaling.html

  * igt@kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling:
    - shard-lnl:          NOTRUN -> [SKIP][93] ([Intel XE#7178] / [Intel XE#7351])
   [93]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-5/igt@kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytile-upscaling.html

  * igt@kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling:
    - shard-ptl:          NOTRUN -> [SKIP][94] ([Intel XE#7178]) +4 other tests skip
   [94]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-6/igt@kms_flip_scaled_crc@flip-64bpp-ytile-to-32bpp-ytilercccs-downscaling.html

  * igt@kms_frontbuffer_tracking@drrs-1p-rte:
    - shard-lnl:          NOTRUN -> [SKIP][95] ([Intel XE#6312] / [Intel XE#651])
   [95]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-1/igt@kms_frontbuffer_tracking@drrs-1p-rte.html

  * igt@kms_frontbuffer_tracking@drrshdr-1p-primscrn-cur-indfb-draw-mmap-wc:
    - shard-ptl:          NOTRUN -> [SKIP][96] ([Intel XE#6312]) +5 other tests skip
   [96]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-6/igt@kms_frontbuffer_tracking@drrshdr-1p-primscrn-cur-indfb-draw-mmap-wc.html

  * igt@kms_frontbuffer_tracking@drrshdr-slowdraw:
    - shard-bmg:          NOTRUN -> [SKIP][97] ([Intel XE#2311]) +31 other tests skip
   [97]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-10/igt@kms_frontbuffer_tracking@drrshdr-slowdraw.html

  * igt@kms_frontbuffer_tracking@fbc-1p-offscreen-pri-shrfb-draw-blt:
    - shard-bmg:          NOTRUN -> [SKIP][98] ([Intel XE#4141]) +10 other tests skip
   [98]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-3/igt@kms_frontbuffer_tracking@fbc-1p-offscreen-pri-shrfb-draw-blt.html

  * igt@kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-indfb-draw-blt:
    - shard-ptl:          NOTRUN -> [SKIP][99] ([Intel XE#5812]) +63 other tests skip
   [99]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-4/igt@kms_frontbuffer_tracking@fbc-2p-scndscrn-pri-indfb-draw-blt.html

  * igt@kms_frontbuffer_tracking@fbc-tiling-y:
    - shard-ptl:          NOTRUN -> [SKIP][100] ([Intel XE#5865] / [Intel XE#7399])
   [100]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-5/igt@kms_frontbuffer_tracking@fbc-tiling-y.html

  * igt@kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-spr-indfb-onoff:
    - shard-ptl:          NOTRUN -> [SKIP][101] ([Intel XE#5800] / [Intel XE#6312]) +12 other tests skip
   [101]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-5/igt@kms_frontbuffer_tracking@fbcdrrs-1p-primscrn-spr-indfb-onoff.html

  * igt@kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-cur-indfb-draw-render:
    - shard-lnl:          NOTRUN -> [SKIP][102] ([Intel XE#656] / [Intel XE#7905]) +3 other tests skip
   [102]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-2/igt@kms_frontbuffer_tracking@fbcdrrs-2p-primscrn-cur-indfb-draw-render.html

  * igt@kms_frontbuffer_tracking@fbcdrrshdr-2p-scndscrn-spr-indfb-draw-blt:
    - shard-lnl:          NOTRUN -> [SKIP][103] ([Intel XE#7905])
   [103]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-2/igt@kms_frontbuffer_tracking@fbcdrrshdr-2p-scndscrn-spr-indfb-draw-blt.html

  * igt@kms_frontbuffer_tracking@fbcdrrshdr-argb161616f-draw-render:
    - shard-bmg:          NOTRUN -> [SKIP][104] ([Intel XE#7061]) +3 other tests skip
   [104]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-10/igt@kms_frontbuffer_tracking@fbcdrrshdr-argb161616f-draw-render.html

  * igt@kms_frontbuffer_tracking@fbcdrrshdr-suspend:
    - shard-lnl:          NOTRUN -> [SKIP][105] ([Intel XE#6312])
   [105]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-6/igt@kms_frontbuffer_tracking@fbcdrrshdr-suspend.html

  * igt@kms_frontbuffer_tracking@fbchdr-1p-primscrn-cur-indfb-move:
    - shard-lnl:          NOTRUN -> [SKIP][106] ([Intel XE#7865])
   [106]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-2/igt@kms_frontbuffer_tracking@fbchdr-1p-primscrn-cur-indfb-move.html

  * igt@kms_frontbuffer_tracking@fbchdr-argb161616f-draw-mmap-wc:
    - shard-ptl:          NOTRUN -> [SKIP][107] ([Intel XE#7061]) +5 other tests skip
   [107]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-6/igt@kms_frontbuffer_tracking@fbchdr-argb161616f-draw-mmap-wc.html

  * igt@kms_frontbuffer_tracking@fbchdr-tiling-y:
    - shard-ptl:          NOTRUN -> [SKIP][108] ([Intel XE#7399])
   [108]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-2/igt@kms_frontbuffer_tracking@fbchdr-tiling-y.html

  * igt@kms_frontbuffer_tracking@fbcpsr-abgr161616f-draw-render:
    - shard-bmg:          NOTRUN -> [SKIP][109] ([Intel XE#7061] / [Intel XE#7356])
   [109]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-5/igt@kms_frontbuffer_tracking@fbcpsr-abgr161616f-draw-render.html

  * igt@kms_frontbuffer_tracking@fbcpsrhdr-1p-primscrn-cur-indfb-draw-mmap-wc:
    - shard-ptl:          NOTRUN -> [SKIP][110] ([Intel XE#7865]) +16 other tests skip
   [110]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-3/igt@kms_frontbuffer_tracking@fbcpsrhdr-1p-primscrn-cur-indfb-draw-mmap-wc.html

  * igt@kms_frontbuffer_tracking@fbcpsrhdr-tiling-y:
    - shard-bmg:          NOTRUN -> [SKIP][111] ([Intel XE#7399])
   [111]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@kms_frontbuffer_tracking@fbcpsrhdr-tiling-y.html

  * igt@kms_frontbuffer_tracking@psrhdr-2p-primscrn-pri-shrfb-draw-render:
    - shard-bmg:          NOTRUN -> [SKIP][112] ([Intel XE#2313]) +37 other tests skip
   [112]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-5/igt@kms_frontbuffer_tracking@psrhdr-2p-primscrn-pri-shrfb-draw-render.html

  * igt@kms_hdmi_audio_bw@suspend-mem-audio-recovery:
    - shard-ptl:          NOTRUN -> [SKIP][113] ([Intel XE#9312])
   [113]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-2/igt@kms_hdmi_audio_bw@suspend-mem-audio-recovery.html

  * igt@kms_hdr@bpc-switch-dpms:
    - shard-bmg:          [PASS][114] -> [DMESG-WARN][115] ([Intel XE#9474]) +4 other tests dmesg-warn
   [114]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-5/igt@kms_hdr@bpc-switch-dpms.html
   [115]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-6/igt@kms_hdr@bpc-switch-dpms.html

  * igt@kms_hdr@bpc-switch-suspend:
    - shard-ptl:          [PASS][116] -> [ABORT][117] ([Intel XE#9362]) +9 other tests abort
   [116]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-ptl-8/igt@kms_hdr@bpc-switch-suspend.html
   [117]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-4/igt@kms_hdr@bpc-switch-suspend.html

  * igt@kms_hdr@static-toggle-dpms:
    - shard-bmg:          NOTRUN -> [DMESG-WARN][118] ([Intel XE#9474])
   [118]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-3/igt@kms_hdr@static-toggle-dpms.html

  * igt@kms_joiner@basic-big-joiner:
    - shard-ptl:          NOTRUN -> [SKIP][119] ([Intel XE#6901])
   [119]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-6/igt@kms_joiner@basic-big-joiner.html

  * igt@kms_plane@pixel-format-x-tiled-modifier:
    - shard-ptl:          NOTRUN -> [SKIP][120] ([Intel XE#7283]) +4 other tests skip
   [120]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-8/igt@kms_plane@pixel-format-x-tiled-modifier.html

  * igt@kms_plane@pixel-format-x-tiled-modifier@pipe-b-plane-5:
    - shard-bmg:          NOTRUN -> [SKIP][121] ([Intel XE#8303]) +1 other test skip
   [121]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-8/igt@kms_plane@pixel-format-x-tiled-modifier@pipe-b-plane-5.html

  * igt@kms_plane@pixel-format-y-tiled-modifier:
    - shard-bmg:          NOTRUN -> [SKIP][122] ([Intel XE#7283]) +3 other tests skip
   [122]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@kms_plane@pixel-format-y-tiled-modifier.html

  * igt@kms_plane_lowres@tiling-none@pipe-b-edp-1:
    - shard-ptl:          NOTRUN -> [SKIP][123] ([Intel XE#5844]) +4 other tests skip
   [123]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-2/igt@kms_plane_lowres@tiling-none@pipe-b-edp-1.html

  * igt@kms_plane_lowres@tiling-yf:
    - shard-ptl:          NOTRUN -> [SKIP][124] ([Intel XE#5946])
   [124]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-8/igt@kms_plane_lowres@tiling-yf.html

  * igt@kms_plane_scaling@2x-scaler-multi-pipe:
    - shard-ptl:          NOTRUN -> [SKIP][125] ([Intel XE#5879] / [Intel XE#7343])
   [125]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-3/igt@kms_plane_scaling@2x-scaler-multi-pipe.html

  * igt@kms_plane_scaling@planes-downscale-factor-0-5:
    - shard-lnl:          NOTRUN -> [SKIP][126] ([Intel XE#2763] / [Intel XE#6886]) +3 other tests skip
   [126]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-2/igt@kms_plane_scaling@planes-downscale-factor-0-5.html

  * igt@kms_plane_scaling@planes-downscale-factor-0-5-unity-scaling@pipe-d:
    - shard-ptl:          NOTRUN -> [SKIP][127] ([Intel XE#6886]) +9 other tests skip
   [127]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-5/igt@kms_plane_scaling@planes-downscale-factor-0-5-unity-scaling@pipe-d.html

  * igt@kms_plane_scaling@planes-downscale-factor-0-5@pipe-c:
    - shard-bmg:          NOTRUN -> [SKIP][128] ([Intel XE#2763] / [Intel XE#6886]) +4 other tests skip
   [128]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-5/igt@kms_plane_scaling@planes-downscale-factor-0-5@pipe-c.html

  * igt@kms_pm_backlight@brightness-with-dpms:
    - shard-bmg:          NOTRUN -> [SKIP][129] ([Intel XE#2938] / [Intel XE#7376] / [Intel XE#7760])
   [129]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-6/igt@kms_pm_backlight@brightness-with-dpms.html

  * igt@kms_pm_backlight@fade-with-suspend:
    - shard-bmg:          NOTRUN -> [SKIP][130] ([Intel XE#7376] / [Intel XE#7760] / [Intel XE#870])
   [130]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-8/igt@kms_pm_backlight@fade-with-suspend.html

  * igt@kms_pm_dc@dc3co-framedrop-check:
    - shard-ptl:          NOTRUN -> [SKIP][131] ([Intel XE#8395] / [Intel XE#8396]) +1 other test skip
   [131]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-5/igt@kms_pm_dc@dc3co-framedrop-check.html

  * igt@kms_pm_dc@dc3co-framedrop-check@psr2-xrgb8888:
    - shard-ptl:          NOTRUN -> [SKIP][132] ([Intel XE#8396]) +1 other test skip
   [132]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-5/igt@kms_pm_dc@dc3co-framedrop-check@psr2-xrgb8888.html

  * igt@kms_pm_dc@dc5-psr-suspend-resume:
    - shard-lnl:          [PASS][133] -> [FAIL][134] ([Intel XE#8399])
   [133]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-lnl-7/igt@kms_pm_dc@dc5-psr-suspend-resume.html
   [134]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-2/igt@kms_pm_dc@dc5-psr-suspend-resume.html

  * igt@kms_psr2_sf@fbc-psr2-cursor-plane-move-continuous-sf:
    - shard-bmg:          NOTRUN -> [SKIP][135] ([Intel XE#1489]) +4 other tests skip
   [135]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-1/igt@kms_psr2_sf@fbc-psr2-cursor-plane-move-continuous-sf.html

  * igt@kms_psr2_sf@fbc-psr2-cursor-plane-update-sf@pipe-b-edp-1:
    - shard-ptl:          NOTRUN -> [SKIP][136] ([Intel XE#5858] / [Intel XE#7304]) +3 other tests skip
   [136]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-4/igt@kms_psr2_sf@fbc-psr2-cursor-plane-update-sf@pipe-b-edp-1.html

  * igt@kms_psr2_sf@fbc-psr2-overlay-plane-move-continuous-exceed-sf@pipe-a-edp-1:
    - shard-ptl:          NOTRUN -> [SKIP][137] ([Intel XE#5858]) +1 other test skip
   [137]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-3/igt@kms_psr2_sf@fbc-psr2-overlay-plane-move-continuous-exceed-sf@pipe-a-edp-1.html

  * igt@kms_psr2_sf@pr-overlay-plane-update-continuous-sf:
    - shard-ptl:          NOTRUN -> [SKIP][138] ([Intel XE#7304]) +1 other test skip
   [138]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-8/igt@kms_psr2_sf@pr-overlay-plane-update-continuous-sf.html

  * igt@kms_psr@fbc-psr2-dpms:
    - shard-ptl:          NOTRUN -> [SKIP][139] ([Intel XE#1406] / [Intel XE#5835]) +3 other tests skip
   [139]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-6/igt@kms_psr@fbc-psr2-dpms.html

  * igt@kms_psr@fbc-psr2-sprite-render:
    - shard-bmg:          NOTRUN -> [SKIP][140] ([Intel XE#2234] / [Intel XE#2850]) +4 other tests skip
   [140]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-1/igt@kms_psr@fbc-psr2-sprite-render.html
    - shard-lnl:          NOTRUN -> [SKIP][141] ([Intel XE#1406] / [Intel XE#7345])
   [141]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-2/igt@kms_psr@fbc-psr2-sprite-render.html

  * igt@kms_psr@fbc-psr2-sprite-render@edp-1:
    - shard-lnl:          NOTRUN -> [SKIP][142] ([Intel XE#1406] / [Intel XE#4609] / [Intel XE#7345])
   [142]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-2/igt@kms_psr@fbc-psr2-sprite-render@edp-1.html

  * igt@kms_psr@pr-basic:
    - shard-ptl:          NOTRUN -> [SKIP][143] ([Intel XE#1406]) +2 other tests skip
   [143]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-4/igt@kms_psr@pr-basic.html

  * igt@kms_psr_stress_test@invalidate-primary-flip-overlay:
    - shard-bmg:          NOTRUN -> [SKIP][144] ([Intel XE#7795])
   [144]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@kms_psr_stress_test@invalidate-primary-flip-overlay.html

  * igt@kms_rotation_crc@bad-pixel-format:
    - shard-bmg:          NOTRUN -> [SKIP][145] ([Intel XE#3904] / [Intel XE#7342]) +1 other test skip
   [145]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-10/igt@kms_rotation_crc@bad-pixel-format.html

  * igt@kms_rotation_crc@primary-rotation-90:
    - shard-lnl:          NOTRUN -> [SKIP][146] ([Intel XE#3414] / [Intel XE#3904] / [Intel XE#7342])
   [146]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-6/igt@kms_rotation_crc@primary-rotation-90.html

  * igt@kms_rotation_crc@primary-y-tiled-reflect-x-180:
    - shard-bmg:          NOTRUN -> [SKIP][147] ([Intel XE#2330] / [Intel XE#5813]) +1 other test skip
   [147]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-1/igt@kms_rotation_crc@primary-y-tiled-reflect-x-180.html

  * igt@kms_rotation_crc@primary-y-tiled-reflect-x-90:
    - shard-ptl:          NOTRUN -> [SKIP][148] ([Intel XE#5821])
   [148]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-5/igt@kms_rotation_crc@primary-y-tiled-reflect-x-90.html

  * igt@kms_rotation_crc@primary-yf-tiled-reflect-x-0:
    - shard-ptl:          NOTRUN -> [SKIP][149] ([Intel XE#5813])
   [149]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-2/igt@kms_rotation_crc@primary-yf-tiled-reflect-x-0.html

  * igt@kms_setmode@basic-clone-single-crtc:
    - shard-ptl:          NOTRUN -> [SKIP][150] ([Intel XE#5910])
   [150]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-6/igt@kms_setmode@basic-clone-single-crtc.html

  * igt@kms_sharpness_filter@invalid-plane-with-filter:
    - shard-bmg:          NOTRUN -> [SKIP][151] ([Intel XE#6503]) +1 other test skip
   [151]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-8/igt@kms_sharpness_filter@invalid-plane-with-filter.html

  * igt@kms_tiled_display@basic-test-pattern-with-chamelium:
    - shard-bmg:          NOTRUN -> [SKIP][152] ([Intel XE#2509] / [Intel XE#7437])
   [152]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-10/igt@kms_tiled_display@basic-test-pattern-with-chamelium.html

  * igt@kms_vblank@ts-continuation-dpms-suspend@pipe-d-dp-2:
    - shard-bmg:          [PASS][153] -> [ABORT][154] ([Intel XE#9093]) +1 other test abort
   [153]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-10/igt@kms_vblank@ts-continuation-dpms-suspend@pipe-d-dp-2.html
   [154]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-5/igt@kms_vblank@ts-continuation-dpms-suspend@pipe-d-dp-2.html

  * igt@kms_vblank@ts-continuation-suspend:
    - shard-ptl:          NOTRUN -> [ABORT][155] ([Intel XE#9362]) +1 other test abort
   [155]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-1/igt@kms_vblank@ts-continuation-suspend.html

  * igt@kms_vrr@flip-basic-fastset:
    - shard-bmg:          NOTRUN -> [SKIP][156] ([Intel XE#1499] / [Intel XE#9271])
   [156]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-3/igt@kms_vrr@flip-basic-fastset.html

  * igt@kms_vrr@flipline@pipe-a-edp-1:
    - shard-ptl:          [PASS][157] -> [FAIL][158] ([Intel XE#4227] / [Intel XE#7397]) +1 other test fail
   [157]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-ptl-7/igt@kms_vrr@flipline@pipe-a-edp-1.html
   [158]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-3/igt@kms_vrr@flipline@pipe-a-edp-1.html

  * igt@kms_vrr@negative-basic:
    - shard-ptl:          NOTRUN -> [SKIP][159] ([Intel XE#5949] / [Intel XE#9277])
   [159]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-6/igt@kms_vrr@negative-basic.html

  * igt@xe_ccs@suspend-resume:
    - shard-bmg:          [PASS][160] -> [ABORT][161] ([Intel XE#9362] / [Intel XE#9581])
   [160]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-6/igt@xe_ccs@suspend-resume.html
   [161]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-5/igt@xe_ccs@suspend-resume.html

  * igt@xe_create@multigpu-create-massive-size:
    - shard-ptl:          NOTRUN -> [SKIP][162] ([Intel XE#5878])
   [162]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-5/igt@xe_create@multigpu-create-massive-size.html

  * igt@xe_evict@evict-beng-cm-threads-large:
    - shard-bmg:          [PASS][163] -> [DMESG-WARN][164] ([Intel XE#6321]) +1 other test dmesg-warn
   [163]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-1/igt@xe_evict@evict-beng-cm-threads-large.html
   [164]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-1/igt@xe_evict@evict-beng-cm-threads-large.html

  * igt@xe_evict@evict-cm-threads-small-multi-vm:
    - shard-ptl:          NOTRUN -> [SKIP][165] ([Intel XE#5764]) +10 other tests skip
   [165]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-7/igt@xe_evict@evict-cm-threads-small-multi-vm.html

  * igt@xe_evict@evict-small-multi-queue-priority:
    - shard-bmg:          NOTRUN -> [SKIP][166] ([Intel XE#8370])
   [166]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-3/igt@xe_evict@evict-small-multi-queue-priority.html

  * igt@xe_exec_balancer@many-cm-virtual-basic:
    - shard-ptl:          NOTRUN -> [SKIP][167] ([Intel XE#7482]) +19 other tests skip
   [167]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-8/igt@xe_exec_balancer@many-cm-virtual-basic.html

  * igt@xe_exec_balancer@twice-virtual-userptr-invalidate:
    - shard-lnl:          NOTRUN -> [SKIP][168] ([Intel XE#7482])
   [168]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-4/igt@xe_exec_balancer@twice-virtual-userptr-invalidate.html

  * igt@xe_exec_basic@multigpu-no-exec-bindexecqueue-rebind:
    - shard-bmg:          NOTRUN -> [SKIP][169] ([Intel XE#2322] / [Intel XE#7372]) +4 other tests skip
   [169]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-6/igt@xe_exec_basic@multigpu-no-exec-bindexecqueue-rebind.html

  * igt@xe_exec_basic@multigpu-once-basic-defer-bind:
    - shard-ptl:          NOTRUN -> [SKIP][170] ([Intel XE#5575] / [Intel XE#7484]) +3 other tests skip
   [170]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-4/igt@xe_exec_basic@multigpu-once-basic-defer-bind.html

  * igt@xe_exec_fault_mode@many-execqueues-multi-queue-userptr-invalidate-imm:
    - shard-bmg:          NOTRUN -> [SKIP][171] ([Intel XE#8374]) +10 other tests skip
   [171]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-7/igt@xe_exec_fault_mode@many-execqueues-multi-queue-userptr-invalidate-imm.html

  * igt@xe_exec_fault_mode@twice-multi-queue-invalid-userptr-fault:
    - shard-lnl:          NOTRUN -> [SKIP][172] ([Intel XE#8374])
   [172]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-3/igt@xe_exec_fault_mode@twice-multi-queue-invalid-userptr-fault.html

  * igt@xe_exec_fault_mode@twice-multi-queue-userptr-rebind-imm:
    - shard-ptl:          NOTRUN -> [SKIP][173] ([Intel XE#8374]) +7 other tests skip
   [173]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-8/igt@xe_exec_fault_mode@twice-multi-queue-userptr-rebind-imm.html

  * igt@xe_exec_multi_queue@one-queue-preempt-mode-close-fd:
    - shard-lnl:          NOTRUN -> [SKIP][174] ([Intel XE#8364])
   [174]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-6/igt@xe_exec_multi_queue@one-queue-preempt-mode-close-fd.html

  * igt@xe_exec_multi_queue@two-queues-preempt-mode-fault-userptr-invalidate:
    - shard-ptl:          NOTRUN -> [SKIP][175] ([Intel XE#8364]) +18 other tests skip
   [175]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-4/igt@xe_exec_multi_queue@two-queues-preempt-mode-fault-userptr-invalidate.html

  * igt@xe_exec_multi_queue@two-queues-userptr:
    - shard-bmg:          NOTRUN -> [SKIP][176] ([Intel XE#8364]) +18 other tests skip
   [176]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-7/igt@xe_exec_multi_queue@two-queues-userptr.html

  * igt@xe_exec_reset@multi-queue-cancel:
    - shard-ptl:          NOTRUN -> [SKIP][177] ([Intel XE#8369]) +1 other test skip
   [177]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-4/igt@xe_exec_reset@multi-queue-cancel.html

  * igt@xe_exec_reset@multi-queue-long-spin-many-queue-switch:
    - shard-bmg:          NOTRUN -> [SKIP][178] ([Intel XE#8369]) +1 other test skip
   [178]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-2/igt@xe_exec_reset@multi-queue-long-spin-many-queue-switch.html

  * igt@xe_exec_system_allocator@pat-index-madvise-pat-idx-wt-single-vma:
    - shard-ptl:          NOTRUN -> [SKIP][179] ([Intel XE#6196])
   [179]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-2/igt@xe_exec_system_allocator@pat-index-madvise-pat-idx-wt-single-vma.html

  * igt@xe_exec_system_allocator@threads-shared-vm-many-stride-malloc-prefetch-madvise:
    - shard-bmg:          NOTRUN -> [DMESG-WARN][180] ([Intel XE#9309])
   [180]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@xe_exec_system_allocator@threads-shared-vm-many-stride-malloc-prefetch-madvise.html

  * igt@xe_exec_system_allocator@threads-shared-vm-many-stride-new-prefetch:
    - shard-bmg:          [PASS][181] -> [DMESG-WARN][182] ([Intel XE#9309]) +6 other tests dmesg-warn
   [181]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-7/igt@xe_exec_system_allocator@threads-shared-vm-many-stride-new-prefetch.html
   [182]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-7/igt@xe_exec_system_allocator@threads-shared-vm-many-stride-new-prefetch.html

  * igt@xe_exec_threads@threads-multi-queue-cm-fd-userptr:
    - shard-bmg:          NOTRUN -> [SKIP][183] ([Intel XE#8378]) +3 other tests skip
   [183]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-2/igt@xe_exec_threads@threads-multi-queue-cm-fd-userptr.html

  * igt@xe_exec_threads@threads-multi-queue-cm-fd-userptr-invalidate-race:
    - shard-ptl:          NOTRUN -> [SKIP][184] ([Intel XE#8378]) +7 other tests skip
   [184]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-6/igt@xe_exec_threads@threads-multi-queue-cm-fd-userptr-invalidate-race.html

  * igt@xe_exec_threads@threads-multi-queue-mixed-fd-userptr-invalidate:
    - shard-lnl:          NOTRUN -> [SKIP][185] ([Intel XE#8378])
   [185]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-4/igt@xe_exec_threads@threads-multi-queue-mixed-fd-userptr-invalidate.html

  * igt@xe_fault_injection@probe-fail-guc-xe_guc_mmio_send_recv:
    - shard-lnl:          [PASS][186] -> [ABORT][187] ([Intel XE#6652] / [Intel XE#9477])
   [186]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-lnl-5/igt@xe_fault_injection@probe-fail-guc-xe_guc_mmio_send_recv.html
   [187]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-7/igt@xe_fault_injection@probe-fail-guc-xe_guc_mmio_send_recv.html

  * igt@xe_live_ktest@xe_bo@xe_ccs_migrate_kunit:
    - shard-bmg:          NOTRUN -> [SKIP][188] ([Intel XE#2229])
   [188]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-2/igt@xe_live_ktest@xe_bo@xe_ccs_migrate_kunit.html

  * igt@xe_live_ktest@xe_migrate@xe_validate_ccs_kunit:
    - shard-ptl:          NOTRUN -> [SKIP][189] ([Intel XE#5775])
   [189]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-5/igt@xe_live_ktest@xe_migrate@xe_validate_ccs_kunit.html

  * igt@xe_mempage_offline@inject-duplicate-page:
    - shard-bmg:          NOTRUN -> [SKIP][190] ([Intel XE#9203])
   [190]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-8/igt@xe_mempage_offline@inject-duplicate-page.html

  * igt@xe_mmap@vram:
    - shard-ptl:          NOTRUN -> [SKIP][191] ([Intel XE#5776])
   [191]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-3/igt@xe_mmap@vram.html

  * igt@xe_multigpu_svm@mgpu-latency-copy-basic:
    - shard-bmg:          NOTRUN -> [SKIP][192] ([Intel XE#6964]) +1 other test skip
   [192]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@xe_multigpu_svm@mgpu-latency-copy-basic.html

  * igt@xe_multigpu_svm@mgpu-xgpu-access-prefetch:
    - shard-ptl:          NOTRUN -> [SKIP][193] ([Intel XE#6964]) +3 other tests skip
   [193]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-7/igt@xe_multigpu_svm@mgpu-xgpu-access-prefetch.html

  * igt@xe_oa@oa-tlb-invalidate:
    - shard-lnl:          NOTRUN -> [SKIP][194] ([Intel XE#2248] / [Intel XE#7325] / [Intel XE#7393])
   [194]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-4/igt@xe_oa@oa-tlb-invalidate.html

  * igt@xe_page_reclaim@binds-null-vma:
    - shard-bmg:          NOTRUN -> [SKIP][195] ([Intel XE#7793]) +1 other test skip
   [195]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-3/igt@xe_page_reclaim@binds-null-vma.html

  * igt@xe_page_reclaim@prl-invalidate-full:
    - shard-ptl:          NOTRUN -> [SKIP][196] ([Intel XE#7793]) +1 other test skip
   [196]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-4/igt@xe_page_reclaim@prl-invalidate-full.html

  * igt@xe_pat@l2-flush-opt-svm-pat-restrict:
    - shard-ptl:          NOTRUN -> [SKIP][197] ([Intel XE#7590])
   [197]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-5/igt@xe_pat@l2-flush-opt-svm-pat-restrict.html
    - shard-bmg:          NOTRUN -> [SKIP][198] ([Intel XE#7590])
   [198]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-9/igt@xe_pat@l2-flush-opt-svm-pat-restrict.html

  * igt@xe_pm@d3cold-i2c:
    - shard-bmg:          NOTRUN -> [SKIP][199] ([Intel XE#5694] / [Intel XE#7370])
   [199]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@xe_pm@d3cold-i2c.html

  * igt@xe_pm@d3cold-mmap-system:
    - shard-ptl:          NOTRUN -> [SKIP][200] ([Intel XE#5741]) +1 other test skip
   [200]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-8/igt@xe_pm@d3cold-mmap-system.html

  * igt@xe_pxp@pxp-stale-bo-exec-post-termination-irq:
    - shard-bmg:          NOTRUN -> [SKIP][201] ([Intel XE#4733] / [Intel XE#7417])
   [201]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-2/igt@xe_pxp@pxp-stale-bo-exec-post-termination-irq.html

  * igt@xe_query@multigpu-query-cs-cycles:
    - shard-bmg:          NOTRUN -> [SKIP][202] ([Intel XE#944]) +2 other tests skip
   [202]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-4/igt@xe_query@multigpu-query-cs-cycles.html

  * igt@xe_query@multigpu-query-uc-fw-version-guc:
    - shard-ptl:          NOTRUN -> [SKIP][203] ([Intel XE#6019]) +3 other tests skip
   [203]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-6/igt@xe_query@multigpu-query-uc-fw-version-guc.html

  * igt@xe_sriov_vram@vf-access-provisioned:
    - shard-ptl:          NOTRUN -> [SKIP][204] ([Intel XE#6376] / [Intel XE#7422])
   [204]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-8/igt@xe_sriov_vram@vf-access-provisioned.html

  * igt@xe_vm@out-of-memory:
    - shard-ptl:          NOTRUN -> [SKIP][205] ([Intel XE#5745] / [Intel XE#7892])
   [205]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-3/igt@xe_vm@out-of-memory.html

  * igt@xe_wedged@basic-wedged:
    - shard-bmg:          [PASS][206] -> [DMESG-WARN][207] ([Intel XE#8963])
   [206]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-5/igt@xe_wedged@basic-wedged.html
   [207]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-3/igt@xe_wedged@basic-wedged.html

  
#### Possible fixes ####

  * igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-c-hdmi-a-3:
    - shard-bmg:          [INCOMPLETE][208] ([Intel XE#7084] / [Intel XE#8150]) -> [PASS][209]
   [208]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-2/igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-c-hdmi-a-3.html
   [209]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-6/igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-c-hdmi-a-3.html

  * igt@kms_flip@flip-vs-expired-vblank-interruptible@a-edp1:
    - shard-lnl:          [FAIL][210] ([Intel XE#301]) -> [PASS][211]
   [210]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-lnl-5/igt@kms_flip@flip-vs-expired-vblank-interruptible@a-edp1.html
   [211]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-6/igt@kms_flip@flip-vs-expired-vblank-interruptible@a-edp1.html

  * igt@kms_flip@flip-vs-expired-vblank@c-edp1:
    - shard-lnl:          [FAIL][212] ([Intel XE#301] / [Intel XE#3149]) -> [PASS][213] +1 other test pass
   [212]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-lnl-4/igt@kms_flip@flip-vs-expired-vblank@c-edp1.html
   [213]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-2/igt@kms_flip@flip-vs-expired-vblank@c-edp1.html

  * igt@kms_hdmi_audio_bw@audio-bw-hblank160:
    - shard-bmg:          [FAIL][214] ([Intel XE#9313]) -> [PASS][215]
   [214]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-1/igt@kms_hdmi_audio_bw@audio-bw-hblank160.html
   [215]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-2/igt@kms_hdmi_audio_bw@audio-bw-hblank160.html

  * igt@kms_hdmi_inject@inject-audio:
    - shard-bmg:          [SKIP][216] ([Intel XE#7308]) -> [PASS][217]
   [216]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-5/igt@kms_hdmi_inject@inject-audio.html
   [217]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-1/igt@kms_hdmi_inject@inject-audio.html

  * igt@kms_pm_dc@dc6-dpms:
    - shard-lnl:          [FAIL][218] ([Intel XE#8399]) -> [PASS][219]
   [218]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-lnl-3/igt@kms_pm_dc@dc6-dpms.html
   [219]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-6/igt@kms_pm_dc@dc6-dpms.html

  * igt@kms_vrr@flip-dpms@pipe-a-edp-1:
    - shard-ptl:          [FAIL][220] ([Intel XE#4227] / [Intel XE#7397]) -> [PASS][221] +3 other tests pass
   [220]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-ptl-5/igt@kms_vrr@flip-dpms@pipe-a-edp-1.html
   [221]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-2/igt@kms_vrr@flip-dpms@pipe-a-edp-1.html

  * igt@xe_exec_threads@threads-hang-userptr-invalidate-race:
    - shard-lnl:          [FAIL][222] ([Intel XE#9096]) -> [PASS][223]
   [222]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-lnl-2/igt@xe_exec_threads@threads-hang-userptr-invalidate-race.html
   [223]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-8/igt@xe_exec_threads@threads-hang-userptr-invalidate-race.html

  * igt@xe_pmu@engine-activity-accuracy-50:
    - shard-bmg:          [FAIL][224] ([Intel XE#9461]) -> [PASS][225] +3 other tests pass
   [224]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-6/igt@xe_pmu@engine-activity-accuracy-50.html
   [225]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-8/igt@xe_pmu@engine-activity-accuracy-50.html

  * igt@xe_pmu@engine-activity-accuracy-50@engine-drm_xe_engine_class_video_enhance0:
    - shard-bmg:          [FAIL][226] -> [PASS][227] +1 other test pass
   [226]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-6/igt@xe_pmu@engine-activity-accuracy-50@engine-drm_xe_engine_class_video_enhance0.html
   [227]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-8/igt@xe_pmu@engine-activity-accuracy-50@engine-drm_xe_engine_class_video_enhance0.html

  * igt@xe_pmu@engine-activity-suspend:
    - shard-ptl:          [ABORT][228] ([Intel XE#9362]) -> [PASS][229] +2 other tests pass
   [228]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-ptl-3/igt@xe_pmu@engine-activity-suspend.html
   [229]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-5/igt@xe_pmu@engine-activity-suspend.html

  * igt@xe_sync_file@sync_file_race:
    - shard-bmg:          [FAIL][230] ([Intel XE#9457]) -> [PASS][231]
   [230]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-bmg-7/igt@xe_sync_file@sync_file_race.html
   [231]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-bmg-7/igt@xe_sync_file@sync_file_race.html
    - shard-ptl:          [FAIL][232] ([Intel XE#9457]) -> [PASS][233]
   [232]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-ptl-6/igt@xe_sync_file@sync_file_race.html
   [233]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-ptl-4/igt@xe_sync_file@sync_file_race.html
    - shard-lnl:          [FAIL][234] ([Intel XE#9457]) -> [PASS][235]
   [234]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-5955-551605da81c33c1a2352b6a6116360609798f171/shard-lnl-8/igt@xe_sync_file@sync_file_race.html
   [235]: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/shard-lnl-5/igt@xe_sync_file@sync_file_race.html

  
  [Intel XE#1124]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1124
  [Intel XE#1138]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1138
  [Intel XE#1178]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1178
  [Intel XE#1406]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1406
  [Intel XE#1489]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1489
  [Intel XE#1499]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1499
  [Intel XE#1508]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1508
  [Intel XE#2229]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2229
  [Intel XE#2234]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2234
  [Intel XE#2248]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2248
  [Intel XE#2252]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2252
  [Intel XE#2286]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2286
  [Intel XE#2311]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2311
  [Intel XE#2313]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2313
  [Intel XE#2316]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2316
  [Intel XE#2320]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2320
  [Intel XE#2321]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2321
  [Intel XE#2322]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2322
  [Intel XE#2325]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2325
  [Intel XE#2327]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2327
  [Intel XE#2330]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2330
  [Intel XE#2390]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2390
  [Intel XE#2509]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2509
  [Intel XE#2652]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2652
  [Intel XE#2763]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2763
  [Intel XE#2850]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2850
  [Intel XE#2887]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2887
  [Intel XE#2938]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2938
  [Intel XE#301]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/301
  [Intel XE#3149]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3149
  [Intel XE#3304]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3304
  [Intel XE#3414]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3414
  [Intel XE#367]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/367
  [Intel XE#3904]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3904
  [Intel XE#4141]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4141
  [Intel XE#4227]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4227
  [Intel XE#4422]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4422
  [Intel XE#4609]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4609
  [Intel XE#4733]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4733
  [Intel XE#5575]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5575
  [Intel XE#5694]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5694
  [Intel XE#5741]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5741
  [Intel XE#5745]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5745
  [Intel XE#5764]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5764
  [Intel XE#5775]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5775
  [Intel XE#5776]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5776
  [Intel XE#5800]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5800
  [Intel XE#5808]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5808
  [Intel XE#5812]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5812
  [Intel XE#5813]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5813
  [Intel XE#5821]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5821
  [Intel XE#5822]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5822
  [Intel XE#5824]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5824
  [Intel XE#5828]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5828
  [Intel XE#5832]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5832
  [Intel XE#5835]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5835
  [Intel XE#5844]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5844
  [Intel XE#5846]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5846
  [Intel XE#5858]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5858
  [Intel XE#5865]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5865
  [Intel XE#5878]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5878
  [Intel XE#5879]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5879
  [Intel XE#5900]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5900
  [Intel XE#5901]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5901
  [Intel XE#5907]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5907
  [Intel XE#5910]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5910
  [Intel XE#5946]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5946
  [Intel XE#5949]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5949
  [Intel XE#5958]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5958
  [Intel XE#5962]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5962
  [Intel XE#6019]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6019
  [Intel XE#6035]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6035
  [Intel XE#610]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/610
  [Intel XE#6196]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6196
  [Intel XE#6312]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6312
  [Intel XE#6321]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6321
  [Intel XE#6376]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6376
  [Intel XE#6503]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6503
  [Intel XE#651]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/651
  [Intel XE#656]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/656
  [Intel XE#6652]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6652
  [Intel XE#6707]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6707
  [Intel XE#6886]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6886
  [Intel XE#6901]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6901
  [Intel XE#6964]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6964
  [Intel XE#6974]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6974
  [Intel XE#7059]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7059
  [Intel XE#7061]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7061
  [Intel XE#7084]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7084
  [Intel XE#7085]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7085
  [Intel XE#7178]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7178
  [Intel XE#7283]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7283
  [Intel XE#7304]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7304
  [Intel XE#7308]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7308
  [Intel XE#7325]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7325
  [Intel XE#7342]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7342
  [Intel XE#7343]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7343
  [Intel XE#7344]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7344
  [Intel XE#7345]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7345
  [Intel XE#7351]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7351
  [Intel XE#7355]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7355
  [Intel XE#7356]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7356
  [Intel XE#7358]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7358
  [Intel XE#7370]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7370
  [Intel XE#7372]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7372
  [Intel XE#7374]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7374
  [Intel XE#7376]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7376
  [Intel XE#7387]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7387
  [Intel XE#7393]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7393
  [Intel XE#7397]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7397
  [Intel XE#7399]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7399
  [Intel XE#7417]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7417
  [Intel XE#7422]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7422
  [Intel XE#7437]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7437
  [Intel XE#7439]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7439
  [Intel XE#7442]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7442
  [Intel XE#7482]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7482
  [Intel XE#7484]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7484
  [Intel XE#7590]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7590
  [Intel XE#7642]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7642
  [Intel XE#7679]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7679
  [Intel XE#7695]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7695
  [Intel XE#7760]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7760
  [Intel XE#7793]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7793
  [Intel XE#7795]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7795
  [Intel XE#7809]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7809
  [Intel XE#7865]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7865
  [Intel XE#7892]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7892
  [Intel XE#7905]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7905
  [Intel XE#7935]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7935
  [Intel XE#8150]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8150
  [Intel XE#8265]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8265
  [Intel XE#8303]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8303
  [Intel XE#8364]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8364
  [Intel XE#8369]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8369
  [Intel XE#8370]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8370
  [Intel XE#8374]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8374
  [Intel XE#8378]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8378
  [Intel XE#8391]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8391
  [Intel XE#8395]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8395
  [Intel XE#8396]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8396
  [Intel XE#8399]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8399
  [Intel XE#8680]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8680
  [Intel XE#870]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/870
  [Intel XE#8963]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8963
  [Intel XE#9093]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9093
  [Intel XE#9096]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9096
  [Intel XE#9203]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9203
  [Intel XE#9221]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9221
  [Intel XE#9271]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9271
  [Intel XE#9277]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9277
  [Intel XE#9287]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9287
  [Intel XE#9309]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9309
  [Intel XE#9312]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9312
  [Intel XE#9313]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9313
  [Intel XE#9319]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9319
  [Intel XE#9346]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9346
  [Intel XE#9362]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9362
  [Intel XE#9364]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9364
  [Intel XE#9375]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9375
  [Intel XE#9389]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9389
  [Intel XE#9428]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9428
  [Intel XE#944]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/944
  [Intel XE#9457]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9457
  [Intel XE#9461]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9461
  [Intel XE#9474]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9474
  [Intel XE#9477]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9477
  [Intel XE#9522]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9522
  [Intel XE#9581]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9581


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

  * IGT: IGT_9149 -> IGT_9150
  * Linux: xe-5955-551605da81c33c1a2352b6a6116360609798f171 -> xe-pw-176241v1

  IGT_9149: 157f243d73fb8c010db8c884db81ca2e558b4ab2 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  IGT_9150: 18811c476bfde62ffbb4c0af55cd6f57e36e0dca @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  xe-5955-551605da81c33c1a2352b6a6116360609798f171: 551605da81c33c1a2352b6a6116360609798f171
  xe-pw-176241v1: 176241v1

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/xe-pw-176241v1/index.html

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

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

* Re: [PATCH v3 1/9] drm/xe/hwmon: initialize fan-control backend and table cache
  2026-10-15 19:07 ` [PATCH v3 1/9] drm/xe/hwmon: initialize fan-control backend and table cache Karthik Poosa
@ 2026-10-28 18:46   ` Purkait, Soham
  2026-10-29 11:34     ` Poosa, Karthik
  0 siblings, 1 reply; 26+ messages in thread
From: Purkait, Soham @ 2026-10-28 18:46 UTC (permalink / raw)
  To: Karthik Poosa, intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi,
	ravi.kishore.koppuravuri

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

Hi Karthik,

On 16-10-2026 00:37, Karthik Poosa wrote:
> Initialize Xe hwmon fan-control support by detecting fan count,
> reading stock fan control points and min PWM.
>
> v2:
>   - Avoid user table initialization during probe. (Badal)
>   - Move unused code to appropriate patches.
>   - Use xe helpers for dmesg logs.
>
> v3:
>   - Rebase.
>   - Refine a few debug log messages and comments.
>   - Update xe_hwmon_read_fan_control_info() to return on any stock table
>     read failures.
>   - Avoid returning when num_fans is 0 in
>     xe_hwmon_get_preregistration_info(), ensuring thermal mailbox
>     initialization is not skipped.
>   - Remove XE_PCODE_FAN_CONTROL_TIMEOUT_MS which is unncessary as default
>     timeout itself is now 10ms.
>   - Use xe_pcode_read() instead of xe_pcode_read_timeout().
>   - Rename fan_control_point_count to point_count in struct fan_table.
>   - Resolve kgdoc warnings.
>   - Add valid check for stock table fan point count.
>   - Use the fan-enable bitmap reported by FSC_READ_NUM_FANS when enumerating
>     fans. This avoids assuming contiguous fan indices and allows masks with
>     gaps to be represented correctly in the hwmon interface.
>
> Signed-off-by: Karthik Poosa<karthik.poosa@intel.com>
> Assisted-by: LLM
> ---
>   drivers/gpu/drm/xe/xe_hwmon.c     | 167 +++++++++++++++++++++++++++---
>   drivers/gpu/drm/xe/xe_pcode_api.h |   5 +
>   2 files changed, 157 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
> index 42acfeb8818c..f2bd20f8b0a2 100644
> --- a/drivers/gpu/drm/xe/xe_hwmon.c
> +++ b/drivers/gpu/drm/xe/xe_hwmon.c
> @@ -21,6 +21,7 @@
>   #include "xe_pcode_api.h"
>   #include "xe_sriov.h"
>   #include "xe_pm.h"
> +#include "xe_printk.h"
>   #include "xe_vsec.h"
>   #include "regs/xe_pmt.h"
>   
> @@ -137,14 +138,51 @@ struct xe_hwmon_energy_info {
>   	long accum_energy;
>   };
>   
> +enum fan_table_type {
> +	/** @STOCK_FAN_TABLE: firmware-provided fan table */
> +	STOCK_FAN_TABLE,
> +	/** @USER_FAN_TABLE: user fan table written through sysfs */
> +	USER_FAN_TABLE,
> +	/** @FAN_TABLE_MAX: number of fan tables tracked per fan */
> +	FAN_TABLE_MAX,
> +};
> +
> +/* Check if a fan is enabled based on the fan_enable_mask got from FSC_READ_NUM_FANS. */
> +#define IS_FAN_ENABLED(fan) (hwmon->fan_enable_mask & BIT(fan))
If this macro is called from any function having no local variable named 
hwmon it will break. Should it take hwmon as an argument ?
> +
> +/* Maximum number of fan control points supported by each fan. */
> +#define MAX_FAN_CONTROL_POINTS	(10)
> +
> +/* Fan control point index: bit31 selects fan table type; bits30:0 control point index. */
> +#define FCP_INDEX(FAN_TABLE_TYPE, POINT_NUM) (((FAN_TABLE_TYPE) << 31) | \
Cast to u32 ? shifting the signed enum into bit 31 could lead to UB.
> +						((POINT_NUM) & REG_GENMASK(30, 0)))
> +
>   /**
> - * struct xe_hwmon_fan_info - to cache previous fan reading
> + * struct xe_hwmon_fan_info - cached fan telemetry and control state
> + *
> + * Each fan keeps the latest tachometer sampling state along with two fan
> + * tables: the stock table discovered from firmware and the user table managed
> + * by hwmon sysfs writes.
>    */
>   struct xe_hwmon_fan_info {
>   	/** @reg_val_prev: previous fan reg val */
>   	u32 reg_val_prev;
>   	/** @time_prev: previous timestamp */
>   	u64 time_prev;
> +	/** @fan_table: fan control tables */
> +	struct fan_table {
> +		/** @point_count: number of fan control points */
> +		u8 point_count;
> +		/** @fcp: array of fan control points */
> +		struct fan_control_point {
> +			/** @temp: temperature in degree celsius */
> +			u8 temp;
> +			/** @speed: fan speed in percentage */
> +			u8 speed;
> +		} fcp[MAX_FAN_CONTROL_POINTS];
> +	} fan_table[FAN_TABLE_MAX];
> +	/** @min_pwm: minimum fan PWM */
> +	u32 min_pwm;
>   };
>   
>   /**
> @@ -193,6 +231,8 @@ struct xe_hwmon {
>   	int scl_shift_time;
>   	/** @ei: Energy info for energyN_input */
>   	struct xe_hwmon_energy_info ei[CHANNEL_MAX];
> +	/** @fan_enable_mask: bitmask of available fans */
> +	u32 fan_enable_mask;
>   	/** @fi: Fan info for fanN_input */
>   	struct xe_hwmon_fan_info fi[FAN_MAX];
>   	/** @read_power_limit_from_pcode: pcode accepted power limits write for the channel */
> @@ -1075,17 +1115,112 @@ static int xe_hwmon_pcode_write_i1(const struct xe_hwmon *hwmon, u32 uval)
>   			      (uval & POWER_SETUP_I1_DATA_MASK));
>   }
>   
> -static int xe_hwmon_pcode_read_fan_control(const struct xe_hwmon *hwmon, u32 subcmd, u32 *uval)
> +static int xe_hwmon_pcode_read_fan_control(const struct xe_hwmon *hwmon, u32 subcmd, u8 fan_num,
> +					   u32 *uval)
>   {
>   	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
Nit: blank line after variable declaration
> +	return xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL, subcmd, fan_num),
> +				     uval, NULL);
> +}
> +
> +static int xe_hwmon_get_fan_enable_mask(struct xe_hwmon *hwmon)
> +{
> +	int ret;
>   
>   	/* Platforms that don't return correct value */
> -	if (hwmon->xe->info.platform == XE_DG2 && subcmd == FSC_READ_NUM_FANS) {
> -		*uval = 2;
> +	if (hwmon->xe->info.platform == XE_DG2) {
> +		hwmon->fan_enable_mask = GENMASK(1, 0);
>   		return 0;
>   	}
>   
> -	return xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL, subcmd, 0), uval, NULL);
> +	ret = xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_NUM_FANS, 0,
> +					      &hwmon->fan_enable_mask);
> +	if (ret) {
> +		xe_warn(hwmon->xe, "failed to read number of fans, ret=%d\n", ret);
> +		return ret;
> +	}
> +
> +	/* Check if fan mask exceeds FAN_MAX and log a warning if it does */
> +	if (hwmon->fan_enable_mask & ~GENMASK(FAN_MAX - 1, 0)) {
> +		xe_warn(hwmon->xe, "fan enable mask exceeds maximum supported fans\n");
Reset the mask to 0 so IS_FAN_ENABLED() stays false in case fan mask 
exceeds FAN_MAX.
> +		return -EINVAL;
> +	}
> +
> +	xe_info(hwmon->xe, "Number of fans detected: %u\n",
> +		hweight32(hwmon->fan_enable_mask));
> +	return 0;
> +}
> +
> +static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
> +{
> +	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
> +	int point;
> +	int fan;
> +	int ret;
> +
> +	for (fan = 0; fan < FAN_MAX; fan++) {
> +		u32 stock_fcp_count = 0;
> +
> +		struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
> +
> +		if (!IS_FAN_ENABLED(fan))
> +			continue;
> +
> +		ret = xe_hwmon_pcode_read_fan_control(hwmon,
> +						      FSC_READ_STOCK_FAN_CONTROL_POINTS,
> +						      fan, &stock_fcp_count);
> +		if (ret) {
> +			xe_err(hwmon->xe,
> +			       "failed to read fan %d stock table point count, ret=%d\n",
> +			       fan, ret);
Why not continue for the rest of the fans marking the current one ?
> +			return ret;
> +		}
> +
> +		if (!stock_fcp_count || stock_fcp_count > MAX_FAN_CONTROL_POINTS) {
> +			xe_warn(hwmon->xe,
> +				"fan %d stock table point count %u is invalid\n",
> +				fan, stock_fcp_count);
Ditto.
> +			return -EINVAL;
> +		}
> +
> +		fi->fan_table[STOCK_FAN_TABLE].point_count = stock_fcp_count;
> +		xe_dbg(hwmon->xe, "fan %d stock table point count is %u\n", fan,
> +		       fi->fan_table[STOCK_FAN_TABLE].point_count);
> +
> +		/* Cache the stock fan table for later use. */
> +		for (point = 0; point < fi->fan_table[STOCK_FAN_TABLE].point_count;
> +		     point++) {
> +			u32 fcp = 0;
> +
> +			fcp = FCP_INDEX(STOCK_FAN_TABLE, point);

nit: u32 fcp = FCP_INDEX(STOCK_FAN_TABLE, point);

Regards,
Soham
> +			ret = xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL,
> +								  FSC_READ_FAN_TABLE, fan),
> +					    &fcp, NULL);
> +			if (ret) {
> +				xe_err(hwmon->xe, "failed to read fan %d stock point %d, ret=%d\n",
> +				       fan, point, ret);
> +				fi->fan_table[STOCK_FAN_TABLE].point_count = 0;
> +				return ret;
> +			}
> +
> +			fi->fan_table[STOCK_FAN_TABLE].fcp[point].temp =
> +						REG_FIELD_GET(FAN_CONTROL_POINT_TEMP_MASK, fcp);
> +			fi->fan_table[STOCK_FAN_TABLE].fcp[point].speed =
> +						REG_FIELD_GET(FAN_CONTROL_POINT_SPEED_MASK, fcp);
> +			xe_dbg(hwmon->xe, "fan %d stock point %d: temp %u C, speed %u\n",
> +			       fan, point, fi->fan_table[STOCK_FAN_TABLE].fcp[point].temp,
> +			       fi->fan_table[STOCK_FAN_TABLE].fcp[point].speed);
> +		}
> +
> +		/* Read minimum fan PWM */
> +		ret = xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_FAN_MIN_PWM, fan,
> +						      &fi->min_pwm);
> +		if (ret)
> +			xe_warn(hwmon->xe, "fan %d min pwm unavailable, ret=%d\n", fan, ret);
> +		else
> +			xe_dbg(hwmon->xe, "fan %d min PWM %u\n", fan, fi->min_pwm);
> +	}
> +	return 0;
>   }
>   
>   static int xe_hwmon_power_curr_crit_read(struct xe_hwmon *hwmon, int channel,
> @@ -1615,17 +1750,12 @@ xe_hwmon_energy_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
>   static umode_t
>   xe_hwmon_fan_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
>   {
> -	u32 uval = 0;
> -
>   	if (!hwmon->xe->info.has_fan_control)
>   		return 0;
>   
>   	switch (attr) {
>   	case hwmon_fan_input:
> -		if (xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_NUM_FANS, &uval))
> -			return 0;
> -
> -		return channel < uval ? 0444 : 0;
> +		return IS_FAN_ENABLED(channel) ? 0444 : 0;
>   	default:
>   		return 0;
>   	}
> @@ -1858,11 +1988,18 @@ xe_hwmon_get_preregistration_info(struct xe_hwmon *hwmon)
>   		if (xe_hwmon_is_visible(hwmon, hwmon_energy, hwmon_energy_input, channel))
>   			xe_hwmon_energy_get(hwmon, channel, &energy);
>   
> -	/* Initialize 'struct xe_hwmon_fan_info' with initial fan register reading. */
> -	for (channel = 0; channel < FAN_MAX; channel++)
> -		if (xe_hwmon_is_visible(hwmon, hwmon_fan, hwmon_fan_input, channel))
> -			xe_hwmon_fan_input_read(hwmon, channel, &fan_speed);
> +	if (hwmon->xe->info.has_fan_control) {
> +		xe_hwmon_get_fan_enable_mask(hwmon);
> +
> +		/* Initialize 'struct xe_hwmon_fan_info' with initial fan register reading. */
> +		for (channel = 0; channel < FAN_MAX; channel++)
> +			if (IS_FAN_ENABLED(channel))
> +				xe_hwmon_fan_input_read(hwmon, channel, &fan_speed);
>   
> +		/* Fan control tables initialization */
> +		if (xe_hwmon_read_fan_control_info(hwmon))
> +			xe_warn(hwmon->xe, "Fan control tables are not available\n");
> +	}
>   	return xe_hwmon_init_temp_info(hwmon);
>   }
>   
> diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h
> index 00c4fc7d0124..0349b24a8259 100644
> --- a/drivers/gpu/drm/xe/xe_pcode_api.h
> +++ b/drivers/gpu/drm/xe/xe_pcode_api.h
> @@ -83,6 +83,11 @@
>   
>   #define   FAN_SPEED_CONTROL			0x7D
>   #define     FSC_READ_NUM_FANS			0x4
> +#define     FSC_READ_STOCK_FAN_CONTROL_POINTS	0x5
> +#define     FSC_READ_FAN_TABLE			0x7
> +#define     FAN_CONTROL_POINT_TEMP_MASK		REG_GENMASK(7, 0)
> +#define     FAN_CONTROL_POINT_SPEED_MASK	REG_GENMASK(15, 8)
> +#define     FSC_READ_FAN_MIN_PWM		0x8
>   
>   #define PCODE_SCRATCH(x)		XE_REG(0x138320 + ((x) * 4))
>   /* PCODE_SCRATCH0 */

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

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

* Re: [PATCH v3 2/9] drm/xe/hwmon: expose fanN_max
  2026-10-15 19:07 ` [PATCH v3 2/9] drm/xe/hwmon: expose fanN_max Karthik Poosa
@ 2026-10-29  4:35   ` Purkait, Soham
  2026-10-29 11:39     ` Poosa, Karthik
  0 siblings, 1 reply; 26+ messages in thread
From: Purkait, Soham @ 2026-10-29  4:35 UTC (permalink / raw)
  To: Karthik Poosa, intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi,
	ravi.kishore.koppuravuri

Hi Karthik,

On 16-10-2026 00:37, Karthik Poosa wrote:
> Expose fan maximum RPM via fanN_max.
>
> The value is derived from the firmware-reported maximum fan RPS and
> converted to RPM in the fan hwmon read path.
>
> Update Xe hwmon ABI documentation for fanN_max.
>
> v2: Use xe helper for dmesg logs.
>
> v3:
>   - Fix indentation of the max_rps struct member.
>   - Enable fanN_max only when fanN is supported.
>
> Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
> Assisted-by: LLM
> ---
>   .../ABI/testing/sysfs-driver-intel-xe-hwmon   |  8 ++++++++
>   drivers/gpu/drm/xe/xe_hwmon.c                 | 19 ++++++++++++++++++-
>   drivers/gpu/drm/xe/xe_pcode_api.h             |  1 +
>   3 files changed, 27 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
> index 0da739d9a816..5ee68aefa485 100644
> --- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
> +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
> @@ -266,6 +266,14 @@ Description:	RO. Fan 3 speed in RPM.
>   
>   		Only supported for particular Intel Xe graphics platforms.
>   
> +What:           /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/fan[1-3]_max
> +Date:           October 2026
> +KernelVersion:  7.3
> +Contact:        intel-xe@lists.freedesktop.org
> +Description:    RO. Maximum fan speed in RPM for each fan channel.
> +
> +                Only supported for particular Intel Xe graphics platforms.
> +
Use tab indentation.
>   What:		/sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/power1_cap
>   Date:		May 2025
>   KernelVersion:	6.15
> diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
> index f2bd20f8b0a2..32016c5d4770 100644
> --- a/drivers/gpu/drm/xe/xe_hwmon.c
> +++ b/drivers/gpu/drm/xe/xe_hwmon.c
> @@ -181,6 +181,8 @@ struct xe_hwmon_fan_info {
>   			u8 speed;
>   		} fcp[MAX_FAN_CONTROL_POINTS];
>   	} fan_table[FAN_TABLE_MAX];
> +	/** @max_rps: maximum fan RPS */
> +	u32 max_rps;
>   	/** @min_pwm: minimum fan PWM */
>   	u32 min_pwm;
>   };
> @@ -909,7 +911,8 @@ static const struct hwmon_channel_info * const hwmon_info[] = {
>   	HWMON_CHANNEL_INFO(curr, HWMON_C_LABEL, HWMON_C_CRIT | HWMON_C_LABEL),
>   	HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LABEL, HWMON_I_INPUT | HWMON_I_LABEL),
>   	HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT | HWMON_E_LABEL, HWMON_E_INPUT | HWMON_E_LABEL),
> -	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT, HWMON_F_INPUT, HWMON_F_INPUT),
> +	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_MAX, HWMON_F_INPUT | HWMON_F_MAX,
> +			   HWMON_F_INPUT | HWMON_F_MAX),
>   	NULL
>   };
>   
> @@ -1219,6 +1222,14 @@ static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
>   			xe_warn(hwmon->xe, "fan %d min pwm unavailable, ret=%d\n", fan, ret);
>   		else
>   			xe_dbg(hwmon->xe, "fan %d min PWM %u\n", fan, fi->min_pwm);
> +
> +		/* Read max fan RPS*/
Add a space before */
> +		ret = xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_MAX_FAN_RPS, fan,
> +						      &fi->max_rps);
> +		if (ret)
Should fi->max_rps be set to 0 on read failure so the attribute is 
correctly hidden on re-read ?
> +			xe_warn(hwmon->xe, "failed to read fan %d max RPS, ret=%d\n", fan, ret);
> +		else
> +			xe_dbg(hwmon->xe, "fan %d max RPS %u\n", fan, fi->max_rps);
>   	}
>   	return 0;
>   }
> @@ -1756,6 +1767,8 @@ xe_hwmon_fan_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
>   	switch (attr) {
>   	case hwmon_fan_input:
>   		return IS_FAN_ENABLED(channel) ? 0444 : 0;
> +	case hwmon_fan_max:
> +		return IS_FAN_ENABLED(channel) && hwmon->fi[channel].max_rps ? 0444 : 0;
>   	default:
>   		return 0;
>   	}
> @@ -1806,6 +1819,10 @@ xe_hwmon_fan_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
>   	switch (attr) {
>   	case hwmon_fan_input:
>   		return xe_hwmon_fan_input_read(hwmon, channel, val);
> +	case hwmon_fan_max:
> +		/* Convert RPS to RPM */
> +		*val = (long)hwmon->fi[channel].max_rps * 60;
> +		return 0;
>   	default:
>   		return -EOPNOTSUPP;
>   	}
> diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h
> index 0349b24a8259..32bac74c4281 100644
> --- a/drivers/gpu/drm/xe/xe_pcode_api.h
> +++ b/drivers/gpu/drm/xe/xe_pcode_api.h
> @@ -82,6 +82,7 @@
>   #define     PCODE_MBOX_DOMAIN_HBM		0x2
>   
>   #define   FAN_SPEED_CONTROL			0x7D
> +#define     FSC_READ_MAX_FAN_RPS        0x3

Nit: alignment.

Regards,
Soham
>   #define     FSC_READ_NUM_FANS			0x4
>   #define     FSC_READ_STOCK_FAN_CONTROL_POINTS	0x5
>   #define     FSC_READ_FAN_TABLE			0x7

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

* Re: [PATCH v3 3/9] drm/xe/pcode: add ordered write batch helper
  2026-10-15 19:07 ` [PATCH v3 3/9] drm/xe/pcode: add ordered write batch helper Karthik Poosa
@ 2026-10-29  5:45   ` Purkait, Soham
  2026-10-29 11:40     ` Poosa, Karthik
  0 siblings, 1 reply; 26+ messages in thread
From: Purkait, Soham @ 2026-10-29  5:45 UTC (permalink / raw)
  To: Karthik Poosa, intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi,
	ravi.kishore.koppuravuri

Hi Karthik,

On 16-10-2026 00:37, Karthik Poosa wrote:
> Provide a pcode write helper that keeps the mailbox lock held while issuing
> an ordered sequence of writes.
> This will be used while writing the fan table ensuring that is not
> interleaved by any other pcode mailbox command.
>
> Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
> ---
>   drivers/gpu/drm/xe/xe_pcode.c | 20 ++++++++++++++++++++
>   drivers/gpu/drm/xe/xe_pcode.h |  7 +++++++
>   2 files changed, 27 insertions(+)
>
> diff --git a/drivers/gpu/drm/xe/xe_pcode.c b/drivers/gpu/drm/xe/xe_pcode.c
> index 266deecbb100..ca107b0234d9 100644
> --- a/drivers/gpu/drm/xe/xe_pcode.c
> +++ b/drivers/gpu/drm/xe/xe_pcode.c
> @@ -124,6 +124,26 @@ int xe_pcode_write_timeout(struct xe_tile *tile, u32 mbox, u32 data, int timeout
>   	return err;
>   }
>   
> +int xe_pcode_write_batch(struct xe_tile *tile, const struct xe_pcode_write *writes,
> +			 unsigned int count)
> +{
> +	unsigned int i;
> +	int err = 0;
> +
> +	mutex_lock(&tile->pcode.lock);
nit: if count == 0 then return immediately without acquiring the mutex.
> +	for (i = 0; i < count; i++) {
> +		u32 data = writes[i].data;
> +
> +		err = pcode_mailbox_rw(tile, writes[i].mbox, &data, NULL, PCODE_DEFAULT_TIMEOUT_MS,
> +				       false, false);
> +		if (err)

Use a debug print in case of failure for clarity.

Regards,
Soham
> +			break;
> +	}
> +	mutex_unlock(&tile->pcode.lock);
> +
> +	return err;
> +}
> +
>   int xe_pcode_write64_timeout(struct xe_tile *tile, u32 mbox, u32 data0, u32 data1, int timeout)
>   {
>   	int err;
> diff --git a/drivers/gpu/drm/xe/xe_pcode.h b/drivers/gpu/drm/xe/xe_pcode.h
> index 7e43792b0037..74bd553ab390 100644
> --- a/drivers/gpu/drm/xe/xe_pcode.h
> +++ b/drivers/gpu/drm/xe/xe_pcode.h
> @@ -18,6 +18,11 @@ struct xe_pcode_version {
>   	u32 engg;
>   };
>   
> +struct xe_pcode_write {
> +	u32 mbox;
> +	u32 data;
> +};
> +
>   #define PCODE_DEFAULT_TIMEOUT_MS	10
>   
>   int xe_pcode_init_early(struct xe_tile *tile);
> @@ -28,6 +33,8 @@ int xe_pcode_init_min_freq_table(struct xe_tile *tile, u32 min_gt_freq,
>   int xe_pcode_read(struct xe_tile *tile, u32 mbox, u32 *val0, u32 *val1);
>   int xe_pcode_write_timeout(struct xe_tile *tile, u32 mbox, u32 val,
>   			   int timeout_ms);
> +int xe_pcode_write_batch(struct xe_tile *tile, const struct xe_pcode_write *writes,
> +			 unsigned int count);
>   int xe_pcode_write64_timeout(struct xe_tile *tile, u32 mbox, u32 data0,
>   			     u32 data1, int timeout);
>   int xe_get_pcode_version(struct xe_device *xe, struct xe_pcode_version *version);

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

* Re: [PATCH v3 4/9] drm/xe/hwmon: expose pwm[1-3]
  2026-10-15 19:07 ` [PATCH v3 4/9] drm/xe/hwmon: expose pwm[1-3] Karthik Poosa
@ 2026-10-29 11:31   ` Purkait, Soham
  0 siblings, 0 replies; 26+ messages in thread
From: Purkait, Soham @ 2026-10-29 11:31 UTC (permalink / raw)
  To: Karthik Poosa, intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi,
	ravi.kishore.koppuravuri

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

Hi Karthik,

On 16-10-2026 00:37, Karthik Poosa wrote:
> Expose pwm[1-3] fan duty attributes through hwmon.
>
> This enables reading and writing user PWM values (0..255) for each
> available fan channel.
>
> Update Xe hwmon ABI documentation for pwm[1-3].
>
> This sysfs node can be used for manual control of fan speed,
> irrespective of fan curve.
>
> v2:
>   - Use xe helpers for dmesg logs.
>   - Avoid using hwmon->num_fans to get fan count in
>     xe_hwmon_pwm_is_visible().
>
> v3:
>   - Set PWM directly through the user table; avoid initializing it from the
>     stock table. (Soham)
>   - Move the unused xe_hwmon_activate_user_fan_table() to the subsequent
>     patch.
>   - Fail pwmN reads when no value has been written, rather than activating
>     the user table from the stock table.
>   - Define MIN_FAN_CONTROL_POINTS as 2.
>   - Use MIN_FAN_CONTROL_POINTS for PWM configuration. (Soham)
>   - Use batched writes for configuring fan control points when setting pwmN.
>   - Add and rephrase couple debug logs.
>   - Update the hwmon documentation.
>
> Signed-off-by: Karthik Poosa<karthik.poosa@intel.com>
> Assisted-by: LLM
> ---
>   .../ABI/testing/sysfs-driver-intel-xe-hwmon   |   9 +
>   drivers/gpu/drm/xe/xe_hwmon.c                 | 170 ++++++++++++++++++
>   drivers/gpu/drm/xe/xe_pcode_api.h             |   3 +
>   3 files changed, 182 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
> index 5ee68aefa485..ce17e9ca3ed8 100644
> --- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
> +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
> @@ -321,3 +321,12 @@ Description:	RW. Package burst power limit interval (Tau in PL2/Tau) in
>   		milliseconds over which sustained power is averaged.
>   
>   		Only supported for particular Intel Xe graphics platforms.
> +
> +What:           /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/pwm[1-3]
> +Date:           October 2026
> +KernelVersion:  7.3
> +Contact:intel-xe@lists.freedesktop.org
> +Description:    RW. Target fan PWM duty value in the range 0..255. 0 is zero
> +                fan speed and 255 is 100% fan speed.
> +
> +                Only supported for particular Intel Xe graphics platforms.
Use tab indentation after the field labels.
> diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
> index 32016c5d4770..a86ed741feb3 100644
> --- a/drivers/gpu/drm/xe/xe_hwmon.c
> +++ b/drivers/gpu/drm/xe/xe_hwmon.c
> @@ -8,6 +8,7 @@
>   #include <linux/jiffies.h>
>   #include <linux/types.h>
>   #include <linux/units.h>
> +#include <linux/delay.h>
Is this header required ?
>   
>   #include <drm/drm_managed.h>
>   #include "regs/xe_gt_regs.h"
> @@ -153,6 +154,9 @@ enum fan_table_type {
>   /* Maximum number of fan control points supported by each fan. */
>   #define MAX_FAN_CONTROL_POINTS	(10)
>   
> +/* Minimum number of points required for a user fan table. */
> +#define MIN_FAN_CONTROL_POINTS  (2)
Use tab indentation.
> +
>   /* Fan control point index: bit31 selects fan table type; bits30:0 control point index. */
>   #define FCP_INDEX(FAN_TABLE_TYPE, POINT_NUM) (((FAN_TABLE_TYPE) << 31) | \
>   						((POINT_NUM) & REG_GENMASK(30, 0)))
> @@ -913,6 +917,7 @@ static const struct hwmon_channel_info * const hwmon_info[] = {
>   	HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT | HWMON_E_LABEL, HWMON_E_INPUT | HWMON_E_LABEL),
>   	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_MAX, HWMON_F_INPUT | HWMON_F_MAX,
>   			   HWMON_F_INPUT | HWMON_F_MAX),
> +	HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT, HWMON_PWM_INPUT, HWMON_PWM_INPUT),
>   	NULL
>   };
>   
> @@ -1154,6 +1159,89 @@ static int xe_hwmon_get_fan_enable_mask(struct xe_hwmon *hwmon)
>   	return 0;
>   }
>   
> +static int xe_hwmon_get_fan_point_count(struct xe_hwmon *hwmon, u8 fan, u32 *point_count,
> +					enum fan_table_type table_type)
> +{
> +	int ret;
> +
> +	ret = xe_hwmon_pcode_read_fan_control(hwmon,
> +					      (table_type == USER_FAN_TABLE) ?
> +					      FSC_READ_USER_FAN_CONTROL_POINTS :
> +					      FSC_READ_STOCK_FAN_CONTROL_POINTS,
> +					      fan, point_count);
> +	if (ret) {
> +		xe_err(hwmon->xe, "failed to read fan %d %s point count, ret=%d\n", fan,
> +		       (table_type == USER_FAN_TABLE) ? "user" : "stock", ret);
> +		return ret;
> +	}
> +
> +	if (*point_count > MAX_FAN_CONTROL_POINTS) {
> +		xe_err(hwmon->xe, "fan %d %s point count %u exceeds max %u\n", fan,
> +		       (table_type == USER_FAN_TABLE) ? "user" : "stock", *point_count,
> +		       MAX_FAN_CONTROL_POINTS);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Temperature to set when setting the fan PWM with pwmN. */
> +#define FIXED_PWM_TEMP	(1)
> +
> +static int xe_hwmon_set_user_fan_pwm(struct xe_hwmon *hwmon, u8 fan, u8 pwm)
> +{
> +	struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
> +	struct xe_pcode_write writes[MIN_FAN_CONTROL_POINTS + 1];
> +	u32 point_count = 0;
> +	u8 clamped_pwm;
> +	int ret, i;
> +
> +	pwm = DIV_ROUND_CLOSEST(pwm * 100, U8_MAX);
> +	clamped_pwm = max_t(u8, pwm, min_t(u32, fi->min_pwm, U8_MAX));
Is clamped_pwm and  fi->min_pwm in percentage ? If so use 100 *instead 
of* U8_MAX to be the max value.
> +
> +	/*
> +	 * Set the first fan control point in the user table to the clamped PWM value.
> +	 * Use only the first fan control point for setting the PWM value.
It says "only the first fan control point" but the loop end up writing 2 
points.
> +	 */
> +
> +	for (i = 0; i < MIN_FAN_CONTROL_POINTS; i++) {
> +		writes[i].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_FAN_TABLE, fan);
> +		writes[i].data = FIELD_PREP(FAN_CONTROL_POINT_TEMP_MASK, FIXED_PWM_TEMP + (i)) |
> +					    FIELD_PREP(FAN_CONTROL_POINT_SPEED_MASK, clamped_pwm);
> +		xe_dbg(hwmon->xe, "prepared fan control point %d with temp=%d, speed=%u\n", i,
> +		       FIXED_PWM_TEMP + (i), clamped_pwm);
> +	}
> +
> +	writes[i].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_NUM_FAN_CONTROL_POINTS, fan);
> +	writes[i].data = MIN_FAN_CONTROL_POINTS;
> +	ret = xe_pcode_write_batch(xe_device_get_root_tile(hwmon->xe), writes, ARRAY_SIZE(writes));
> +	if (ret) {
> +		xe_err(hwmon->xe, "failed to write pwm %d for fan %d, ret=%d\n", pwm, fan, ret);
"pwm" has been reassigned to a percentage by this point, so either print 
the original 0–255 value (keep it in a separate variable) or label this 
one as a percentage.
> +		return ret;
> +	}
> +	xe_dbg(hwmon->xe, "applied fixed pwm %u for fan %d\n", clamped_pwm, fan);
> +
> +	/* Verify if the fan points are set */
> +	ret = xe_hwmon_get_fan_point_count(hwmon, fan, &point_count, USER_FAN_TABLE);
> +	if (ret && point_count == 0) {
On failure point_count is already 0, so && point_count == 0 seems to be 
redundant.
Instead could this be more usable :
if (ret || point_count != MIN_FAN_CONTROL_POINTS),  if the valid write 
needed to be checked ?

> +		xe_err(hwmon->xe, "pwm set verify failed for fan %d, ret=%d, point count=%u\n", fan,
> +		       ret, point_count);
> +		return ret;
> +	}
> +
> +	/* Update the user fan table cache. */
> +	for (i = 0; i < MIN_FAN_CONTROL_POINTS; i++) {
> +		fi->fan_table[USER_FAN_TABLE].fcp[i].temp = FIXED_PWM_TEMP + (i);
Drop the parentheses around i: FIXED_PWM_TEMP + i.
> +		fi->fan_table[USER_FAN_TABLE].fcp[i].speed = clamped_pwm;
> +		xe_dbg(hwmon->xe, "fan %d user table cache point %d with temp=%d, speed=%u\n", fan,
> +		       i, fi->fan_table[USER_FAN_TABLE].fcp[i].temp,
> +			  fi->fan_table[USER_FAN_TABLE].fcp[i].speed);
The arguments don't align under the opening (.
> +	}
> +	fi->fan_table[USER_FAN_TABLE].point_count = MIN_FAN_CONTROL_POINTS;
> +
> +	return 0;
> +}
> +
>   static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
>   {
>   	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
> @@ -1774,6 +1862,20 @@ xe_hwmon_fan_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
>   	}
>   }
>   
> +static umode_t
> +xe_hwmon_pwm_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
> +{
> +	if (!hwmon->xe->info.has_fan_control || !IS_FAN_ENABLED(channel))
> +		return 0;
> +
> +	switch (attr) {
> +	case hwmon_pwm_input:
> +		return 0644;
> +	default:
> +		return 0;
> +	}
> +}
> +
>   static int
>   xe_hwmon_fan_input_read(struct xe_hwmon *hwmon, int channel, long *val)
>   {
> @@ -1828,6 +1930,67 @@ xe_hwmon_fan_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
>   	}
>   }
>   
> +static int
> +xe_hwmon_pwm_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
> +{
> +	struct xe_hwmon_fan_info *fi;
> +	int ret = 0;
> +
> +	if (channel < 0 || channel >= FAN_MAX)
Add a short xe_dbg/xe_warn before these -EINVAL returns for clarity.
> +		return -EINVAL;
> +
> +	mutex_lock(&hwmon->hwmon_lock);
> +
> +	fi = &hwmon->fi[channel];
> +
> +	switch (attr) {
> +	case hwmon_pwm_input:
> +		/* Check if user fan table is set else activate it.*/
Where does it activate ? Use space before */.
> +		if (!fi->fan_table[USER_FAN_TABLE].point_count) {
> +			xe_warn(hwmon->xe, "pwm not set for fan %d\n", channel);
> +			ret = -ENXIO;
> +			goto unlock;
> +		}
> +		*val = DIV_ROUND_CLOSEST(fi->fan_table[USER_FAN_TABLE].fcp[0].speed * U8_MAX, 100);
The 0–255 <-> percentage round-trip is lossy for small values; Better to 
add a one-line note since the ABI says a full 0–255 range.
> +		xe_dbg(hwmon->xe, "pwm read for fan %d: %ld\n", channel, *val);
> +		break;
> +	default:
> +		ret = -EOPNOTSUPP;
> +		break;
> +	}
> +
> +unlock:
> +	mutex_unlock(&hwmon->hwmon_lock);
> +	return ret;
> +}
> +
> +static int
> +xe_hwmon_pwm_write(struct xe_hwmon *hwmon, u32 attr, int channel, long val)
> +{
> +	int ret = 0;
> +
> +	if (channel < 0 || channel >= FAN_MAX)

Add a short xe_dbg/xe_warn before these -EINVAL returns for clarity.


Regards,
Soham
> +		return -EINVAL;
> +
> +	mutex_lock(&hwmon->hwmon_lock);
> +
> +	switch (attr) {
> +	case hwmon_pwm_input:
> +		if (val < 0 || val > U8_MAX) {
> +			ret = -EINVAL;
> +			break;
> +		}
> +		ret = xe_hwmon_set_user_fan_pwm(hwmon, channel, (u8)val);
> +		break;
> +	default:
> +		ret = -EOPNOTSUPP;
> +		break;
> +	}
> +	mutex_unlock(&hwmon->hwmon_lock);
> +
> +	return ret;
> +}
> +
>   static umode_t
>   xe_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
>   		    u32 attr, int channel)
> @@ -1854,6 +2017,9 @@ xe_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
>   	case hwmon_fan:
>   		ret = xe_hwmon_fan_is_visible(hwmon, attr, channel);
>   		break;
> +	case hwmon_pwm:
> +		ret = xe_hwmon_pwm_is_visible(hwmon, attr, channel);
> +		break;
>   	default:
>   		ret = 0;
>   		break;
> @@ -1883,6 +2049,8 @@ xe_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
>   		return xe_hwmon_energy_read(hwmon, attr, channel, val);
>   	case hwmon_fan:
>   		return xe_hwmon_fan_read(hwmon, attr, channel, val);
> +	case hwmon_pwm:
> +		return xe_hwmon_pwm_read(hwmon, attr, channel, val);
>   	default:
>   		return -EOPNOTSUPP;
>   	}
> @@ -1901,6 +2069,8 @@ xe_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
>   		return xe_hwmon_power_write(hwmon, attr, channel, val);
>   	case hwmon_curr:
>   		return xe_hwmon_curr_write(hwmon, attr, channel, val);
> +	case hwmon_pwm:
> +		return xe_hwmon_pwm_write(hwmon, attr, channel, val);
>   	default:
>   		return -EOPNOTSUPP;
>   	}
> diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h
> index 32bac74c4281..80642bee0ac8 100644
> --- a/drivers/gpu/drm/xe/xe_pcode_api.h
> +++ b/drivers/gpu/drm/xe/xe_pcode_api.h
> @@ -82,9 +82,12 @@
>   #define     PCODE_MBOX_DOMAIN_HBM		0x2
>   
>   #define   FAN_SPEED_CONTROL			0x7D
> +#define     FSC_WRITE_NUM_FAN_CONTROL_POINTS	0x0
> +#define     FSC_WRITE_FAN_TABLE			0x1
>   #define     FSC_READ_MAX_FAN_RPS        0x3
>   #define     FSC_READ_NUM_FANS			0x4
>   #define     FSC_READ_STOCK_FAN_CONTROL_POINTS	0x5
> +#define     FSC_READ_USER_FAN_CONTROL_POINTS	0x6
>   #define     FSC_READ_FAN_TABLE			0x7
>   #define     FAN_CONTROL_POINT_TEMP_MASK		REG_GENMASK(7, 0)
>   #define     FAN_CONTROL_POINT_SPEED_MASK	REG_GENMASK(15, 8)

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

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

* Re: [PATCH v3 1/9] drm/xe/hwmon: initialize fan-control backend and table cache
  2026-10-28 18:46   ` Purkait, Soham
@ 2026-10-29 11:34     ` Poosa, Karthik
  2026-10-29 12:02       ` Purkait, Soham
  2026-10-29 12:04       ` Purkait, Soham
  0 siblings, 2 replies; 26+ messages in thread
From: Poosa, Karthik @ 2026-10-29 11:34 UTC (permalink / raw)
  To: Purkait, Soham, intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi,
	ravi.kishore.koppuravuri


On 29-10-2026 00:16, Purkait, Soham wrote:
>
> Hi Karthik,
>
> On 16-10-2026 00:37, Karthik Poosa wrote:
>> Initialize Xe hwmon fan-control support by detecting fan count,
>> reading stock fan control points and min PWM.
>>
>> v2:
>>   - Avoid user table initialization during probe. (Badal)
>>   - Move unused code to appropriate patches.
>>   - Use xe helpers for dmesg logs.
>>
>> v3:
>>   - Rebase.
>>   - Refine a few debug log messages and comments.
>>   - Update xe_hwmon_read_fan_control_info() to return on any stock table
>>     read failures.
>>   - Avoid returning when num_fans is 0 in
>>     xe_hwmon_get_preregistration_info(), ensuring thermal mailbox
>>     initialization is not skipped.
>>   - Remove XE_PCODE_FAN_CONTROL_TIMEOUT_MS which is unncessary as default
>>     timeout itself is now 10ms.
>>   - Use xe_pcode_read() instead of xe_pcode_read_timeout().
>>   - Rename fan_control_point_count to point_count in struct fan_table.
>>   - Resolve kgdoc warnings.
>>   - Add valid check for stock table fan point count.
>>   - Use the fan-enable bitmap reported by FSC_READ_NUM_FANS when enumerating
>>     fans. This avoids assuming contiguous fan indices and allows masks with
>>     gaps to be represented correctly in the hwmon interface.
>>
>> Signed-off-by: Karthik Poosa<karthik.poosa@intel.com>
>> Assisted-by: LLM
>> ---
>>   drivers/gpu/drm/xe/xe_hwmon.c     | 167 +++++++++++++++++++++++++++---
>>   drivers/gpu/drm/xe/xe_pcode_api.h |   5 +
>>   2 files changed, 157 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
>> index 42acfeb8818c..f2bd20f8b0a2 100644
>> --- a/drivers/gpu/drm/xe/xe_hwmon.c
>> +++ b/drivers/gpu/drm/xe/xe_hwmon.c
>> @@ -21,6 +21,7 @@
>>   #include "xe_pcode_api.h"
>>   #include "xe_sriov.h"
>>   #include "xe_pm.h"
>> +#include "xe_printk.h"
>>   #include "xe_vsec.h"
>>   #include "regs/xe_pmt.h"
>>   
>> @@ -137,14 +138,51 @@ struct xe_hwmon_energy_info {
>>   	long accum_energy;
>>   };
>>   
>> +enum fan_table_type {
>> +	/** @STOCK_FAN_TABLE: firmware-provided fan table */
>> +	STOCK_FAN_TABLE,
>> +	/** @USER_FAN_TABLE: user fan table written through sysfs */
>> +	USER_FAN_TABLE,
>> +	/** @FAN_TABLE_MAX: number of fan tables tracked per fan */
>> +	FAN_TABLE_MAX,
>> +};
>> +
>> +/* Check if a fan is enabled based on the fan_enable_mask got from FSC_READ_NUM_FANS. */
>> +#define IS_FAN_ENABLED(fan) (hwmon->fan_enable_mask & BIT(fan))
> If this macro is called from any function having no local variable 
> named hwmon it will break. Should it take hwmon as an argument ?
yes will change this
>> +
>> +/* Maximum number of fan control points supported by each fan. */
>> +#define MAX_FAN_CONTROL_POINTS	(10)
>> +
>> +/* Fan control point index: bit31 selects fan table type; bits30:0 control point index. */
>> +#define FCP_INDEX(FAN_TABLE_TYPE, POINT_NUM) (((FAN_TABLE_TYPE) << 31) | \
> Cast to u32 ? shifting the signed enum into bit 31 could lead to UB.
okay
>> +						((POINT_NUM) & REG_GENMASK(30, 0)))
>> +
>>   /**
>> - * struct xe_hwmon_fan_info - to cache previous fan reading
>> + * struct xe_hwmon_fan_info - cached fan telemetry and control state
>> + *
>> + * Each fan keeps the latest tachometer sampling state along with two fan
>> + * tables: the stock table discovered from firmware and the user table managed
>> + * by hwmon sysfs writes.
>>    */
>>   struct xe_hwmon_fan_info {
>>   	/** @reg_val_prev: previous fan reg val */
>>   	u32 reg_val_prev;
>>   	/** @time_prev: previous timestamp */
>>   	u64 time_prev;
>> +	/** @fan_table: fan control tables */
>> +	struct fan_table {
>> +		/** @point_count: number of fan control points */
>> +		u8 point_count;
>> +		/** @fcp: array of fan control points */
>> +		struct fan_control_point {
>> +			/** @temp: temperature in degree celsius */
>> +			u8 temp;
>> +			/** @speed: fan speed in percentage */
>> +			u8 speed;
>> +		} fcp[MAX_FAN_CONTROL_POINTS];
>> +	} fan_table[FAN_TABLE_MAX];
>> +	/** @min_pwm: minimum fan PWM */
>> +	u32 min_pwm;
>>   };
>>   
>>   /**
>> @@ -193,6 +231,8 @@ struct xe_hwmon {
>>   	int scl_shift_time;
>>   	/** @ei: Energy info for energyN_input */
>>   	struct xe_hwmon_energy_info ei[CHANNEL_MAX];
>> +	/** @fan_enable_mask: bitmask of available fans */
>> +	u32 fan_enable_mask;
>>   	/** @fi: Fan info for fanN_input */
>>   	struct xe_hwmon_fan_info fi[FAN_MAX];
>>   	/** @read_power_limit_from_pcode: pcode accepted power limits write for the channel */
>> @@ -1075,17 +1115,112 @@ static int xe_hwmon_pcode_write_i1(const struct xe_hwmon *hwmon, u32 uval)
>>   			      (uval & POWER_SETUP_I1_DATA_MASK));
>>   }
>>   
>> -static int xe_hwmon_pcode_read_fan_control(const struct xe_hwmon *hwmon, u32 subcmd, u32 *uval)
>> +static int xe_hwmon_pcode_read_fan_control(const struct xe_hwmon *hwmon, u32 subcmd, u8 fan_num,
>> +					   u32 *uval)
>>   {
>>   	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
> Nit: blank line after variable declaration
ok
>> +	return xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL, subcmd, fan_num),
>> +				     uval, NULL);
>> +}
>> +
>> +static int xe_hwmon_get_fan_enable_mask(struct xe_hwmon *hwmon)
>> +{
>> +	int ret;
>>   
>>   	/* Platforms that don't return correct value */
>> -	if (hwmon->xe->info.platform == XE_DG2 && subcmd == FSC_READ_NUM_FANS) {
>> -		*uval = 2;
>> +	if (hwmon->xe->info.platform == XE_DG2) {
>> +		hwmon->fan_enable_mask = GENMASK(1, 0);
>>   		return 0;
>>   	}
>>   
>> -	return xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL, subcmd, 0), uval, NULL);
>> +	ret = xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_NUM_FANS, 0,
>> +					      &hwmon->fan_enable_mask);
>> +	if (ret) {
>> +		xe_warn(hwmon->xe, "failed to read number of fans, ret=%d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	/* Check if fan mask exceeds FAN_MAX and log a warning if it does */
>> +	if (hwmon->fan_enable_mask & ~GENMASK(FAN_MAX - 1, 0)) {
>> +		xe_warn(hwmon->xe, "fan enable mask exceeds maximum supported fans\n");
> Reset the mask to 0 so IS_FAN_ENABLED() stays false in case fan mask 
> exceeds FAN_MAX.
how about clamping to FAN_MAX ?
>> +		return -EINVAL;
>> +	}
>> +
>> +	xe_info(hwmon->xe, "Number of fans detected: %u\n",
>> +		hweight32(hwmon->fan_enable_mask));
>> +	return 0;
>> +}
>> +
>> +static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
>> +{
>> +	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
>> +	int point;
>> +	int fan;
>> +	int ret;
>> +
>> +	for (fan = 0; fan < FAN_MAX; fan++) {
>> +		u32 stock_fcp_count = 0;
>> +
>> +		struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
>> +
>> +		if (!IS_FAN_ENABLED(fan))
>> +			continue;
>> +
>> +		ret = xe_hwmon_pcode_read_fan_control(hwmon,
>> +						      FSC_READ_STOCK_FAN_CONTROL_POINTS,
>> +						      fan, &stock_fcp_count);
>> +		if (ret) {
>> +			xe_err(hwmon->xe,
>> +			       "failed to read fan %d stock table point count, ret=%d\n",
>> +			       fan, ret);
> Why not continue for the rest of the fans marking the current one ?
yes we can continue, you want to mark current fan invalid ?
>> +			return ret;
>> +		}
>> +
>> +		if (!stock_fcp_count || stock_fcp_count > MAX_FAN_CONTROL_POINTS) {
>> +			xe_warn(hwmon->xe,
>> +				"fan %d stock table point count %u is invalid\n",
>> +				fan, stock_fcp_count);
> Ditto.
okay
>> +			return -EINVAL;
>> +		}
>> +
>> +		fi->fan_table[STOCK_FAN_TABLE].point_count = stock_fcp_count;
>> +		xe_dbg(hwmon->xe, "fan %d stock table point count is %u\n", fan,
>> +		       fi->fan_table[STOCK_FAN_TABLE].point_count);
>> +
>> +		/* Cache the stock fan table for later use. */
>> +		for (point = 0; point < fi->fan_table[STOCK_FAN_TABLE].point_count;
>> +		     point++) {
>> +			u32 fcp = 0;
>> +
>> +			fcp = FCP_INDEX(STOCK_FAN_TABLE, point);
>
> nit: u32 fcp = FCP_INDEX(STOCK_FAN_TABLE, point);
>
> Regards,
> Soham
ok
>> +			ret = xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL,
>> +								  FSC_READ_FAN_TABLE, fan),
>> +					    &fcp, NULL);
>> +			if (ret) {
>> +				xe_err(hwmon->xe, "failed to read fan %d stock point %d, ret=%d\n",
>> +				       fan, point, ret);
>> +				fi->fan_table[STOCK_FAN_TABLE].point_count = 0;
>> +				return ret;
>> +			}
>> +
>> +			fi->fan_table[STOCK_FAN_TABLE].fcp[point].temp =
>> +						REG_FIELD_GET(FAN_CONTROL_POINT_TEMP_MASK, fcp);
>> +			fi->fan_table[STOCK_FAN_TABLE].fcp[point].speed =
>> +						REG_FIELD_GET(FAN_CONTROL_POINT_SPEED_MASK, fcp);
>> +			xe_dbg(hwmon->xe, "fan %d stock point %d: temp %u C, speed %u\n",
>> +			       fan, point, fi->fan_table[STOCK_FAN_TABLE].fcp[point].temp,
>> +			       fi->fan_table[STOCK_FAN_TABLE].fcp[point].speed);
>> +		}
>> +
>> +		/* Read minimum fan PWM */
>> +		ret = xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_FAN_MIN_PWM, fan,
>> +						      &fi->min_pwm);
>> +		if (ret)
>> +			xe_warn(hwmon->xe, "fan %d min pwm unavailable, ret=%d\n", fan, ret);
>> +		else
>> +			xe_dbg(hwmon->xe, "fan %d min PWM %u\n", fan, fi->min_pwm);
>> +	}
>> +	return 0;
>>   }
>>   
>>   static int xe_hwmon_power_curr_crit_read(struct xe_hwmon *hwmon, int channel,
>> @@ -1615,17 +1750,12 @@ xe_hwmon_energy_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
>>   static umode_t
>>   xe_hwmon_fan_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
>>   {
>> -	u32 uval = 0;
>> -
>>   	if (!hwmon->xe->info.has_fan_control)
>>   		return 0;
>>   
>>   	switch (attr) {
>>   	case hwmon_fan_input:
>> -		if (xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_NUM_FANS, &uval))
>> -			return 0;
>> -
>> -		return channel < uval ? 0444 : 0;
>> +		return IS_FAN_ENABLED(channel) ? 0444 : 0;
>>   	default:
>>   		return 0;
>>   	}
>> @@ -1858,11 +1988,18 @@ xe_hwmon_get_preregistration_info(struct xe_hwmon *hwmon)
>>   		if (xe_hwmon_is_visible(hwmon, hwmon_energy, hwmon_energy_input, channel))
>>   			xe_hwmon_energy_get(hwmon, channel, &energy);
>>   
>> -	/* Initialize 'struct xe_hwmon_fan_info' with initial fan register reading. */
>> -	for (channel = 0; channel < FAN_MAX; channel++)
>> -		if (xe_hwmon_is_visible(hwmon, hwmon_fan, hwmon_fan_input, channel))
>> -			xe_hwmon_fan_input_read(hwmon, channel, &fan_speed);
>> +	if (hwmon->xe->info.has_fan_control) {
>> +		xe_hwmon_get_fan_enable_mask(hwmon);
>> +
>> +		/* Initialize 'struct xe_hwmon_fan_info' with initial fan register reading. */
>> +		for (channel = 0; channel < FAN_MAX; channel++)
>> +			if (IS_FAN_ENABLED(channel))
>> +				xe_hwmon_fan_input_read(hwmon, channel, &fan_speed);
>>   
>> +		/* Fan control tables initialization */
>> +		if (xe_hwmon_read_fan_control_info(hwmon))
>> +			xe_warn(hwmon->xe, "Fan control tables are not available\n");
>> +	}
>>   	return xe_hwmon_init_temp_info(hwmon);
>>   }
>>   
>> diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h
>> index 00c4fc7d0124..0349b24a8259 100644
>> --- a/drivers/gpu/drm/xe/xe_pcode_api.h
>> +++ b/drivers/gpu/drm/xe/xe_pcode_api.h
>> @@ -83,6 +83,11 @@
>>   
>>   #define   FAN_SPEED_CONTROL			0x7D
>>   #define     FSC_READ_NUM_FANS			0x4
>> +#define     FSC_READ_STOCK_FAN_CONTROL_POINTS	0x5
>> +#define     FSC_READ_FAN_TABLE			0x7
>> +#define     FAN_CONTROL_POINT_TEMP_MASK		REG_GENMASK(7, 0)
>> +#define     FAN_CONTROL_POINT_SPEED_MASK	REG_GENMASK(15, 8)
>> +#define     FSC_READ_FAN_MIN_PWM		0x8
>>   
>>   #define PCODE_SCRATCH(x)		XE_REG(0x138320 + ((x) * 4))
>>   /* PCODE_SCRATCH0 */

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

* Re: [PATCH v3 2/9] drm/xe/hwmon: expose fanN_max
  2026-10-29  4:35   ` Purkait, Soham
@ 2026-10-29 11:39     ` Poosa, Karthik
  0 siblings, 0 replies; 26+ messages in thread
From: Poosa, Karthik @ 2026-10-29 11:39 UTC (permalink / raw)
  To: Purkait, Soham, intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi,
	ravi.kishore.koppuravuri


On 29-10-2026 10:05, Purkait, Soham wrote:
> Hi Karthik,
>
> On 16-10-2026 00:37, Karthik Poosa wrote:
>> Expose fan maximum RPM via fanN_max.
>>
>> The value is derived from the firmware-reported maximum fan RPS and
>> converted to RPM in the fan hwmon read path.
>>
>> Update Xe hwmon ABI documentation for fanN_max.
>>
>> v2: Use xe helper for dmesg logs.
>>
>> v3:
>>   - Fix indentation of the max_rps struct member.
>>   - Enable fanN_max only when fanN is supported.
>>
>> Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
>> Assisted-by: LLM
>> ---
>>   .../ABI/testing/sysfs-driver-intel-xe-hwmon   |  8 ++++++++
>>   drivers/gpu/drm/xe/xe_hwmon.c                 | 19 ++++++++++++++++++-
>>   drivers/gpu/drm/xe/xe_pcode_api.h             |  1 +
>>   3 files changed, 27 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon 
>> b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
>> index 0da739d9a816..5ee68aefa485 100644
>> --- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
>> +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
>> @@ -266,6 +266,14 @@ Description:    RO. Fan 3 speed in RPM.
>>             Only supported for particular Intel Xe graphics platforms.
>>   +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/fan[1-3]_max
>> +Date:           October 2026
>> +KernelVersion:  7.3
>> +Contact:        intel-xe@lists.freedesktop.org
>> +Description:    RO. Maximum fan speed in RPM for each fan channel.
>> +
>> +                Only supported for particular Intel Xe graphics 
>> platforms.
>> +
> Use tab indentation.
ok
>>   What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/power1_cap
>>   Date:        May 2025
>>   KernelVersion:    6.15
>> diff --git a/drivers/gpu/drm/xe/xe_hwmon.c 
>> b/drivers/gpu/drm/xe/xe_hwmon.c
>> index f2bd20f8b0a2..32016c5d4770 100644
>> --- a/drivers/gpu/drm/xe/xe_hwmon.c
>> +++ b/drivers/gpu/drm/xe/xe_hwmon.c
>> @@ -181,6 +181,8 @@ struct xe_hwmon_fan_info {
>>               u8 speed;
>>           } fcp[MAX_FAN_CONTROL_POINTS];
>>       } fan_table[FAN_TABLE_MAX];
>> +    /** @max_rps: maximum fan RPS */
>> +    u32 max_rps;
>>       /** @min_pwm: minimum fan PWM */
>>       u32 min_pwm;
>>   };
>> @@ -909,7 +911,8 @@ static const struct hwmon_channel_info * const 
>> hwmon_info[] = {
>>       HWMON_CHANNEL_INFO(curr, HWMON_C_LABEL, HWMON_C_CRIT | 
>> HWMON_C_LABEL),
>>       HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LABEL, 
>> HWMON_I_INPUT | HWMON_I_LABEL),
>>       HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT | HWMON_E_LABEL, 
>> HWMON_E_INPUT | HWMON_E_LABEL),
>> -    HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT, HWMON_F_INPUT, 
>> HWMON_F_INPUT),
>> +    HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_MAX, 
>> HWMON_F_INPUT | HWMON_F_MAX,
>> +               HWMON_F_INPUT | HWMON_F_MAX),
>>       NULL
>>   };
>>   @@ -1219,6 +1222,14 @@ static int 
>> xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
>>               xe_warn(hwmon->xe, "fan %d min pwm unavailable, 
>> ret=%d\n", fan, ret);
>>           else
>>               xe_dbg(hwmon->xe, "fan %d min PWM %u\n", fan, 
>> fi->min_pwm);
>> +
>> +        /* Read max fan RPS*/
> Add a space before */
ok
>> +        ret = xe_hwmon_pcode_read_fan_control(hwmon, 
>> FSC_READ_MAX_FAN_RPS, fan,
>> +                              &fi->max_rps);
>> +        if (ret)
> Should fi->max_rps be set to 0 on read failure so the attribute is 
> correctly hidden on re-read ?
not needed as fi->max_rps will be filled only if read passed,

see __pcode_mailbox_rw()
  90         err = xe_mmio_wait32(mmio, PCODE_MAILBOX, PCODE_READY, 0,
  91                              timeout_ms * USEC_PER_MSEC, NULL, atomic);
  92         if (err)
  93                 return err;
  94
  95         if (return_data) {
  96                 *data0 = xe_mmio_read32(mmio, PCODE_DATA0);
  97                 if (data1)
  98                         *data1 = xe_mmio_read32(mmio, PCODE_DATA1);
  99         }


>> +            xe_warn(hwmon->xe, "failed to read fan %d max RPS, 
>> ret=%d\n", fan, ret);
>> +        else
>> +            xe_dbg(hwmon->xe, "fan %d max RPS %u\n", fan, fi->max_rps);
>>       }
>>       return 0;
>>   }
>> @@ -1756,6 +1767,8 @@ xe_hwmon_fan_is_visible(struct xe_hwmon *hwmon, 
>> u32 attr, int channel)
>>       switch (attr) {
>>       case hwmon_fan_input:
>>           return IS_FAN_ENABLED(channel) ? 0444 : 0;
>> +    case hwmon_fan_max:
>> +        return IS_FAN_ENABLED(channel) && hwmon->fi[channel].max_rps 
>> ? 0444 : 0;
>>       default:
>>           return 0;
>>       }
>> @@ -1806,6 +1819,10 @@ xe_hwmon_fan_read(struct xe_hwmon *hwmon, u32 
>> attr, int channel, long *val)
>>       switch (attr) {
>>       case hwmon_fan_input:
>>           return xe_hwmon_fan_input_read(hwmon, channel, val);
>> +    case hwmon_fan_max:
>> +        /* Convert RPS to RPM */
>> +        *val = (long)hwmon->fi[channel].max_rps * 60;
>> +        return 0;
>>       default:
>>           return -EOPNOTSUPP;
>>       }
>> diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h 
>> b/drivers/gpu/drm/xe/xe_pcode_api.h
>> index 0349b24a8259..32bac74c4281 100644
>> --- a/drivers/gpu/drm/xe/xe_pcode_api.h
>> +++ b/drivers/gpu/drm/xe/xe_pcode_api.h
>> @@ -82,6 +82,7 @@
>>   #define     PCODE_MBOX_DOMAIN_HBM        0x2
>>     #define   FAN_SPEED_CONTROL            0x7D
>> +#define     FSC_READ_MAX_FAN_RPS        0x3
>
> Nit: alignment.
>
> Regards,
> Soham
>>   #define     FSC_READ_NUM_FANS 0x4
>>   #define     FSC_READ_STOCK_FAN_CONTROL_POINTS    0x5
>>   #define     FSC_READ_FAN_TABLE            0x7

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

* Re: [PATCH v3 3/9] drm/xe/pcode: add ordered write batch helper
  2026-10-29  5:45   ` Purkait, Soham
@ 2026-10-29 11:40     ` Poosa, Karthik
  0 siblings, 0 replies; 26+ messages in thread
From: Poosa, Karthik @ 2026-10-29 11:40 UTC (permalink / raw)
  To: Purkait, Soham, intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi,
	ravi.kishore.koppuravuri


On 29-10-2026 11:15, Purkait, Soham wrote:
> Hi Karthik,
>
> On 16-10-2026 00:37, Karthik Poosa wrote:
>> Provide a pcode write helper that keeps the mailbox lock held while 
>> issuing
>> an ordered sequence of writes.
>> This will be used while writing the fan table ensuring that is not
>> interleaved by any other pcode mailbox command.
>>
>> Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
>> ---
>>   drivers/gpu/drm/xe/xe_pcode.c | 20 ++++++++++++++++++++
>>   drivers/gpu/drm/xe/xe_pcode.h |  7 +++++++
>>   2 files changed, 27 insertions(+)
>>
>> diff --git a/drivers/gpu/drm/xe/xe_pcode.c 
>> b/drivers/gpu/drm/xe/xe_pcode.c
>> index 266deecbb100..ca107b0234d9 100644
>> --- a/drivers/gpu/drm/xe/xe_pcode.c
>> +++ b/drivers/gpu/drm/xe/xe_pcode.c
>> @@ -124,6 +124,26 @@ int xe_pcode_write_timeout(struct xe_tile *tile, 
>> u32 mbox, u32 data, int timeout
>>       return err;
>>   }
>>   +int xe_pcode_write_batch(struct xe_tile *tile, const struct 
>> xe_pcode_write *writes,
>> +             unsigned int count)
>> +{
>> +    unsigned int i;
>> +    int err = 0;
>> +
>> +    mutex_lock(&tile->pcode.lock);
> nit: if count == 0 then return immediately without acquiring the mutex.
ok
>> +    for (i = 0; i < count; i++) {
>> +        u32 data = writes[i].data;
>> +
>> +        err = pcode_mailbox_rw(tile, writes[i].mbox, &data, NULL, 
>> PCODE_DEFAULT_TIMEOUT_MS,
>> +                       false, false);
>> +        if (err)
>
> Use a debug print in case of failure for clarity.
>
> Regards,
ok, we could print which cmd out of the batch failed.
> Soham
>> +            break;
>> +    }
>> +    mutex_unlock(&tile->pcode.lock);
>> +
>> +    return err;
>> +}
>> +
>>   int xe_pcode_write64_timeout(struct xe_tile *tile, u32 mbox, u32 
>> data0, u32 data1, int timeout)
>>   {
>>       int err;
>> diff --git a/drivers/gpu/drm/xe/xe_pcode.h 
>> b/drivers/gpu/drm/xe/xe_pcode.h
>> index 7e43792b0037..74bd553ab390 100644
>> --- a/drivers/gpu/drm/xe/xe_pcode.h
>> +++ b/drivers/gpu/drm/xe/xe_pcode.h
>> @@ -18,6 +18,11 @@ struct xe_pcode_version {
>>       u32 engg;
>>   };
>>   +struct xe_pcode_write {
>> +    u32 mbox;
>> +    u32 data;
>> +};
>> +
>>   #define PCODE_DEFAULT_TIMEOUT_MS    10
>>     int xe_pcode_init_early(struct xe_tile *tile);
>> @@ -28,6 +33,8 @@ int xe_pcode_init_min_freq_table(struct xe_tile 
>> *tile, u32 min_gt_freq,
>>   int xe_pcode_read(struct xe_tile *tile, u32 mbox, u32 *val0, u32 
>> *val1);
>>   int xe_pcode_write_timeout(struct xe_tile *tile, u32 mbox, u32 val,
>>                  int timeout_ms);
>> +int xe_pcode_write_batch(struct xe_tile *tile, const struct 
>> xe_pcode_write *writes,
>> +             unsigned int count);
>>   int xe_pcode_write64_timeout(struct xe_tile *tile, u32 mbox, u32 
>> data0,
>>                    u32 data1, int timeout);
>>   int xe_get_pcode_version(struct xe_device *xe, struct 
>> xe_pcode_version *version);

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

* Re: [PATCH v3 1/9] drm/xe/hwmon: initialize fan-control backend and table cache
  2026-10-29 11:34     ` Poosa, Karthik
@ 2026-10-29 12:02       ` Purkait, Soham
  2026-10-29 12:04       ` Purkait, Soham
  1 sibling, 0 replies; 26+ messages in thread
From: Purkait, Soham @ 2026-10-29 12:02 UTC (permalink / raw)
  To: Poosa, Karthik, intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi,
	ravi.kishore.koppuravuri


On 29-10-2026 17:04, Poosa, Karthik wrote:
>
> On 29-10-2026 00:16, Purkait, Soham wrote:
>>
>> Hi Karthik,
>>
>> On 16-10-2026 00:37, Karthik Poosa wrote:
>>> Initialize Xe hwmon fan-control support by detecting fan count,
>>> reading stock fan control points and min PWM.
>>>
>>> v2:
>>>   - Avoid user table initialization during probe. (Badal)
>>>   - Move unused code to appropriate patches.
>>>   - Use xe helpers for dmesg logs.
>>>
>>> v3:
>>>   - Rebase.
>>>   - Refine a few debug log messages and comments.
>>>   - Update xe_hwmon_read_fan_control_info() to return on any stock 
>>> table
>>>     read failures.
>>>   - Avoid returning when num_fans is 0 in
>>>     xe_hwmon_get_preregistration_info(), ensuring thermal mailbox
>>>     initialization is not skipped.
>>>   - Remove XE_PCODE_FAN_CONTROL_TIMEOUT_MS which is unncessary as 
>>> default
>>>     timeout itself is now 10ms.
>>>   - Use xe_pcode_read() instead of xe_pcode_read_timeout().
>>>   - Rename fan_control_point_count to point_count in struct fan_table.
>>>   - Resolve kgdoc warnings.
>>>   - Add valid check for stock table fan point count.
>>>   - Use the fan-enable bitmap reported by FSC_READ_NUM_FANS when 
>>> enumerating
>>>     fans. This avoids assuming contiguous fan indices and allows 
>>> masks with
>>>     gaps to be represented correctly in the hwmon interface.
>>>
>>> Signed-off-by: Karthik Poosa<karthik.poosa@intel.com>
>>> Assisted-by: LLM
>>> ---
>>>   drivers/gpu/drm/xe/xe_hwmon.c     | 167 
>>> +++++++++++++++++++++++++++---
>>>   drivers/gpu/drm/xe/xe_pcode_api.h |   5 +
>>>   2 files changed, 157 insertions(+), 15 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/xe/xe_hwmon.c 
>>> b/drivers/gpu/drm/xe/xe_hwmon.c
>>> index 42acfeb8818c..f2bd20f8b0a2 100644
>>> --- a/drivers/gpu/drm/xe/xe_hwmon.c
>>> +++ b/drivers/gpu/drm/xe/xe_hwmon.c
>>> @@ -21,6 +21,7 @@
>>>   #include "xe_pcode_api.h"
>>>   #include "xe_sriov.h"
>>>   #include "xe_pm.h"
>>> +#include "xe_printk.h"
>>>   #include "xe_vsec.h"
>>>   #include "regs/xe_pmt.h"
>>>   @@ -137,14 +138,51 @@ struct xe_hwmon_energy_info {
>>>       long accum_energy;
>>>   };
>>>   +enum fan_table_type {
>>> +    /** @STOCK_FAN_TABLE: firmware-provided fan table */
>>> +    STOCK_FAN_TABLE,
>>> +    /** @USER_FAN_TABLE: user fan table written through sysfs */
>>> +    USER_FAN_TABLE,
>>> +    /** @FAN_TABLE_MAX: number of fan tables tracked per fan */
>>> +    FAN_TABLE_MAX,
>>> +};
>>> +
>>> +/* Check if a fan is enabled based on the fan_enable_mask got from 
>>> FSC_READ_NUM_FANS. */
>>> +#define IS_FAN_ENABLED(fan) (hwmon->fan_enable_mask & BIT(fan))
>> If this macro is called from any function having no local variable 
>> named hwmon it will break. Should it take hwmon as an argument ?
> yes will change this
>>> +
>>> +/* Maximum number of fan control points supported by each fan. */
>>> +#define MAX_FAN_CONTROL_POINTS    (10)
>>> +
>>> +/* Fan control point index: bit31 selects fan table type; bits30:0 
>>> control point index. */
>>> +#define FCP_INDEX(FAN_TABLE_TYPE, POINT_NUM) (((FAN_TABLE_TYPE) << 
>>> 31) | \
>> Cast to u32 ? shifting the signed enum into bit 31 could lead to UB.
> okay
>>> +                        ((POINT_NUM) & REG_GENMASK(30, 0)))
>>> +
>>>   /**
>>> - * struct xe_hwmon_fan_info - to cache previous fan reading
>>> + * struct xe_hwmon_fan_info - cached fan telemetry and control state
>>> + *
>>> + * Each fan keeps the latest tachometer sampling state along with 
>>> two fan
>>> + * tables: the stock table discovered from firmware and the user 
>>> table managed
>>> + * by hwmon sysfs writes.
>>>    */
>>>   struct xe_hwmon_fan_info {
>>>       /** @reg_val_prev: previous fan reg val */
>>>       u32 reg_val_prev;
>>>       /** @time_prev: previous timestamp */
>>>       u64 time_prev;
>>> +    /** @fan_table: fan control tables */
>>> +    struct fan_table {
>>> +        /** @point_count: number of fan control points */
>>> +        u8 point_count;
>>> +        /** @fcp: array of fan control points */
>>> +        struct fan_control_point {
>>> +            /** @temp: temperature in degree celsius */
>>> +            u8 temp;
>>> +            /** @speed: fan speed in percentage */
>>> +            u8 speed;
>>> +        } fcp[MAX_FAN_CONTROL_POINTS];
>>> +    } fan_table[FAN_TABLE_MAX];
>>> +    /** @min_pwm: minimum fan PWM */
>>> +    u32 min_pwm;
>>>   };
>>>     /**
>>> @@ -193,6 +231,8 @@ struct xe_hwmon {
>>>       int scl_shift_time;
>>>       /** @ei: Energy info for energyN_input */
>>>       struct xe_hwmon_energy_info ei[CHANNEL_MAX];
>>> +    /** @fan_enable_mask: bitmask of available fans */
>>> +    u32 fan_enable_mask;
>>>       /** @fi: Fan info for fanN_input */
>>>       struct xe_hwmon_fan_info fi[FAN_MAX];
>>>       /** @read_power_limit_from_pcode: pcode accepted power limits 
>>> write for the channel */
>>> @@ -1075,17 +1115,112 @@ static int xe_hwmon_pcode_write_i1(const 
>>> struct xe_hwmon *hwmon, u32 uval)
>>>                     (uval & POWER_SETUP_I1_DATA_MASK));
>>>   }
>>>   -static int xe_hwmon_pcode_read_fan_control(const struct xe_hwmon 
>>> *hwmon, u32 subcmd, u32 *uval)
>>> +static int xe_hwmon_pcode_read_fan_control(const struct xe_hwmon 
>>> *hwmon, u32 subcmd, u8 fan_num,
>>> +                       u32 *uval)
>>>   {
>>>       struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
>> Nit: blank line after variable declaration
> ok
>>> +    return xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL, 
>>> subcmd, fan_num),
>>> +                     uval, NULL);
>>> +}
>>> +
>>> +static int xe_hwmon_get_fan_enable_mask(struct xe_hwmon *hwmon)
>>> +{
>>> +    int ret;
>>>         /* Platforms that don't return correct value */
>>> -    if (hwmon->xe->info.platform == XE_DG2 && subcmd == 
>>> FSC_READ_NUM_FANS) {
>>> -        *uval = 2;
>>> +    if (hwmon->xe->info.platform == XE_DG2) {
>>> +        hwmon->fan_enable_mask = GENMASK(1, 0);
>>>           return 0;
>>>       }
>>>   -    return xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL, 
>>> subcmd, 0), uval, NULL);
>>> +    ret = xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_NUM_FANS, 0,
>>> +                          &hwmon->fan_enable_mask);
>>> +    if (ret) {
>>> +        xe_warn(hwmon->xe, "failed to read number of fans, 
>>> ret=%d\n", ret);
>>> +        return ret;
>>> +    }
>>> +
>>> +    /* Check if fan mask exceeds FAN_MAX and log a warning if it 
>>> does */
>>> +    if (hwmon->fan_enable_mask & ~GENMASK(FAN_MAX - 1, 0)) {
>>> +        xe_warn(hwmon->xe, "fan enable mask exceeds maximum 
>>> supported fans\n");
>> Reset the mask to 0 so IS_FAN_ENABLED() stays false in case fan mask 
>> exceeds FAN_MAX.
> how about clamping to FAN_MAX ?
Clamping might be a better option. In that case the warning should state 
that the extra bits are being dropped.
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    xe_info(hwmon->xe, "Number of fans detected: %u\n",
>>> +        hweight32(hwmon->fan_enable_mask));
>>> +    return 0;
>>> +}
>>> +
>>> +static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
>>> +{
>>> +    struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
>>> +    int point;
>>> +    int fan;
>>> +    int ret;
>>> +
>>> +    for (fan = 0; fan < FAN_MAX; fan++) {
>>> +        u32 stock_fcp_count = 0;
>>> +
>>> +        struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
>>> +
>>> +        if (!IS_FAN_ENABLED(fan))
>>> +            continue;
>>> +
>>> +        ret = xe_hwmon_pcode_read_fan_control(hwmon,
>>> + FSC_READ_STOCK_FAN_CONTROL_POINTS,
>>> +                              fan, &stock_fcp_count);
>>> +        if (ret) {
>>> +            xe_err(hwmon->xe,
>>> +                   "failed to read fan %d stock table point count, 
>>> ret=%d\n",
>>> +                   fan, ret);
>> Why not continue for the rest of the fans marking the current one ?
> yes we can continue, you want to mark current fan invalid ?
>>> +            return ret;
>>> +        }
>>> +
>>> +        if (!stock_fcp_count || stock_fcp_count > 
>>> MAX_FAN_CONTROL_POINTS) {
>>> +            xe_warn(hwmon->xe,
>>> +                "fan %d stock table point count %u is invalid\n",
>>> +                fan, stock_fcp_count);
>> Ditto.
> okay
>>> +            return -EINVAL;
>>> +        }
>>> +
>>> +        fi->fan_table[STOCK_FAN_TABLE].point_count = stock_fcp_count;
>>> +        xe_dbg(hwmon->xe, "fan %d stock table point count is %u\n", 
>>> fan,
>>> + fi->fan_table[STOCK_FAN_TABLE].point_count);
>>> +
>>> +        /* Cache the stock fan table for later use. */
>>> +        for (point = 0; point < 
>>> fi->fan_table[STOCK_FAN_TABLE].point_count;
>>> +             point++) {
>>> +            u32 fcp = 0;
>>> +
>>> +            fcp = FCP_INDEX(STOCK_FAN_TABLE, point);
>>
>> nit: u32 fcp = FCP_INDEX(STOCK_FAN_TABLE, point);
>>
>> Regards,
>> Soham
> ok
>>> +            ret = xe_pcode_read(root_tile, 
>>> PCODE_MBOX(FAN_SPEED_CONTROL,
>>> +                                  FSC_READ_FAN_TABLE, fan),
>>> +                        &fcp, NULL);
>>> +            if (ret) {
>>> +                xe_err(hwmon->xe, "failed to read fan %d stock 
>>> point %d, ret=%d\n",
>>> +                       fan, point, ret);
>>> +                fi->fan_table[STOCK_FAN_TABLE].point_count = 0;
>>> +                return ret;
>>> +            }
>>> +
>>> +            fi->fan_table[STOCK_FAN_TABLE].fcp[point].temp =
>>> + REG_FIELD_GET(FAN_CONTROL_POINT_TEMP_MASK, fcp);
>>> + fi->fan_table[STOCK_FAN_TABLE].fcp[point].speed =
>>> + REG_FIELD_GET(FAN_CONTROL_POINT_SPEED_MASK, fcp);
>>> +            xe_dbg(hwmon->xe, "fan %d stock point %d: temp %u C, 
>>> speed %u\n",
>>> +                   fan, point, 
>>> fi->fan_table[STOCK_FAN_TABLE].fcp[point].temp,
>>> + fi->fan_table[STOCK_FAN_TABLE].fcp[point].speed);
>>> +        }
>>> +
>>> +        /* Read minimum fan PWM */
>>> +        ret = xe_hwmon_pcode_read_fan_control(hwmon, 
>>> FSC_READ_FAN_MIN_PWM, fan,
>>> +                              &fi->min_pwm);
>>> +        if (ret)
>>> +            xe_warn(hwmon->xe, "fan %d min pwm unavailable, 
>>> ret=%d\n", fan, ret);
>>> +        else
>>> +            xe_dbg(hwmon->xe, "fan %d min PWM %u\n", fan, 
>>> fi->min_pwm);
>>> +    }
>>> +    return 0;
>>>   }
>>>     static int xe_hwmon_power_curr_crit_read(struct xe_hwmon *hwmon, 
>>> int channel,
>>> @@ -1615,17 +1750,12 @@ xe_hwmon_energy_read(struct xe_hwmon *hwmon, 
>>> u32 attr, int channel, long *val)
>>>   static umode_t
>>>   xe_hwmon_fan_is_visible(struct xe_hwmon *hwmon, u32 attr, int 
>>> channel)
>>>   {
>>> -    u32 uval = 0;
>>> -
>>>       if (!hwmon->xe->info.has_fan_control)
>>>           return 0;
>>>         switch (attr) {
>>>       case hwmon_fan_input:
>>> -        if (xe_hwmon_pcode_read_fan_control(hwmon, 
>>> FSC_READ_NUM_FANS, &uval))
>>> -            return 0;
>>> -
>>> -        return channel < uval ? 0444 : 0;
>>> +        return IS_FAN_ENABLED(channel) ? 0444 : 0;
>>>       default:
>>>           return 0;
>>>       }
>>> @@ -1858,11 +1988,18 @@ xe_hwmon_get_preregistration_info(struct 
>>> xe_hwmon *hwmon)
>>>           if (xe_hwmon_is_visible(hwmon, hwmon_energy, 
>>> hwmon_energy_input, channel))
>>>               xe_hwmon_energy_get(hwmon, channel, &energy);
>>>   -    /* Initialize 'struct xe_hwmon_fan_info' with initial fan 
>>> register reading. */
>>> -    for (channel = 0; channel < FAN_MAX; channel++)
>>> -        if (xe_hwmon_is_visible(hwmon, hwmon_fan, hwmon_fan_input, 
>>> channel))
>>> -            xe_hwmon_fan_input_read(hwmon, channel, &fan_speed);
>>> +    if (hwmon->xe->info.has_fan_control) {
>>> +        xe_hwmon_get_fan_enable_mask(hwmon);
>>> +
>>> +        /* Initialize 'struct xe_hwmon_fan_info' with initial fan 
>>> register reading. */
>>> +        for (channel = 0; channel < FAN_MAX; channel++)
>>> +            if (IS_FAN_ENABLED(channel))
>>> +                xe_hwmon_fan_input_read(hwmon, channel, &fan_speed);
>>>   +        /* Fan control tables initialization */
>>> +        if (xe_hwmon_read_fan_control_info(hwmon))
>>> +            xe_warn(hwmon->xe, "Fan control tables are not 
>>> available\n");
>>> +    }
>>>       return xe_hwmon_init_temp_info(hwmon);
>>>   }
>>>   diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h 
>>> b/drivers/gpu/drm/xe/xe_pcode_api.h
>>> index 00c4fc7d0124..0349b24a8259 100644
>>> --- a/drivers/gpu/drm/xe/xe_pcode_api.h
>>> +++ b/drivers/gpu/drm/xe/xe_pcode_api.h
>>> @@ -83,6 +83,11 @@
>>>     #define   FAN_SPEED_CONTROL            0x7D
>>>   #define     FSC_READ_NUM_FANS            0x4
>>> +#define     FSC_READ_STOCK_FAN_CONTROL_POINTS    0x5
>>> +#define     FSC_READ_FAN_TABLE            0x7
>>> +#define     FAN_CONTROL_POINT_TEMP_MASK        REG_GENMASK(7, 0)
>>> +#define     FAN_CONTROL_POINT_SPEED_MASK    REG_GENMASK(15, 8)
>>> +#define     FSC_READ_FAN_MIN_PWM        0x8
>>>     #define PCODE_SCRATCH(x)        XE_REG(0x138320 + ((x) * 4))
>>>   /* PCODE_SCRATCH0 */

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

* Re: [PATCH v3 1/9] drm/xe/hwmon: initialize fan-control backend and table cache
  2026-10-29 11:34     ` Poosa, Karthik
  2026-10-29 12:02       ` Purkait, Soham
@ 2026-10-29 12:04       ` Purkait, Soham
  1 sibling, 0 replies; 26+ messages in thread
From: Purkait, Soham @ 2026-10-29 12:04 UTC (permalink / raw)
  To: Poosa, Karthik, intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi,
	ravi.kishore.koppuravuri


On 29-10-2026 17:04, Poosa, Karthik wrote:
>
> On 29-10-2026 00:16, Purkait, Soham wrote:
>>
>> Hi Karthik,
>>
>> On 16-10-2026 00:37, Karthik Poosa wrote:
>>> Initialize Xe hwmon fan-control support by detecting fan count,
>>> reading stock fan control points and min PWM.
>>>
>>> v2:
>>>   - Avoid user table initialization during probe. (Badal)
>>>   - Move unused code to appropriate patches.
>>>   - Use xe helpers for dmesg logs.
>>>
>>> v3:
>>>   - Rebase.
>>>   - Refine a few debug log messages and comments.
>>>   - Update xe_hwmon_read_fan_control_info() to return on any stock 
>>> table
>>>     read failures.
>>>   - Avoid returning when num_fans is 0 in
>>>     xe_hwmon_get_preregistration_info(), ensuring thermal mailbox
>>>     initialization is not skipped.
>>>   - Remove XE_PCODE_FAN_CONTROL_TIMEOUT_MS which is unncessary as 
>>> default
>>>     timeout itself is now 10ms.
>>>   - Use xe_pcode_read() instead of xe_pcode_read_timeout().
>>>   - Rename fan_control_point_count to point_count in struct fan_table.
>>>   - Resolve kgdoc warnings.
>>>   - Add valid check for stock table fan point count.
>>>   - Use the fan-enable bitmap reported by FSC_READ_NUM_FANS when 
>>> enumerating
>>>     fans. This avoids assuming contiguous fan indices and allows 
>>> masks with
>>>     gaps to be represented correctly in the hwmon interface.
>>>
>>> Signed-off-by: Karthik Poosa<karthik.poosa@intel.com>
>>> Assisted-by: LLM
>>> ---
>>>   drivers/gpu/drm/xe/xe_hwmon.c     | 167 
>>> +++++++++++++++++++++++++++---
>>>   drivers/gpu/drm/xe/xe_pcode_api.h |   5 +
>>>   2 files changed, 157 insertions(+), 15 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/xe/xe_hwmon.c 
>>> b/drivers/gpu/drm/xe/xe_hwmon.c
>>> index 42acfeb8818c..f2bd20f8b0a2 100644
>>> --- a/drivers/gpu/drm/xe/xe_hwmon.c
>>> +++ b/drivers/gpu/drm/xe/xe_hwmon.c
>>> @@ -21,6 +21,7 @@
>>>   #include "xe_pcode_api.h"
>>>   #include "xe_sriov.h"
>>>   #include "xe_pm.h"
>>> +#include "xe_printk.h"
>>>   #include "xe_vsec.h"
>>>   #include "regs/xe_pmt.h"
>>>   @@ -137,14 +138,51 @@ struct xe_hwmon_energy_info {
>>>       long accum_energy;
>>>   };
>>>   +enum fan_table_type {
>>> +    /** @STOCK_FAN_TABLE: firmware-provided fan table */
>>> +    STOCK_FAN_TABLE,
>>> +    /** @USER_FAN_TABLE: user fan table written through sysfs */
>>> +    USER_FAN_TABLE,
>>> +    /** @FAN_TABLE_MAX: number of fan tables tracked per fan */
>>> +    FAN_TABLE_MAX,
>>> +};
>>> +
>>> +/* Check if a fan is enabled based on the fan_enable_mask got from 
>>> FSC_READ_NUM_FANS. */
>>> +#define IS_FAN_ENABLED(fan) (hwmon->fan_enable_mask & BIT(fan))
>> If this macro is called from any function having no local variable 
>> named hwmon it will break. Should it take hwmon as an argument ?
> yes will change this
>>> +
>>> +/* Maximum number of fan control points supported by each fan. */
>>> +#define MAX_FAN_CONTROL_POINTS    (10)
>>> +
>>> +/* Fan control point index: bit31 selects fan table type; bits30:0 
>>> control point index. */
>>> +#define FCP_INDEX(FAN_TABLE_TYPE, POINT_NUM) (((FAN_TABLE_TYPE) << 
>>> 31) | \
>> Cast to u32 ? shifting the signed enum into bit 31 could lead to UB.
> okay
>>> +                        ((POINT_NUM) & REG_GENMASK(30, 0)))
>>> +
>>>   /**
>>> - * struct xe_hwmon_fan_info - to cache previous fan reading
>>> + * struct xe_hwmon_fan_info - cached fan telemetry and control state
>>> + *
>>> + * Each fan keeps the latest tachometer sampling state along with 
>>> two fan
>>> + * tables: the stock table discovered from firmware and the user 
>>> table managed
>>> + * by hwmon sysfs writes.
>>>    */
>>>   struct xe_hwmon_fan_info {
>>>       /** @reg_val_prev: previous fan reg val */
>>>       u32 reg_val_prev;
>>>       /** @time_prev: previous timestamp */
>>>       u64 time_prev;
>>> +    /** @fan_table: fan control tables */
>>> +    struct fan_table {
>>> +        /** @point_count: number of fan control points */
>>> +        u8 point_count;
>>> +        /** @fcp: array of fan control points */
>>> +        struct fan_control_point {
>>> +            /** @temp: temperature in degree celsius */
>>> +            u8 temp;
>>> +            /** @speed: fan speed in percentage */
>>> +            u8 speed;
>>> +        } fcp[MAX_FAN_CONTROL_POINTS];
>>> +    } fan_table[FAN_TABLE_MAX];
>>> +    /** @min_pwm: minimum fan PWM */
>>> +    u32 min_pwm;
>>>   };
>>>     /**
>>> @@ -193,6 +231,8 @@ struct xe_hwmon {
>>>       int scl_shift_time;
>>>       /** @ei: Energy info for energyN_input */
>>>       struct xe_hwmon_energy_info ei[CHANNEL_MAX];
>>> +    /** @fan_enable_mask: bitmask of available fans */
>>> +    u32 fan_enable_mask;
>>>       /** @fi: Fan info for fanN_input */
>>>       struct xe_hwmon_fan_info fi[FAN_MAX];
>>>       /** @read_power_limit_from_pcode: pcode accepted power limits 
>>> write for the channel */
>>> @@ -1075,17 +1115,112 @@ static int xe_hwmon_pcode_write_i1(const 
>>> struct xe_hwmon *hwmon, u32 uval)
>>>                     (uval & POWER_SETUP_I1_DATA_MASK));
>>>   }
>>>   -static int xe_hwmon_pcode_read_fan_control(const struct xe_hwmon 
>>> *hwmon, u32 subcmd, u32 *uval)
>>> +static int xe_hwmon_pcode_read_fan_control(const struct xe_hwmon 
>>> *hwmon, u32 subcmd, u8 fan_num,
>>> +                       u32 *uval)
>>>   {
>>>       struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
>> Nit: blank line after variable declaration
> ok
>>> +    return xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL, 
>>> subcmd, fan_num),
>>> +                     uval, NULL);
>>> +}
>>> +
>>> +static int xe_hwmon_get_fan_enable_mask(struct xe_hwmon *hwmon)
>>> +{
>>> +    int ret;
>>>         /* Platforms that don't return correct value */
>>> -    if (hwmon->xe->info.platform == XE_DG2 && subcmd == 
>>> FSC_READ_NUM_FANS) {
>>> -        *uval = 2;
>>> +    if (hwmon->xe->info.platform == XE_DG2) {
>>> +        hwmon->fan_enable_mask = GENMASK(1, 0);
>>>           return 0;
>>>       }
>>>   -    return xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL, 
>>> subcmd, 0), uval, NULL);
>>> +    ret = xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_NUM_FANS, 0,
>>> +                          &hwmon->fan_enable_mask);
>>> +    if (ret) {
>>> +        xe_warn(hwmon->xe, "failed to read number of fans, 
>>> ret=%d\n", ret);
>>> +        return ret;
>>> +    }
>>> +
>>> +    /* Check if fan mask exceeds FAN_MAX and log a warning if it 
>>> does */
>>> +    if (hwmon->fan_enable_mask & ~GENMASK(FAN_MAX - 1, 0)) {
>>> +        xe_warn(hwmon->xe, "fan enable mask exceeds maximum 
>>> supported fans\n");
>> Reset the mask to 0 so IS_FAN_ENABLED() stays false in case fan mask 
>> exceeds FAN_MAX.
> how about clamping to FAN_MAX ?
>>> +        return -EINVAL;
>>> +    }
>>> +
>>> +    xe_info(hwmon->xe, "Number of fans detected: %u\n",
>>> +        hweight32(hwmon->fan_enable_mask));
>>> +    return 0;
>>> +}
>>> +
>>> +static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
>>> +{
>>> +    struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
>>> +    int point;
>>> +    int fan;
>>> +    int ret;
>>> +
>>> +    for (fan = 0; fan < FAN_MAX; fan++) {
>>> +        u32 stock_fcp_count = 0;
>>> +
>>> +        struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
>>> +
>>> +        if (!IS_FAN_ENABLED(fan))
>>> +            continue;
>>> +
>>> +        ret = xe_hwmon_pcode_read_fan_control(hwmon,
>>> + FSC_READ_STOCK_FAN_CONTROL_POINTS,
>>> +                              fan, &stock_fcp_count);
>>> +        if (ret) {
>>> +            xe_err(hwmon->xe,
>>> +                   "failed to read fan %d stock table point count, 
>>> ret=%d\n",
>>> +                   fan, ret);
>> Why not continue for the rest of the fans marking the current one ?
> yes we can continue, you want to mark current fan invalid ?
yes.
>>> +            return ret;
>>> +        }
>>> +
>>> +        if (!stock_fcp_count || stock_fcp_count > 
>>> MAX_FAN_CONTROL_POINTS) {
>>> +            xe_warn(hwmon->xe,
>>> +                "fan %d stock table point count %u is invalid\n",
>>> +                fan, stock_fcp_count);
>> Ditto.
> okay
>>> +            return -EINVAL;
>>> +        }
>>> +
>>> +        fi->fan_table[STOCK_FAN_TABLE].point_count = stock_fcp_count;
>>> +        xe_dbg(hwmon->xe, "fan %d stock table point count is %u\n", 
>>> fan,
>>> + fi->fan_table[STOCK_FAN_TABLE].point_count);
>>> +
>>> +        /* Cache the stock fan table for later use. */
>>> +        for (point = 0; point < 
>>> fi->fan_table[STOCK_FAN_TABLE].point_count;
>>> +             point++) {
>>> +            u32 fcp = 0;
>>> +
>>> +            fcp = FCP_INDEX(STOCK_FAN_TABLE, point);
>>
>> nit: u32 fcp = FCP_INDEX(STOCK_FAN_TABLE, point);
>>
>> Regards,
>> Soham
> ok
>>> +            ret = xe_pcode_read(root_tile, 
>>> PCODE_MBOX(FAN_SPEED_CONTROL,
>>> +                                  FSC_READ_FAN_TABLE, fan),
>>> +                        &fcp, NULL);
>>> +            if (ret) {
>>> +                xe_err(hwmon->xe, "failed to read fan %d stock 
>>> point %d, ret=%d\n",
>>> +                       fan, point, ret);
>>> +                fi->fan_table[STOCK_FAN_TABLE].point_count = 0;
>>> +                return ret;
>>> +            }
>>> +
>>> +            fi->fan_table[STOCK_FAN_TABLE].fcp[point].temp =
>>> + REG_FIELD_GET(FAN_CONTROL_POINT_TEMP_MASK, fcp);
>>> + fi->fan_table[STOCK_FAN_TABLE].fcp[point].speed =
>>> + REG_FIELD_GET(FAN_CONTROL_POINT_SPEED_MASK, fcp);
>>> +            xe_dbg(hwmon->xe, "fan %d stock point %d: temp %u C, 
>>> speed %u\n",
>>> +                   fan, point, 
>>> fi->fan_table[STOCK_FAN_TABLE].fcp[point].temp,
>>> + fi->fan_table[STOCK_FAN_TABLE].fcp[point].speed);
>>> +        }
>>> +
>>> +        /* Read minimum fan PWM */
>>> +        ret = xe_hwmon_pcode_read_fan_control(hwmon, 
>>> FSC_READ_FAN_MIN_PWM, fan,
>>> +                              &fi->min_pwm);
>>> +        if (ret)
>>> +            xe_warn(hwmon->xe, "fan %d min pwm unavailable, 
>>> ret=%d\n", fan, ret);
>>> +        else
>>> +            xe_dbg(hwmon->xe, "fan %d min PWM %u\n", fan, 
>>> fi->min_pwm);
>>> +    }
>>> +    return 0;
>>>   }
>>>     static int xe_hwmon_power_curr_crit_read(struct xe_hwmon *hwmon, 
>>> int channel,
>>> @@ -1615,17 +1750,12 @@ xe_hwmon_energy_read(struct xe_hwmon *hwmon, 
>>> u32 attr, int channel, long *val)
>>>   static umode_t
>>>   xe_hwmon_fan_is_visible(struct xe_hwmon *hwmon, u32 attr, int 
>>> channel)
>>>   {
>>> -    u32 uval = 0;
>>> -
>>>       if (!hwmon->xe->info.has_fan_control)
>>>           return 0;
>>>         switch (attr) {
>>>       case hwmon_fan_input:
>>> -        if (xe_hwmon_pcode_read_fan_control(hwmon, 
>>> FSC_READ_NUM_FANS, &uval))
>>> -            return 0;
>>> -
>>> -        return channel < uval ? 0444 : 0;
>>> +        return IS_FAN_ENABLED(channel) ? 0444 : 0;
>>>       default:
>>>           return 0;
>>>       }
>>> @@ -1858,11 +1988,18 @@ xe_hwmon_get_preregistration_info(struct 
>>> xe_hwmon *hwmon)
>>>           if (xe_hwmon_is_visible(hwmon, hwmon_energy, 
>>> hwmon_energy_input, channel))
>>>               xe_hwmon_energy_get(hwmon, channel, &energy);
>>>   -    /* Initialize 'struct xe_hwmon_fan_info' with initial fan 
>>> register reading. */
>>> -    for (channel = 0; channel < FAN_MAX; channel++)
>>> -        if (xe_hwmon_is_visible(hwmon, hwmon_fan, hwmon_fan_input, 
>>> channel))
>>> -            xe_hwmon_fan_input_read(hwmon, channel, &fan_speed);
>>> +    if (hwmon->xe->info.has_fan_control) {
>>> +        xe_hwmon_get_fan_enable_mask(hwmon);
>>> +
>>> +        /* Initialize 'struct xe_hwmon_fan_info' with initial fan 
>>> register reading. */
>>> +        for (channel = 0; channel < FAN_MAX; channel++)
>>> +            if (IS_FAN_ENABLED(channel))
>>> +                xe_hwmon_fan_input_read(hwmon, channel, &fan_speed);
>>>   +        /* Fan control tables initialization */
>>> +        if (xe_hwmon_read_fan_control_info(hwmon))
>>> +            xe_warn(hwmon->xe, "Fan control tables are not 
>>> available\n");
>>> +    }
>>>       return xe_hwmon_init_temp_info(hwmon);
>>>   }
>>>   diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h 
>>> b/drivers/gpu/drm/xe/xe_pcode_api.h
>>> index 00c4fc7d0124..0349b24a8259 100644
>>> --- a/drivers/gpu/drm/xe/xe_pcode_api.h
>>> +++ b/drivers/gpu/drm/xe/xe_pcode_api.h
>>> @@ -83,6 +83,11 @@
>>>     #define   FAN_SPEED_CONTROL            0x7D
>>>   #define     FSC_READ_NUM_FANS            0x4
>>> +#define     FSC_READ_STOCK_FAN_CONTROL_POINTS    0x5
>>> +#define     FSC_READ_FAN_TABLE            0x7
>>> +#define     FAN_CONTROL_POINT_TEMP_MASK        REG_GENMASK(7, 0)
>>> +#define     FAN_CONTROL_POINT_SPEED_MASK    REG_GENMASK(15, 8)
>>> +#define     FSC_READ_FAN_MIN_PWM        0x8
>>>     #define PCODE_SCRATCH(x)        XE_REG(0x138320 + ((x) * 4))
>>>   /* PCODE_SCRATCH0 */

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

* Re: [PATCH v3 5/9] drm/xe/hwmon: expose pwm[1-3]_enable
  2026-10-15 19:07 ` [PATCH v3 5/9] drm/xe/hwmon: expose pwm[1-3]_enable Karthik Poosa
@ 2026-10-29 18:33   ` Purkait, Soham
  0 siblings, 0 replies; 26+ messages in thread
From: Purkait, Soham @ 2026-10-29 18:33 UTC (permalink / raw)
  To: Karthik Poosa, intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi,
	ravi.kishore.koppuravuri

Hi Karthik,

On 16-10-2026 00:37, Karthik Poosa wrote:
> Expose pwm[1-3]_enable to control the fan operating mode through
> the hwmon interface.
>   
> Mode 0 forces the fan to run at full speed.
> Mode 1 enables user fan-table control.
> Mode 2 restores firmware-controlled fan management.
>   
> Document pwm[1-3]_enable in the Xe hwmon ABI.
>
> v2:
>   - Use xe helpers for dmesg logs.
>   - Update kernel version in Xe hwmon documentation.
>   - Correct level of some dmesg logs.
>
> v3:
>   - Each pwm_enable mode now sets its own state; drop the redundant
>     post-switch pwm_enable_mode/is_full_speed update. (Badal)
>   - Fix misindented dead assignment in the stock-table branch.
>   - Make error handling consistent across pwm_enable modes. (Badal)
>   - Document the pwm[1-3] manual-mode write precondition in the ABI. (Badal)
>   - Use xe_pcode_write() instead of the timeout variant api as it is not
>     needed.
>
> Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
> Assisted-by: LLM
> ---
>   .../ABI/testing/sysfs-driver-intel-xe-hwmon   |  15 ++
>   drivers/gpu/drm/xe/xe_hwmon.c                 | 156 +++++++++++++++++-
>   2 files changed, 168 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
> index ce17e9ca3ed8..92c91c57b3f2 100644
> --- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
> +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
> @@ -329,4 +329,19 @@ Contact:        intel-xe@lists.freedesktop.org
>   Description:    RW. Target fan PWM duty value in the range 0..255. 0 is zero
>                   fan speed and 255 is 100% fan speed.
>   
> +                Writing requires the corresponding pwm[1-3]_enable to be set to
> +                1 (manual user-table mode) first; otherwise the write is
> +                rejected with -EINVAL.
> +
>                   Only supported for particular Intel Xe graphics platforms.
> +
> +What:          /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/pwm[1-3]_enable
> +Date:          September 2026
> +KernelVersion: 7.3
Please use the correct version as per the prediction.
https://jnikula.github.io/linux-kernel-tea-leaves/
> +Contact:       intel-xe@lists.freedesktop.org
> +Description:   RW. Fan control mode selector.
> +
> +               Use value 0 to run fans at full speed. Use value 1 to enable
> +               user table control and value 2 to use firmware default behavior.
> +
> +               Only supported for particular Intel Xe graphics platforms.
Use tab indentation.
> diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
> index a86ed741feb3..c3d5c682768d 100644
> --- a/drivers/gpu/drm/xe/xe_hwmon.c
> +++ b/drivers/gpu/drm/xe/xe_hwmon.c
> @@ -139,6 +139,15 @@ struct xe_hwmon_energy_info {
>   	long accum_energy;
>   };
>   
> +enum xe_fan_pwm_enable_mode {
> +	/** @XE_FAN_PWM_FULL_SPEED: force all user table points to full speed */
> +	XE_FAN_PWM_FULL_SPEED = 0,
> +	/** @XE_FAN_PWM_MANUAL_USER_TABLE: use the driver-managed user table */
> +	XE_FAN_PWM_MANUAL_USER_TABLE = 1,
> +	/** @XE_FAN_PWM_AUTO_STOCK_TABLE: use the firmware stock table */
Keep the wordings consistent with the ABI doc.
> +	XE_FAN_PWM_AUTO_STOCK_TABLE = 2,
> +};
> +
>   enum fan_table_type {
>   	/** @STOCK_FAN_TABLE: firmware-provided fan table */
>   	STOCK_FAN_TABLE,
> @@ -189,6 +198,10 @@ struct xe_hwmon_fan_info {
>   	u32 max_rps;
>   	/** @min_pwm: minimum fan PWM */
>   	u32 min_pwm;
> +	/** @pwm_enable_mode: current xe_fan_pwm_enable_mode */
> +	u8 pwm_enable_mode;
> +	/** @is_full_speed: flag indicating if fan is in full speed */
> +	bool is_full_speed;
>   };
>   
>   /**
> @@ -917,7 +930,9 @@ static const struct hwmon_channel_info * const hwmon_info[] = {
>   	HWMON_CHANNEL_INFO(energy, HWMON_E_INPUT | HWMON_E_LABEL, HWMON_E_INPUT | HWMON_E_LABEL),
>   	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_MAX, HWMON_F_INPUT | HWMON_F_MAX,
>   			   HWMON_F_INPUT | HWMON_F_MAX),
> -	HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT, HWMON_PWM_INPUT, HWMON_PWM_INPUT),
> +	HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
> +			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE,
> +			   HWMON_PWM_INPUT | HWMON_PWM_ENABLE),
>   	NULL
>   };
>   
> @@ -1185,10 +1200,80 @@ static int xe_hwmon_get_fan_point_count(struct xe_hwmon *hwmon, u8 fan, u32 *poi
>   	return 0;
>   }
>   
> +static int xe_hwmon_activate_user_fan_table(struct xe_hwmon *hwmon, u8 fan,
> +					    bool is_full_speed, enum fan_table_type table_source)
xe_hwmon_activate_user_fan_table(), xe_hwmon_set_user_fan_pwm(), and 
xe_hwmon_commit_user_fan_table() share the same write/batch/verify 
logic. Can these be consolidated into a single helper ?
> +{
> +	struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
> +	struct xe_pcode_write writes[MAX_FAN_CONTROL_POINTS + 1];
> +	u32 point_count;
> +	int ret;
> +	int point;
> +	struct fan_table *source_table = &fi->fan_table[table_source];
Inverted xmas tree.
> +
> +	xe_dbg(hwmon->xe, "activating fan %d user table from %s table\n", fan,
> +	       (table_source == USER_FAN_TABLE) ? "user" : "stock");
> +
> +	point_count = source_table->point_count;
> +	if (!point_count || point_count > MAX_FAN_CONTROL_POINTS) {
> +		xe_err(hwmon->xe,
> +		       "fan %d %s table point count %d is invalid, cannot activate user table\n",
> +		       fan, (table_source == USER_FAN_TABLE) ? "user" : "stock", point_count);
> +		return -EINVAL;
> +	}
> +
> +	for (point = 0; point < point_count; point++) {
> +		u8 temp = source_table->fcp[point].temp;
> +		u8 speed = is_full_speed ? 100 : max_t(u8, source_table->fcp[point].speed,
> +					    min_t(u32, fi->min_pwm, U8_MAX));
Nit: same per-point speed is recomputed below. Could these values be 
reused?
> +
> +		writes[point].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_FAN_TABLE, fan);
> +		writes[point].data = FIELD_PREP(FAN_CONTROL_POINT_TEMP_MASK, temp) |
> +					FIELD_PREP(FAN_CONTROL_POINT_SPEED_MASK, speed);
> +	}
> +
> +	writes[point_count].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_NUM_FAN_CONTROL_POINTS,
> +					      fan);
> +	writes[point_count].data = point_count;
> +	ret = xe_pcode_write_batch(xe_device_get_root_tile(hwmon->xe), writes, point_count + 1);
> +	if (ret) {
> +		xe_dbg(hwmon->xe, "failed to write fan %d user table, ret=%d\n", fan, ret);
> +		return ret;
> +	}
> +
> +	/* Verify if all the user points are set */
> +	ret = xe_hwmon_get_fan_point_count(hwmon, fan, &point_count, USER_FAN_TABLE);
> +	if (ret) {
> +		xe_err(hwmon->xe,
> +		       "failed to read fan %d user table point count, ret=%d\n", fan, ret);
> +		return ret;
> +	}
> +	if (point_count != source_table->point_count) {
> +		xe_err(hwmon->xe, "fan %d user table point count mismatch, expected %u, got %u\n",
> +		       fan, source_table->point_count, point_count);
> +		return -EIO;
> +	}
> +
> +	if (table_source == STOCK_FAN_TABLE) {
> +		for (point = 0; point < point_count; point++) {
> +			fi->fan_table[USER_FAN_TABLE].fcp[point].temp =
> +				source_table->fcp[point].temp;
> +			fi->fan_table[USER_FAN_TABLE].fcp[point].speed =
> +				is_full_speed ? 100 : max_t(u8, source_table->fcp[point].speed,
> +							    min_t(u32, fi->min_pwm, U8_MAX));
Nit: ditto
> +		}
> +	}
> +
> +	fi->fan_table[USER_FAN_TABLE].point_count = point_count;
> +	fi->pwm_enable_mode = XE_FAN_PWM_MANUAL_USER_TABLE;
> +	fi->is_full_speed = is_full_speed;
> +
> +	return 0;
> +}
> +
>   /* Temperature to set when setting the fan PWM with pwmN. */
>   #define FIXED_PWM_TEMP	(1)
>   
> -static int xe_hwmon_set_user_fan_pwm(struct xe_hwmon *hwmon, u8 fan, u8 pwm)
> +static int xe_hwmon_set_user_fan_pwm(struct xe_hwmon *hwmon, u8 fan, u8 pwm, bool full_speed)
Either use full_speed or is_full_speed but keep it consistent throughout.
>   {
>   	struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
>   	struct xe_pcode_write writes[MIN_FAN_CONTROL_POINTS + 1];
> @@ -1196,6 +1281,11 @@ static int xe_hwmon_set_user_fan_pwm(struct xe_hwmon *hwmon, u8 fan, u8 pwm)
>   	u8 clamped_pwm;
>   	int ret, i;
>   
> +	if (!full_speed && fi->pwm_enable_mode != XE_FAN_PWM_MANUAL_USER_TABLE) {
> +		xe_dbg(hwmon->xe, "fan %d manual mode is not active, cannot set pwm\n", fan);
> +		return -EINVAL;
> +	}
> +
>   	pwm = DIV_ROUND_CLOSEST(pwm * 100, U8_MAX);
>   	clamped_pwm = max_t(u8, pwm, min_t(u32, fi->min_pwm, U8_MAX));
>   
> @@ -1239,6 +1329,8 @@ static int xe_hwmon_set_user_fan_pwm(struct xe_hwmon *hwmon, u8 fan, u8 pwm)
>   	}
>   	fi->fan_table[USER_FAN_TABLE].point_count = MIN_FAN_CONTROL_POINTS;
>   
> +	fi->pwm_enable_mode = XE_FAN_PWM_MANUAL_USER_TABLE;
> +	fi->is_full_speed = full_speed;
>   	return 0;
>   }
>   
> @@ -1303,6 +1395,9 @@ static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
>   			       fi->fan_table[STOCK_FAN_TABLE].fcp[point].speed);
>   		}
>   
> +		/* Set PWM enable mode to automatic i.e stock table in use. */
> +		fi->pwm_enable_mode = XE_FAN_PWM_AUTO_STOCK_TABLE;
> +
>   		/* Read minimum fan PWM */
>   		ret = xe_hwmon_pcode_read_fan_control(hwmon, FSC_READ_FAN_MIN_PWM, fan,
>   						      &fi->min_pwm);
> @@ -1870,6 +1965,7 @@ xe_hwmon_pwm_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
>   
>   	switch (attr) {
>   	case hwmon_pwm_input:
> +	case hwmon_pwm_enable:
>   		return 0644;
>   	default:
>   		return 0;
> @@ -1954,6 +2050,9 @@ xe_hwmon_pwm_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
>   		*val = DIV_ROUND_CLOSEST(fi->fan_table[USER_FAN_TABLE].fcp[0].speed * U8_MAX, 100);
>   		xe_dbg(hwmon->xe, "pwm read for fan %d: %ld\n", channel, *val);
>   		break;
> +	case hwmon_pwm_enable:
> +		*val = fi->pwm_enable_mode;
> +		break;
>   	default:
>   		ret = -EOPNOTSUPP;
>   		break;
> @@ -1967,11 +2066,15 @@ xe_hwmon_pwm_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
>   static int
>   xe_hwmon_pwm_write(struct xe_hwmon *hwmon, u32 attr, int channel, long val)
>   {
> +	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
> +	struct xe_hwmon_fan_info *fi;
>   	int ret = 0;
>   
>   	if (channel < 0 || channel >= FAN_MAX)
>   		return -EINVAL;
>   
> +	fi = &hwmon->fi[channel];
> +
>   	mutex_lock(&hwmon->hwmon_lock);
>   
>   	switch (attr) {
> @@ -1980,12 +2083,59 @@ xe_hwmon_pwm_write(struct xe_hwmon *hwmon, u32 attr, int channel, long val)
>   			ret = -EINVAL;
>   			break;
>   		}
> -		ret = xe_hwmon_set_user_fan_pwm(hwmon, channel, (u8)val);
> +		ret = xe_hwmon_set_user_fan_pwm(hwmon, channel, (u8)val, false);
> +		break;
> +	case hwmon_pwm_enable:
> +		if (val == XE_FAN_PWM_FULL_SPEED) {
> +			ret = xe_hwmon_set_user_fan_pwm(hwmon, channel, U8_MAX, true);
> +			if (ret) {
> +				xe_warn(hwmon->xe,
> +					"full speed enable for fan %d failed, ret=%d\n",
> +					channel, ret);
> +				break;
> +			}
> +		} else if (val == XE_FAN_PWM_MANUAL_USER_TABLE) {
> +			enum fan_table_type source = fi->fan_table[USER_FAN_TABLE].point_count ?
> +				USER_FAN_TABLE : STOCK_FAN_TABLE;
> +
> +			/*
> +			 * Manual fan speed control using user fan table.
> +			 * If user fan table is not programmed, it would be initialized with
> +			 * clamped stock points which allows manual control with some
> +			 * default points.
> +			 */
> +			ret = xe_hwmon_activate_user_fan_table(hwmon, channel, false, source);
> +			if (ret) {
> +				xe_warn(hwmon->xe,
> +					"failed to activate user fan table for fan %d, ret=%d\n",
> +					channel, ret);
> +				break;
> +			}
> +		} else if (val == XE_FAN_PWM_AUTO_STOCK_TABLE) {
> +			/* Switch to stock table specifying the user points to 0. */
> +			ret = xe_pcode_write(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL,
> +								   FSC_WRITE_NUM_FAN_CONTROL_POINTS,
> +								   channel), 0);
Is it required to verify the write as other modes ?
> +			if (ret) {
> +				xe_warn(hwmon->xe,
> +					"failed to disable user fan table for fan %d, ret=%d\n",
> +					channel, ret);
> +				break;
> +			}
> +			xe_dbg(hwmon->xe,
> +			       "automatic control enabled for fan %d using stock table\n",
> +			       channel);
> +			fi->pwm_enable_mode = XE_FAN_PWM_AUTO_STOCK_TABLE;
> +			fi->is_full_speed = false;
> +		} else {
Rejected silently. Add a xe_dbg/xe_warn before these -EINVAL returns for 
clarity.

Regards,
Soham
> +			ret = -EINVAL;
> +		}
>   		break;
>   	default:
>   		ret = -EOPNOTSUPP;
>   		break;
>   	}
> +
>   	mutex_unlock(&hwmon->hwmon_lock);
>   
>   	return ret;

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

* Re: [PATCH v3 6/9] drm/xe/hwmon: Enable fan curve control support
  2026-10-15 19:07 ` [PATCH v3 6/9] drm/xe/hwmon: Enable fan curve control support Karthik Poosa
@ 2026-10-30  6:33   ` Purkait, Soham
  0 siblings, 0 replies; 26+ messages in thread
From: Purkait, Soham @ 2026-10-30  6:33 UTC (permalink / raw)
  To: Karthik Poosa, intel-xe
  Cc: rodrigo.vivi, anshuman.gupta, badal.nilawar, raag.jadav,
	riana.tauro, sk.anirban, mallesh.koujalagi,
	ravi.kishore.koppuravuri

Hi Karthik,

On 16-10-2026 00:37, Karthik Poosa wrote:
> Expose curve-point temperature and pwm controls via
> pwmF_auto_point[P]_temp and pwmF_auto_point[P]_pwm, where
> F is the fan number and P is the fan curve point number.
> Each fan curve point has temperature and pwm sysfs.
>
> Update Xe hwmon ABI documentation for pwm auto point temperature
> attributes.
>
> v2:
> - Use xe helpers for dmesg logs.
> - Update kernel version in Xe hwmon documentation.
> - Correct debug level of some dmesg logs.
>
> v3:
>   - Allow variable fan curve points from >=2 to MAX_FAN_CONTROL_POINTS.
>   - Expose all MAX_FAN_CONTROL_POINTS fan-curve slots so users can extend
>     a short fan table.
>   - Stage temp/PWM pairs without changing the active curve. Commit at a
>     (0, 0) end marker or after all MAX_FAN_CONTROL_POINTS pairs.
>   - Write the points together, verify the firmware count, then update the
>     active cache.
>
> Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
> Assisted-by: LLM
> ---
>   drivers/gpu/drm/xe/xe_hwmon.c | 693 +++++++++++++++++++++++++++++++++-
>   1 file changed, 692 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
> index c3d5c682768d..de2adb56d15b 100644
> --- a/drivers/gpu/drm/xe/xe_hwmon.c
> +++ b/drivers/gpu/drm/xe/xe_hwmon.c
> @@ -193,6 +193,12 @@ struct xe_hwmon_fan_info {
>   			/** @speed: fan speed in percentage */
>   			u8 speed;
>   		} fcp[MAX_FAN_CONTROL_POINTS];
> +		/** @staged_fcp: curve supplied via sysfs but not yet committed */
> +		struct fan_control_point staged_fcp[MAX_FAN_CONTROL_POINTS];
> +		/** @temp_staged: bitmask of temperature fields supplied via sysfs */
> +		u16 temp_staged;
> +		/** @speed_staged: bitmask of PWM fields supplied via sysfs */
Either "PWM" or "speed" should be used consistently throughout the series.
IMHO "PWM" and "speed in terms of percentage" are not same so there 
should be a clear distinction and same should be applicable for entire 
series.
> +		u16 speed_staged;
>   	} fan_table[FAN_TABLE_MAX];
>   	/** @max_rps: maximum fan RPS */
>   	u32 max_rps;
> @@ -899,8 +905,11 @@ static const struct attribute_group hwmon_attrgroup = {
>   	.is_visible = xe_hwmon_attributes_visible,
>   };
>   
> +static const struct attribute_group hwmon_curve_attrgroup;
> +
>   static const struct attribute_group *hwmon_groups[] = {
>   	&hwmon_attrgroup,
> +	&hwmon_curve_attrgroup,
>   	NULL
>   };
>   
> @@ -1200,6 +1209,74 @@ static int xe_hwmon_get_fan_point_count(struct xe_hwmon *hwmon, u8 fan, u32 *poi
>   	return 0;
>   }
>   
> +static int xe_hwmon_commit_user_fan_table(struct xe_hwmon *hwmon, u8 fan,
> +					  const struct fan_control_point *points, u32 point_count)
> +{
> +	/* The extra write is for the final write that sets the number of fan control points */
> +	struct xe_pcode_write writes[MAX_FAN_CONTROL_POINTS + 1];
> +	u32 accepted_count = 0;
> +	int point;
u32 ?
> +	int ret;
> +
> +	if (!point_count) {
> +		xe_err(hwmon->xe, "no fan control points provided for fan %d\n", fan);
> +		return -ENODATA;
> +	}
> +
> +	for (point = 0; point < point_count; point++) {
point is int but point_count is  u32.
> +		u8 temp = points[point].temp;
> +		u8 speed = points[point].speed;
> +
> +		/* Ensure fan control points are strictly increasing order */
> +		if (point > 0) {
> +			u8 prev_temp = points[point - 1].temp;
> +			u8 prev_speed = points[point - 1].speed;
> +
> +			if (temp < prev_temp || speed < prev_speed) {
This only rejects a point that is smaller than the previous one. But the 
comment says "fan control points are strictly increasing order".
> +				xe_dbg(hwmon->xe,
> +				       "fan %d invalid point prev > current %d: %u/%u prev=%u/%u\n",
> +					fan, point, temp, speed, prev_temp, prev_speed);
> +				return -EINVAL;
> +			}
> +		}
> +
> +		/* Prepare the write for this fan control point */
> +		writes[point].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_FAN_TABLE,
> +						fan);
> +		writes[point].data = FIELD_PREP(FAN_CONTROL_POINT_TEMP_MASK, temp) |
> +				FIELD_PREP(FAN_CONTROL_POINT_SPEED_MASK, speed);
> +	}
> +
> +	xe_dbg(hwmon->xe, "committing fan %d user table with %d points\n", fan, point_count);
> +
> +	writes[point_count].mbox = PCODE_MBOX(FAN_SPEED_CONTROL, FSC_WRITE_NUM_FAN_CONTROL_POINTS,
> +					      fan);
> +	writes[point_count].data = point_count;
> +
> +	ret = xe_pcode_write_batch(xe_device_get_root_tile(hwmon->xe), writes, point_count + 1);
> +	if (ret) {
> +		xe_dbg(hwmon->xe,
> +		       "failed to write fan %d user table count to %d, ret=%d\n", fan, point_count,
> +		       ret);
> +		return ret;
> +	}
> +
> +	/* Verify if the user fan table was accepted correctly */
> +	ret = xe_hwmon_get_fan_point_count(hwmon, fan, &accepted_count, USER_FAN_TABLE);
> +	if (ret)
> +		return ret;
> +
> +	if (accepted_count != point_count) {
> +		xe_err(hwmon->xe, "fan %d table count mismatch after commit, expected %u, got %u\n",
> +		       fan, point_count, accepted_count);
> +		return -EIO;
> +	}
> +
> +	xe_dbg(hwmon->xe, "fan %d user table committed successfully with %d points\n", fan,
> +	       point_count);
> +	return 0;
> +}
> +
>   static int xe_hwmon_activate_user_fan_table(struct xe_hwmon *hwmon, u8 fan,
>   					    bool is_full_speed, enum fan_table_type table_source)
>   {
> @@ -1264,6 +1341,8 @@ static int xe_hwmon_activate_user_fan_table(struct xe_hwmon *hwmon, u8 fan,
>   	}
>   
>   	fi->fan_table[USER_FAN_TABLE].point_count = point_count;
> +	fi->fan_table[USER_FAN_TABLE].temp_staged = 0;
> +	fi->fan_table[USER_FAN_TABLE].speed_staged = 0;
>   	fi->pwm_enable_mode = XE_FAN_PWM_MANUAL_USER_TABLE;
>   	fi->is_full_speed = is_full_speed;
>   
> @@ -1328,12 +1407,622 @@ static int xe_hwmon_set_user_fan_pwm(struct xe_hwmon *hwmon, u8 fan, u8 pwm, boo
>   			  fi->fan_table[USER_FAN_TABLE].fcp[i].speed);
>   	}
>   	fi->fan_table[USER_FAN_TABLE].point_count = MIN_FAN_CONTROL_POINTS;
> +	fi->fan_table[USER_FAN_TABLE].temp_staged = 0;
> +	fi->fan_table[USER_FAN_TABLE].speed_staged = 0;
>   
>   	fi->pwm_enable_mode = XE_FAN_PWM_MANUAL_USER_TABLE;
>   	fi->is_full_speed = full_speed;
>   	return 0;
>   }
>   
> +#define XE_CURVE_IDX(fan, point)	(((fan) << 8) | (point))
> +#define XE_CURVE_FAN(idx)		((u8)(((idx) >> 8) & 0xff))
> +#define XE_CURVE_POINT(idx)		((u8)((idx) & 0xff))
> +
> +static int
> +xe_hwmon_decode_curve_index(u32 index, u8 *fan, u8 *point)
> +{
> +	u8 local_fan = XE_CURVE_FAN(index);
> +	u8 local_point = XE_CURVE_POINT(index);
> +
> +	if (local_fan >= FAN_MAX || local_point >= MAX_FAN_CONTROL_POINTS)
Add a xe_dbg/xe_warn before these -EINVAL returns for clarity.
> +		return -EINVAL;
> +
> +	*fan = local_fan;
> +	*point = local_point;
> +
> +	return 0;
> +}
> +
> +static inline enum fan_table_type xe_hwmon_get_active_fan_table(struct xe_hwmon *hwmon, u8 fan)
Drop inline.
> +{
> +	if (hwmon->fi[fan].pwm_enable_mode == XE_FAN_PWM_AUTO_STOCK_TABLE)
> +		return STOCK_FAN_TABLE;
> +	else
> +		return USER_FAN_TABLE;
> +}
> +
> +static ssize_t
> +xe_hwmon_pwm_auto_point_temp_show(struct device *dev,
> +				  struct device_attribute *attr, char *buf)
> +{
> +	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
> +	struct xe_hwmon *hwmon = dev_get_drvdata(dev);
> +	struct xe_hwmon_fan_info *fi;
> +	u32 point_count;
> +	u8 fan;
> +	u8 point;
> +	u8 temp;
> +	int ret;
> +	enum fan_table_type active_table;
Inverted xmas tree.
> +
> +	ret = xe_hwmon_decode_curve_index(sattr->index, &fan, &point);
> +	if (ret)
> +		return ret;
> +
> +	guard(xe_pm_runtime)(hwmon->xe);
> +
> +	mutex_lock(&hwmon->hwmon_lock);
> +
> +	fi = &hwmon->fi[fan];
> +	active_table = xe_hwmon_get_active_fan_table(hwmon, fan);
> +
> +	ret = xe_hwmon_get_fan_point_count(hwmon, fan, &point_count, active_table);
> +	if (ret)
> +		goto unlock;
> +
> +	/* Slots beyond the active curve can still be staged for the next curve. */
> +	if (point >= point_count &&
> +	    (active_table != USER_FAN_TABLE ||
> +	    !(fi->fan_table[USER_FAN_TABLE].temp_staged & BIT(point))))
> +		temp = 0;
> +	else if (point >= point_count)
> +		temp = fi->fan_table[USER_FAN_TABLE].staged_fcp[point].temp;
> +	else
> +		temp = fi->fan_table[active_table].fcp[point].temp;
> +	ret = sysfs_emit(buf, "%u\n", temp * MILLIDEGREE_PER_DEGREE);
> +
> +unlock:
> +	mutex_unlock(&hwmon->hwmon_lock);
> +
> +	return ret;
> +}
> +
> +static int xe_hwmon_update_user_fan_point(struct xe_hwmon *hwmon, u8 fan, u32 point,
> +					  bool is_temp, u8 value)
> +{
> +	struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
> +	struct fan_table *table;
> +	u32 point_count;
> +	int ret;
> +
> +	table = &fi->fan_table[USER_FAN_TABLE];
> +
> +	if (is_temp) {
> +		table->staged_fcp[point].temp = value;
> +		table->temp_staged |= BIT(point);
> +	} else {
> +		table->staged_fcp[point].speed = value;
> +		table->speed_staged |= BIT(point);
> +	}
> +
> +	/* Wait for a complete prefix; (0, 0) ends the curve without becoming a point. */
> +	for (point_count = 0; point_count < MAX_FAN_CONTROL_POINTS; point_count++) {
> +		if (!(table->temp_staged & BIT(point_count)) ||
> +		    !(table->speed_staged & BIT(point_count)))
> +			return 0;
> +		if (!table->staged_fcp[point_count].temp &&
> +		    !table->staged_fcp[point_count].speed)
> +			break;
> +	}
> +
> +	if (point_count < MIN_FAN_CONTROL_POINTS)
Add a xe_dbg/xe_warn before these -EINVAL returns for clarity.
> +		return -EINVAL;
> +
> +	ret = xe_hwmon_commit_user_fan_table(hwmon, fan, table->staged_fcp, point_count);
> +	if (ret)
> +		return ret;
> +
> +	/* Publish the new curve only after firmware accepts its point count. */
> +	memcpy(table->fcp, table->staged_fcp, point_count * sizeof(table->fcp[0]));
> +	table->point_count = point_count;
> +	table->temp_staged = 0;
> +	table->speed_staged = 0;
> +	fi->pwm_enable_mode = XE_FAN_PWM_MANUAL_USER_TABLE;
> +	fi->is_full_speed = false;
> +	return 0;
> +}
> +
> +static int xe_hwmon_get_u8_from_sysfs(long val, bool is_temp, u8 *out)
Could "get" be dropped from the name, e.g. xe_hwmon_sysfs_to_hw_val()?
> +{
> +	long hw_val;
> +
> +	if (is_temp)
> +		hw_val = DIV_ROUND_CLOSEST(val, MILLIDEGREE_PER_DEGREE);
> +	else
> +		hw_val = DIV_ROUND_CLOSEST(val * 100, U8_MAX);
> +
> +	if (hw_val < 0 || hw_val > U8_MAX)
Add a xe_dbg before these -EINVAL returns for clarity.
> +		return -EINVAL;
> +
> +	*out = hw_val;
> +
> +	return 0;
> +}
> +
> +static ssize_t
> +xe_hwmon_pwm_auto_point_temp_store(struct device *dev,
> +				   struct device_attribute *attr,
> +				   const char *buf, size_t count)
> +{
> +	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
> +	struct xe_hwmon *hwmon = dev_get_drvdata(dev);
> +	struct xe_hwmon_fan_info *fi;
> +	u8 fan;
> +	u8 point;
> +	u8 temp;
> +	long val;
> +	int ret;
> +
> +	ret = xe_hwmon_decode_curve_index(sattr->index, &fan, &point);
> +	if (ret)
> +		return ret;
> +
> +	ret = kstrtol(buf, 10, &val);
> +	if (ret)
> +		return ret;
> +
> +	ret = xe_hwmon_get_u8_from_sysfs(val, true, &temp);
> +	if (ret)
> +		return ret;
> +
> +	guard(xe_pm_runtime)(hwmon->xe);
> +
> +	mutex_lock(&hwmon->hwmon_lock);
> +	fi = &hwmon->fi[fan];
> +
> +	if (fi->pwm_enable_mode != XE_FAN_PWM_MANUAL_USER_TABLE) {
> +		drm_err(&hwmon->xe->drm,
> +			"pwm%d_enable not in manual mode; cannot update temp point %d\n",
> +			fan, point);
> +		ret = -EINVAL;
> +		goto unlock;
> +	}
> +
> +	drm_dbg(&hwmon->xe->drm,
> +		"staging fan %d point %d temp to %u\n", fan, point, temp);
> +	ret = xe_hwmon_update_user_fan_point(hwmon, fan, point, true, temp);
> +
> +unlock:
> +	mutex_unlock(&hwmon->hwmon_lock);
> +
> +	return ret ? ret : count;
> +}
> +
> +static ssize_t
> +xe_hwmon_pwm_auto_point_pwm_show(struct device *dev,
> +				 struct device_attribute *attr,
> +				 char *buf)
> +{
> +	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
> +	struct xe_hwmon *hwmon = dev_get_drvdata(dev);
> +	struct xe_hwmon_fan_info *fi;
> +	u8 fan;
> +	u8 point;
> +	u32 point_count;
> +	int ret;
> +	enum fan_table_type active_table;
> +
> +	ret = xe_hwmon_decode_curve_index(sattr->index, &fan, &point);
> +	if (ret)
> +		return ret;
> +
> +	guard(xe_pm_runtime)(hwmon->xe);
> +
> +	mutex_lock(&hwmon->hwmon_lock);
> +
> +	fi = &hwmon->fi[fan];
> +	active_table = xe_hwmon_get_active_fan_table(hwmon, fan);
> +
> +	ret = xe_hwmon_get_fan_point_count(hwmon, fan, &point_count, active_table);
> +	if (ret)
> +		goto unlock;
> +
> +	if (point >= point_count &&
> +	    (active_table != USER_FAN_TABLE ||
> +	    !(fi->fan_table[USER_FAN_TABLE].speed_staged & BIT(point))))
> +		ret = sysfs_emit(buf, "0\n");
> +	else
> +		ret = sysfs_emit(buf, "%u\n",
> +				 DIV_ROUND_CLOSEST((point >= point_count ?
> +						    fi->fan_table[USER_FAN_TABLE].staged_fcp[point].speed :
> +						    fi->fan_table[active_table].fcp[point].speed) * U8_MAX,
> +						    100));
Could the value selection be split into if/else if/else like the temp 
sibling, instead of the nested ternary?
> +
> +unlock:
> +	mutex_unlock(&hwmon->hwmon_lock);
> +
> +	return ret;
> +}
> +
> +static ssize_t
> +xe_hwmon_pwm_auto_point_pwm_store(struct device *dev,
> +				  struct device_attribute *attr,
> +				  const char *buf, size_t count)
> +{
> +	struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
> +	struct xe_hwmon *hwmon = dev_get_drvdata(dev);
> +	struct xe_hwmon_fan_info *fi;
> +	long val;
> +	u8 point;
> +	u8 fan;
> +	u8 pwm;
> +	int ret;
> +
> +	ret = xe_hwmon_decode_curve_index(sattr->index, &fan, &point);
> +	if (ret)
> +		return ret;
> +
> +	ret = kstrtol(buf, 10, &val);
> +	if (ret)
> +		return ret;
> +
> +	ret = xe_hwmon_get_u8_from_sysfs(val, false, &pwm);
> +	if (ret)
> +		return ret;
> +
> +	guard(xe_pm_runtime)(hwmon->xe);
> +
> +	mutex_lock(&hwmon->hwmon_lock);
> +	fi = &hwmon->fi[fan];
> +
> +	if (fi->pwm_enable_mode != XE_FAN_PWM_MANUAL_USER_TABLE) {
> +		drm_err(&hwmon->xe->drm,
> +			"pwm%d_enable is not in manual user mode, cannot update pwm point %d\n",
> +			fan, point);
> +		ret = -EINVAL;
> +		goto unlock;
> +	}
> +
> +	/* Preserve zero for the (0, 0) end marker instead of clamping it. */
> +	if (pwm)
> +		pwm = max_t(u8, pwm, min_t(u32, fi->min_pwm, U8_MAX));
> +
> +	drm_dbg(&hwmon->xe->drm, "staging fan %d point %d pwm to %u\n",
> +		fan, point, pwm);
> +	ret = xe_hwmon_update_user_fan_point(hwmon, fan, point, false, pwm);
> +
> +unlock:
> +	mutex_unlock(&hwmon->hwmon_lock);
> +
> +	return ret ? ret : count;
> +}
> +
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(0, 0));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(0, 0));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(0, 1));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(0, 1));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(0, 2));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(0, 2));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(0, 3));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point4_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(0, 3));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(0, 4));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point5_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(0, 4));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point6_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(0, 5));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point6_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(0, 5));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point7_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(0, 6));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point7_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(0, 6));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point8_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(0, 7));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point8_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(0, 7));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point9_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(0, 8));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point9_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(0, 8));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point10_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(0, 9));
> +static SENSOR_DEVICE_ATTR(pwm1_auto_point10_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(0, 9));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point1_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(1, 0));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(1, 0));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point2_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(1, 1));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(1, 1));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point3_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(1, 2));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point3_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(1, 2));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point4_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(1, 3));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point4_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(1, 3));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point5_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(1, 4));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point5_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(1, 4));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point6_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(1, 5));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point6_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(1, 5));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point7_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(1, 6));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point7_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(1, 6));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point8_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(1, 7));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point8_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(1, 7));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point9_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(1, 8));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point9_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(1, 8));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point10_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(1, 9));
> +static SENSOR_DEVICE_ATTR(pwm2_auto_point10_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(1, 9));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point1_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(2, 0));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(2, 0));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point2_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(2, 1));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(2, 1));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point3_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(2, 2));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point3_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(2, 2));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point4_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(2, 3));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point4_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(2, 3));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point5_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(2, 4));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point5_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(2, 4));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point6_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(2, 5));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point6_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(2, 5));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point7_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(2, 6));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point7_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(2, 6));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point8_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(2, 7));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point8_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(2, 7));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point9_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(2, 8));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point9_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(2, 8));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point10_temp, 0644,
> +			  xe_hwmon_pwm_auto_point_temp_show,
> +			  xe_hwmon_pwm_auto_point_temp_store,
> +			  XE_CURVE_IDX(2, 9));
> +static SENSOR_DEVICE_ATTR(pwm3_auto_point10_pwm, 0644,
> +			  xe_hwmon_pwm_auto_point_pwm_show,
> +			  xe_hwmon_pwm_auto_point_pwm_store,
> +			  XE_CURVE_IDX(2, 9));
nit: could this be collapsed with a macro, e.g.:

#define XE_FAN_POINT_ATTRS(fan, point)        \
      static SENSOR_DEVICE_ATTR(pwm##fan##_auto_point##point##_temp, 0644,\
                    xe_hwmon_pwm_auto_point_temp_show,       \
                    xe_hwmon_pwm_auto_point_temp_store,      \
                    XE_CURVE_IDX((fan) - 1, (point) - 1));   \
      static SENSOR_DEVICE_ATTR(pwm##fan##_auto_point##point##_pwm, 0644, \
                    xe_hwmon_pwm_auto_point_pwm_show,        \
                    xe_hwmon_pwm_auto_point_pwm_store,       \
                    XE_CURVE_IDX((fan) - 1, (point) - 1))

#define XE_FAN_ATTRS(fan)      \
      XE_FAN_POINT_ATTRS(fan, 1);  XE_FAN_POINT_ATTRS(fan, 2);  \
      XE_FAN_POINT_ATTRS(fan, 3);  XE_FAN_POINT_ATTRS(fan, 4);  \
      XE_FAN_POINT_ATTRS(fan, 5);  XE_FAN_POINT_ATTRS(fan, 6);  \
      XE_FAN_POINT_ATTRS(fan, 7);  XE_FAN_POINT_ATTRS(fan, 8);  \
      XE_FAN_POINT_ATTRS(fan, 9);  XE_FAN_POINT_ATTRS(fan, 10)

XE_FAN_ATTRS(1);
XE_FAN_ATTRS(2);
XE_FAN_ATTRS(3);
> +
> +static struct attribute *hwmon_curve_attributes[] = {
> +	&sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point3_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point4_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point5_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point6_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point7_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point8_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point9_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point10_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point4_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point5_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point6_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point7_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point8_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point9_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm1_auto_point10_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point3_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point4_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point5_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point6_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point7_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point8_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point9_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point10_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point3_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point4_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point5_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point6_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point7_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point8_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point9_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm2_auto_point10_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point5_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point6_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point7_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point8_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point9_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point10_temp.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point5_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point6_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point7_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point8_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point9_pwm.dev_attr.attr,
> +	&sensor_dev_attr_pwm3_auto_point10_pwm.dev_attr.attr,
> +	NULL
> +};
nit: Could the entries of hwmon_curve_attributes[] be generated with a
small macro. e.g.:

#define XE_ATTR(fan, point, kind) \
&sensor_dev_attr_pwm##fan##_auto_point##point##_##kind.dev_attr.attr

#define XE_FAN_KIND_LIST(fan, kind)                       \
      XE_ATTR(fan, 1, kind),  XE_ATTR(fan, 2, kind),        \
      XE_ATTR(fan, 3, kind),  XE_ATTR(fan, 4, kind),        \
      XE_ATTR(fan, 5, kind),  XE_ATTR(fan, 6, kind),        \
      XE_ATTR(fan, 7, kind),  XE_ATTR(fan, 8, kind),        \
      XE_ATTR(fan, 9, kind),  XE_ATTR(fan, 10, kind)

#define XE_FAN_ATTR_LIST(fan) \
      XE_FAN_KIND_LIST(fan, temp), XE_FAN_KIND_LIST(fan, pwm)

static struct attribute *hwmon_curve_attributes[] = {
      XE_FAN_ATTR_LIST(1),
      XE_FAN_ATTR_LIST(2),
      XE_FAN_ATTR_LIST(3),
      NULL,

};

Regards,
Soham
> +
> +static umode_t xe_hwmon_curve_attributes_visible(struct kobject *kobj,
> +						 struct attribute *attr, int index)
> +{
> +	struct device *dev = kobj_to_dev(kobj);
> +	struct xe_hwmon *hwmon = dev_get_drvdata(dev);
> +	u32 attrs_per_fan = 2 * MAX_FAN_CONTROL_POINTS;
> +	u32 fan = index / attrs_per_fan;
> +
> +	if (!hwmon->xe->info.has_fan_control || !IS_FAN_ENABLED(fan))
> +		return 0;
> +
> +	/* All slots must exist at registration, before the user curve has been staged. */
> +	return attr->mode;
> +}
> +
> +static const struct attribute_group hwmon_curve_attrgroup = {
> +	.attrs = hwmon_curve_attributes,
> +	.is_visible = xe_hwmon_curve_attributes_visible,
> +};
> +
>   static int xe_hwmon_read_fan_control_info(struct xe_hwmon *hwmon)
>   {
>   	struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
> @@ -2051,7 +2740,7 @@ xe_hwmon_pwm_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
>   		xe_dbg(hwmon->xe, "pwm read for fan %d: %ld\n", channel, *val);
>   		break;
>   	case hwmon_pwm_enable:
> -		*val = fi->pwm_enable_mode;
> +		*val = fi->is_full_speed ? XE_FAN_PWM_FULL_SPEED : fi->pwm_enable_mode;
>   		break;
>   	default:
>   		ret = -EOPNOTSUPP;
> @@ -2127,6 +2816,8 @@ xe_hwmon_pwm_write(struct xe_hwmon *hwmon, u32 attr, int channel, long val)
>   			       channel);
>   			fi->pwm_enable_mode = XE_FAN_PWM_AUTO_STOCK_TABLE;
>   			fi->is_full_speed = false;
> +			fi->fan_table[USER_FAN_TABLE].temp_staged = 0;
> +			fi->fan_table[USER_FAN_TABLE].speed_staged = 0;
>   		} else {
>   			ret = -EINVAL;
>   		}

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

end of thread, other threads:[~2026-10-30  6:35 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-15 19:07 [PATCH v3 0/9] Add fan control support Karthik Poosa
2026-10-15 19:07 ` [PATCH v3 1/9] drm/xe/hwmon: initialize fan-control backend and table cache Karthik Poosa
2026-10-28 18:46   ` Purkait, Soham
2026-10-29 11:34     ` Poosa, Karthik
2026-10-29 12:02       ` Purkait, Soham
2026-10-29 12:04       ` Purkait, Soham
2026-10-15 19:07 ` [PATCH v3 2/9] drm/xe/hwmon: expose fanN_max Karthik Poosa
2026-10-29  4:35   ` Purkait, Soham
2026-10-29 11:39     ` Poosa, Karthik
2026-10-15 19:07 ` [PATCH v3 3/9] drm/xe/pcode: add ordered write batch helper Karthik Poosa
2026-10-29  5:45   ` Purkait, Soham
2026-10-29 11:40     ` Poosa, Karthik
2026-10-15 19:07 ` [PATCH v3 4/9] drm/xe/hwmon: expose pwm[1-3] Karthik Poosa
2026-10-29 11:31   ` Purkait, Soham
2026-10-15 19:07 ` [PATCH v3 5/9] drm/xe/hwmon: expose pwm[1-3]_enable Karthik Poosa
2026-10-29 18:33   ` Purkait, Soham
2026-10-15 19:07 ` [PATCH v3 6/9] drm/xe/hwmon: Enable fan curve control support Karthik Poosa
2026-10-30  6:33   ` Purkait, Soham
2026-10-15 19:07 ` [PATCH v3 7/9] drm/xe/hwmon: Add kernel-doc for fan control Karthik Poosa
2026-10-15 19:07 ` [PATCH v3 8/9] drm/xe/hwmon: preserve fan user table across suspend resume Karthik Poosa
2026-10-15 19:07 ` [PATCH v3 9/9] drm/xe/hwmon: Update fan info after late binding Karthik Poosa
2026-10-15 19:46 ` ✗ CI.checkpatch: warning for Add fan control support Patchwork
2026-10-15 19:48 ` ✓ CI.KUnit: success " Patchwork
2026-10-15 21:01 ` ✗ Xe.CI.BAT: failure " Patchwork
2026-10-16  7:56 ` ✗ Xe.CI.FULL: " Patchwork
  -- strict thread matches above, loose matches on Subject: below --
2026-10-15 19:01 [PATCH v3 0/9] " Karthik Poosa
2026-10-15 19:01 ` [PATCH v3 4/9] drm/xe/hwmon: expose pwm[1-3] Karthik Poosa

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.