Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: "Poosa, Karthik" <karthik.poosa@intel.com>
To: "Nilawar, Badal" <badal.nilawar@intel.com>,
	<intel-xe@lists.freedesktop.org>
Cc: <rodrigo.vivi@intel.com>, <anshuman.gupta@intel.com>,
	<raag.jadav@intel.com>, <riana.tauro@intel.com>,
	<sk.anirban@intel.com>, <mallesh.koujalagi@intel.com>,
	<soham.purkait@intel.com>
Subject: Re: [PATCH v2 2/9] drm/xe/hwmon: initialize fan-control backend and table cache
Date: Tue, 25 Aug 2026 21:40:59 +0530	[thread overview]
Message-ID: <24b6ba1b-e3d7-4a83-a6dd-7e4873ccbefa@intel.com> (raw)
In-Reply-To: <9277b78f-94a9-4b88-aa27-13b7d42fc223@intel.com>

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


On 10-08-2026 11:33, Nilawar, Badal wrote:
>
>
> On 17-07-2026 09:47, 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.
>>
>> Signed-off-by: Karthik Poosa<karthik.poosa@intel.com>
>> Assisted-by: Codex:gpt-5-4
>> ---
>>   drivers/gpu/drm/xe/xe_hwmon.c     | 159 +++++++++++++++++++++++++++---
>>   drivers/gpu/drm/xe/xe_pcode_api.h |   5 +
>>   2 files changed, 149 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
>> index de3f2aeffc3f..0a416e3e7b8c 100644
>> --- a/drivers/gpu/drm/xe/xe_hwmon.c
>> +++ b/drivers/gpu/drm/xe/xe_hwmon.c
>> @@ -20,6 +20,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"
>>   
>> @@ -122,14 +123,50 @@ 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 table slots tracked per fan */
>> +	FAN_TABLE_MAX,
>> +};
>> +
>> +/* 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)))
>> +
>> +/* PCODE operations timeout for fan control commands */
>> +#define XE_PCODE_FAN_CONTROL_TIMEOUT_MS	(10)
>> +
>>   /**
>> - * 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 {
>> +		/** @fan_control_point_count: number of supported fan control points */
>> +		u8 fan_control_point_count;
>> +		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;
>>   };
>>   
>>   /**
>> @@ -168,6 +205,8 @@ struct xe_hwmon {
>>   	int scl_shift_time;
>>   	/** @ei: Energy info for energyN_input */
>>   	struct xe_hwmon_energy_info ei[CHANNEL_MAX];
>> +	/** @num_fans: number of fans available */
>> +	u8 num_fans;
>>   	/** @fi: Fan info for fanN_input */
>>   	struct xe_hwmon_fan_info fi[FAN_MAX];
>>   	/** @boot_power_limit_read: is boot power limits read */
>> @@ -856,17 +895,100 @@ 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_timeout(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL, subcmd, fan_num),
>> +				     uval, NULL, XE_PCODE_FAN_CONTROL_TIMEOUT_MS);
>> +}
>> +
>> +static int xe_hwmon_get_num_fans(const struct xe_hwmon *hwmon, u32 *num_fans)
>> +{
>> +	u32 fan_mask = 0;
>> +	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) {
>> +		*num_fans = 2;
>>   		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, &fan_mask);
>> +	if (ret) {
>> +		xe_warn(hwmon->xe, "failed to read number of fans, ret=%d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	*num_fans = min_t(u32, hweight32(fan_mask), FAN_MAX);
>> +
>> +	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 < hwmon->num_fans; fan++) {
>> +		u32 stock_fcp_count = 0;
>> +
>> +		struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
>> +
>> +		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 control point count, ret=%d\n",
>> +			       fan, ret);
>> +			return ret;
>> +		}
>> +		fi->fan_table[STOCK_FAN_TABLE].fan_control_point_count =
>> +				min_t(u8, stock_fcp_count, MAX_FAN_CONTROL_POINTS);
>> +
>> +		xe_dbg(hwmon->xe, "fan %d stock points %u\n", fan,
>> +		       fi->fan_table[STOCK_FAN_TABLE].fan_control_point_count);
>> +
>> +		/* Dump the stock fan control points for debugging purposes. */
>> +		for (point = 0; point < fi->fan_table[STOCK_FAN_TABLE].fan_control_point_count;
>> +		     point++) {
>> +			u32 fcp = 0;
>> +
>> +			fcp = FCP_INDEX(STOCK_FAN_TABLE, point);
>> +			ret = xe_pcode_read_timeout(root_tile,
>> +						    PCODE_MBOX(FAN_SPEED_CONTROL,
>> +							       FSC_READ_FAN_TABLE, fan),
>> +						    &fcp, NULL, XE_PCODE_FAN_CONTROL_TIMEOUT_MS);
>> +			if (ret) {
>> +				xe_err(hwmon->xe, "failed to read fan %d stock point %d, ret=%d\n",
>> +				       fan, point, ret);
>> +				continue;
>> +			}
>> +
>> +			/* Cache the stock fan control points in local structure for later use. */
>> +			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_err(hwmon->xe, "failed to read fan %d min PWM, ret=%d\n", fan, ret);
>> +			continue;
>> +		}
>> +
>> +		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,
>> @@ -1279,17 +1401,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 channel < hwmon->num_fans ? 0444 : 0;
>>   	default:
>>   		return 0;
>>   	}
>> @@ -1476,6 +1593,7 @@ xe_hwmon_get_preregistration_info(struct xe_hwmon *hwmon)
>>   	u64 val_sku_unit = 0;
>>   	int channel;
>>   	struct xe_reg pkg_power_sku_unit;
>> +	u32 num_fans = 0;
>>   
>>   	if (hwmon->xe->info.has_mbx_power_limits) {
>>   		/* Check if GPU firmware support mailbox power limits commands. */
>> @@ -1531,10 +1649,21 @@ 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_num_fans(hwmon, &num_fans);
>> +
>> +		xe_info(hwmon->xe, "Number of fans detected: %u\n", num_fans);
>> +		hwmon->num_fans = num_fans;
>> +
>> +		/* Initialize 'struct xe_hwmon_fan_info' with initial fan register reading. */
>> +		for (channel = 0; channel < hwmon->num_fans; channel++)
>> +			if (xe_hwmon_is_visible(hwmon, hwmon_fan, hwmon_fan_input, 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");
>
> The table appears to be captured before late binding. Do we need 
> separate pre-/post-LB tables, or should the table be updated again 
> after late binding done?
>
> Thanks,
> Badal
>
Yes, the stock table is captured before late binding.

I don't think separate pre-/post-LB tables are necessary. We can simply 
overwrite the cached stock table after late binding completes via 
|xe_hwmon_fan_update_post_lb()|.

When late binding is disabled, the default stock table should remain in 
use. So we can cache the default table initially and update it only when 
late binding is applied.


>> +	}
>>   
>>   	if (hwmon->xe->info.has_mbx_thermal_info && xe_hwmon_pcode_read_thermal_info(hwmon))
>>   		drm_warn(&hwmon->xe->drm, "Thermal mailbox not supported by card firmware\n");
>> diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h
>> index 94575c476e3d..669010f1e2d0 100644
>> --- a/drivers/gpu/drm/xe/xe_pcode_api.h
>> +++ b/drivers/gpu/drm/xe/xe_pcode_api.h
>> @@ -85,6 +85,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: 11785 bytes --]

  reply	other threads:[~2026-08-25 16:11 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-17  4:17 [PATCH v2 0/9] Add fan control support Karthik Poosa
2026-07-17  4:16 ` ✓ CI.KUnit: success for Add fan control support (rev2) Patchwork
2026-07-17  4:17 ` [PATCH v2 1/9] drm/xe/pcode: Introduce xe_pcode_read_timeout() API Karthik Poosa
2026-07-17  4:17 ` [PATCH v2 2/9] drm/xe/hwmon: initialize fan-control backend and table cache Karthik Poosa
2026-08-10  6:03   ` Nilawar, Badal
2026-08-25 16:10     ` Poosa, Karthik [this message]
2026-08-11 13:11   ` Nilawar, Badal
2026-08-17 17:01     ` Poosa, Karthik
2026-08-25 16:14     ` Poosa, Karthik
2026-07-17  4:17 ` [PATCH v2 3/9] drm/xe/hwmon: expose fanN_max Karthik Poosa
2026-07-23  5:34   ` Purkait, Soham
2026-07-17  4:17 ` [PATCH v2 4/9] drm/xe/hwmon: expose pwm[1-3] Karthik Poosa
2026-07-24  7:02   ` Purkait, Soham
2026-08-11 13:58     ` Poosa, Karthik
2026-07-17  4:17 ` [PATCH v2 5/9] drm/xe/hwmon: expose pwm[1-3]_enable Karthik Poosa
2026-07-17  4:17 ` [PATCH v2 6/9] drm/xe/hwmon: Enable fan curve control support Karthik Poosa
2026-07-22 18:16   ` Purkait, Soham
2026-08-27 12:07     ` Poosa, Karthik
2026-07-17  4:17 ` [PATCH v2 7/9] drm/xe/hwmon: Add kernel-doc for fan control Karthik Poosa
2026-07-17  4:17 ` [PATCH v2 8/9] drm/xe/hwmon: preserve fan user table across suspend resume Karthik Poosa
2026-08-10  5:53   ` Nilawar, Badal
2026-08-27 10:27     ` Poosa, Karthik
2026-07-17  4:17 ` [PATCH v2 9/9] drm/xe/hwmon: Update fan info after late binding Karthik Poosa
2026-07-20  6:20   ` Purkait, Soham
2026-08-27 10:36     ` Poosa, Karthik
2026-07-17  5:00 ` ✓ Xe.CI.BAT: success for Add fan control support (rev2) Patchwork
2026-07-17  8:18 ` ✗ Xe.CI.FULL: failure " Patchwork

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=24b6ba1b-e3d7-4a83-a6dd-7e4873ccbefa@intel.com \
    --to=karthik.poosa@intel.com \
    --cc=anshuman.gupta@intel.com \
    --cc=badal.nilawar@intel.com \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=mallesh.koujalagi@intel.com \
    --cc=raag.jadav@intel.com \
    --cc=riana.tauro@intel.com \
    --cc=rodrigo.vivi@intel.com \
    --cc=sk.anirban@intel.com \
    --cc=soham.purkait@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox