From: Rodrigo Vivi <rodrigo.vivi@intel.com>
To: Raag Jadav <raag.jadav@intel.com>
Cc: <lucas.demarchi@intel.com>, <matthew.d.roper@intel.com>,
<andi.shyti@linux.intel.com>, <intel-xe@lists.freedesktop.org>,
<anshuman.gupta@intel.com>, <riana.tauro@intel.com>,
<badal.nilawar@intel.com>, <karthik.poosa@intel.com>,
<aravind.iddamsetty@linux.intel.com>
Subject: Re: [PATCH v2] drm/xe/hwmon: expose fan speed
Date: Fri, 7 Mar 2025 09:33:05 -0500 [thread overview]
Message-ID: <Z8sDoWxu0dUEpAQ-@intel.com> (raw)
In-Reply-To: <20250307125112.575242-1-raag.jadav@intel.com>
On Fri, Mar 07, 2025 at 06:21:12PM +0530, Raag Jadav wrote:
> Add hwmon support for fan1_input, fan2_input and fan3_input attributes,
> which will expose fan speed of respective channels in RPM when supported
> by hardware. With this in place we can monitor fan speed using lm-sensors
> tool.
>
> v2: Rely on platform checks instead of mailbox error (Aravind, Rodrigo)
>
> Signed-off-by: Raag Jadav <raag.jadav@intel.com>
> Reviewed-by: Andi Shyti <andi.shyti@linux.intel.com>
> ---
> .../ABI/testing/sysfs-driver-intel-xe-hwmon | 24 ++++
> drivers/gpu/drm/xe/regs/xe_pcode_regs.h | 3 +
> drivers/gpu/drm/xe/xe_hwmon.c | 129 +++++++++++++++++-
> drivers/gpu/drm/xe/xe_pcode_api.h | 3 +
> 4 files changed, 158 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
> index 9bce281314df..adbb9bce15a5 100644
> --- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
> +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon
> @@ -124,3 +124,27 @@ Contact: intel-xe@lists.freedesktop.org
> Description: RO. VRAM temperature in millidegree Celsius.
>
> Only supported for particular Intel Xe graphics platforms.
> +
> +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/fan1_input
> +Date: March 2025
> +KernelVersion: 6.14
> +Contact: intel-xe@lists.freedesktop.org
> +Description: RO. Fan 1 speed in RPM.
> +
> + Only supported for particular Intel Xe graphics platforms.
> +
> +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/fan2_input
> +Date: March 2025
> +KernelVersion: 6.14
> +Contact: intel-xe@lists.freedesktop.org
> +Description: RO. Fan 2 speed in RPM.
> +
> + Only supported for particular Intel Xe graphics platforms.
> +
> +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/fan3_input
> +Date: March 2025
> +KernelVersion: 6.14
> +Contact: intel-xe@lists.freedesktop.org
> +Description: RO. Fan 3 speed in RPM.
> +
> + Only supported for particular Intel Xe graphics platforms.
> diff --git a/drivers/gpu/drm/xe/regs/xe_pcode_regs.h b/drivers/gpu/drm/xe/regs/xe_pcode_regs.h
> index 8846eb9ce2a4..c7d5d782e3f9 100644
> --- a/drivers/gpu/drm/xe/regs/xe_pcode_regs.h
> +++ b/drivers/gpu/drm/xe/regs/xe_pcode_regs.h
> @@ -21,6 +21,9 @@
> #define BMG_PACKAGE_POWER_SKU XE_REG(0x138098)
> #define BMG_PACKAGE_POWER_SKU_UNIT XE_REG(0x1380dc)
> #define BMG_PACKAGE_ENERGY_STATUS XE_REG(0x138120)
> +#define BMG_FAN_1_SPEED XE_REG(0x138140)
> +#define BMG_FAN_2_SPEED XE_REG(0x138170)
> +#define BMG_FAN_3_SPEED XE_REG(0x1381a0)
> #define BMG_VRAM_TEMPERATURE XE_REG(0x1382c0)
> #define BMG_PACKAGE_TEMPERATURE XE_REG(0x138434)
> #define BMG_PACKAGE_RAPL_LIMIT XE_REG(0x138440)
> diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
> index 48d80ffdf7bb..c52a2bfd770e 100644
> --- a/drivers/gpu/drm/xe/xe_hwmon.c
> +++ b/drivers/gpu/drm/xe/xe_hwmon.c
> @@ -5,6 +5,7 @@
>
> #include <linux/hwmon-sysfs.h>
> #include <linux/hwmon.h>
> +#include <linux/jiffies.h>
> #include <linux/types.h>
> #include <linux/units.h>
>
> @@ -27,6 +28,7 @@ enum xe_hwmon_reg {
> REG_PKG_POWER_SKU_UNIT,
> REG_GT_PERF_STATUS,
> REG_PKG_ENERGY_STATUS,
> + REG_FAN_SPEED,
> };
>
> enum xe_hwmon_reg_operation {
> @@ -42,6 +44,13 @@ enum xe_hwmon_channel {
> CHANNEL_MAX,
> };
>
> +enum xe_fan_channel {
> + FAN_1,
> + FAN_2,
> + FAN_3,
> + FAN_MAX,
> +};
> +
> /*
> * SF_* - scale factors for particular quantities according to hwmon spec.
> */
> @@ -61,6 +70,16 @@ struct xe_hwmon_energy_info {
> long accum_energy;
> };
>
> +/**
> + * struct xe_hwmon_fan_info - to cache previous fan reading
> + */
> +struct xe_hwmon_fan_info {
> + /** @reg_val_prev: previous fan reg val */
> + u32 reg_val_prev;
> + /** @time_prev: previous timestamp */
> + u64 time_prev;
> +};
> +
> /**
> * struct xe_hwmon - xe hwmon data structure
> */
> @@ -79,6 +98,8 @@ struct xe_hwmon {
> int scl_shift_time;
> /** @ei: Energy info for energyN_input */
> struct xe_hwmon_energy_info ei[CHANNEL_MAX];
> + /** @fi: Fan info for fanN_input */
> + struct xe_hwmon_fan_info fi[FAN_MAX];
> };
>
> static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg hwmon_reg,
> @@ -144,6 +165,16 @@ static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg
> return PCU_CR_PACKAGE_ENERGY_STATUS;
> }
> break;
> + case REG_FAN_SPEED:
> + if (xe->info.platform == XE_BATTLEMAGE || xe->info.platform == XE_DG2) {
we should probably have a has_fan_control flag in the platform definition struct so you
don't need to do platform checks here and it gets easier when we need to add new platforms.
> + if (channel == FAN_1)
> + return BMG_FAN_1_SPEED;
> + else if (channel == FAN_2)
> + return BMG_FAN_2_SPEED;
> + else if (channel == FAN_3)
> + return BMG_FAN_3_SPEED;
> + }
> + break;
> default:
> drm_warn(&xe->drm, "Unknown xe hwmon reg id: %d\n", hwmon_reg);
> break;
> @@ -454,6 +485,7 @@ 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),
here as well... I believe we should not expose the fan files if !has_fan_control
> NULL
> };
>
> @@ -480,6 +512,24 @@ 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_num_fans(const struct xe_hwmon *hwmon, u32 *uval)
> +{
> + struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
> +
> + /* Platforms that don't return correct value */
> + if (hwmon->xe->info.platform == XE_DG2) {
> + *uval = 2;
> + return 0;
> + }
> +
> + /* Avoid Illegal Subcommand error */
> + if (hwmon->xe->info.platform != XE_BATTLEMAGE)
> + return -ENXIO;
perhaps if the file is not exposed you don't even need this check here...
but if needed even when fan file is not exposed, then you use the
has_fan_control flag instead of the the platform checks here as well.
> +
> + return xe_pcode_read(root_tile, PCODE_MBOX(FAN_SPEED_CONTROL,
> + FSC_READ_NUM_FANS, 0), uval, NULL);
> +}
> +
> static int xe_hwmon_power_curr_crit_read(struct xe_hwmon *hwmon, int channel,
> long *value, u32 scale_factor)
> {
> @@ -705,6 +755,72 @@ 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;
> +
> + switch (attr) {
> + case hwmon_fan_input:
> + if (xe_hwmon_pcode_read_num_fans(hwmon, &uval))
> + return 0;
> +
> + return channel < uval ? 0444 : 0;
> + default:
> + return 0;
> + }
> +}
> +
> +static int
> +xe_hwmon_fan_input_read(struct xe_hwmon *hwmon, int channel, long *val)
> +{
> + struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe);
> + struct xe_hwmon_fan_info *fi = &hwmon->fi[channel];
> + u64 rotations, time_now, time;
> + u32 reg_val;
> + int ret = 0;
> +
> + mutex_lock(&hwmon->hwmon_lock);
> +
> + reg_val = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_FAN_SPEED, channel));
> + time_now = get_jiffies_64();
> +
> + /*
> + * HW register value is accumulated count of pulses from PWM fan with the scale
> + * of 2 pulses per rotation.
> + */
> + rotations = (reg_val - fi->reg_val_prev) / 2;
> +
> + time = jiffies_delta_to_msecs(time_now - fi->time_prev);
> + if (unlikely(!time)) {
> + ret = -EAGAIN;
> + goto unlock;
> + }
> +
> + /*
> + * Calculate fan speed in RPM by time averaging two subsequent readings in minutes.
> + * RPM = number of rotations * msecs per minute / time in msecs
> + */
> + *val = DIV_ROUND_UP_ULL(rotations * (MSEC_PER_SEC * 60), time);
> +
> + fi->reg_val_prev = reg_val;
> + fi->time_prev = time_now;
> +unlock:
> + mutex_unlock(&hwmon->hwmon_lock);
> + return ret;
> +}
> +
> +static int
> +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);
> + default:
> + return -EOPNOTSUPP;
> + }
> +}
> +
> static umode_t
> xe_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
> u32 attr, int channel)
> @@ -730,6 +846,9 @@ xe_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
> case hwmon_energy:
> ret = xe_hwmon_energy_is_visible(hwmon, attr, channel);
> break;
> + case hwmon_fan:
> + ret = xe_hwmon_fan_is_visible(hwmon, attr, channel);
> + break;
> default:
> ret = 0;
> break;
> @@ -765,6 +884,9 @@ xe_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
> case hwmon_energy:
> ret = xe_hwmon_energy_read(hwmon, attr, channel, val);
> break;
> + case hwmon_fan:
> + ret = xe_hwmon_fan_read(hwmon, attr, channel, val);
> + break;
> default:
> ret = -EOPNOTSUPP;
> break;
> @@ -842,7 +964,7 @@ static void
> xe_hwmon_get_preregistration_info(struct xe_hwmon *hwmon)
> {
> struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe);
> - long energy;
> + long energy, fan_speed;
> u64 val_sku_unit = 0;
> int channel;
> struct xe_reg pkg_power_sku_unit;
> @@ -866,6 +988,11 @@ xe_hwmon_get_preregistration_info(struct xe_hwmon *hwmon)
> for (channel = 0; channel < CHANNEL_MAX; channel++)
> 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);
> }
>
> static void xe_hwmon_mutex_destroy(void *arg)
> diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h
> index 2bae9afdbd35..e622ae17f08d 100644
> --- a/drivers/gpu/drm/xe/xe_pcode_api.h
> +++ b/drivers/gpu/drm/xe/xe_pcode_api.h
> @@ -49,6 +49,9 @@
> /* Domain IDs (param2) */
> #define PCODE_MBOX_DOMAIN_HBM 0x2
>
> +#define FAN_SPEED_CONTROL 0x7D
> +#define FSC_READ_NUM_FANS 0x4
> +
> #define PCODE_SCRATCH(x) XE_REG(0x138320 + ((x) * 4))
> /* PCODE_SCRATCH0 */
> #define AUXINFO_REG_OFFSET REG_GENMASK(17, 15)
> --
> 2.34.1
>
next prev parent reply other threads:[~2025-03-07 14:33 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-07 12:51 [PATCH v2] drm/xe/hwmon: expose fan speed Raag Jadav
2025-03-07 13:44 ` ✓ CI.Patch_applied: success for drm/xe/hwmon: expose fan speed (rev2) Patchwork
2025-03-07 13:44 ` ✓ CI.checkpatch: " Patchwork
2025-03-07 13:45 ` ✓ CI.KUnit: " Patchwork
2025-03-07 14:02 ` ✓ CI.Build: " Patchwork
2025-03-07 14:04 ` ✓ CI.Hooks: " Patchwork
2025-03-07 14:06 ` ✓ CI.checksparse: " Patchwork
2025-03-07 14:27 ` ✓ Xe.CI.BAT: " Patchwork
2025-03-07 14:33 ` Rodrigo Vivi [this message]
2025-03-07 17:58 ` [PATCH v2] drm/xe/hwmon: expose fan speed Raag Jadav
2025-03-07 18:07 ` Raag Jadav
2025-03-07 20:36 ` Rodrigo Vivi
2025-03-08 16:12 ` Raag Jadav
2025-03-10 17:01 ` Rodrigo Vivi
2025-03-10 17:26 ` Raag Jadav
2025-03-10 17:37 ` Rodrigo Vivi
2025-03-08 10:07 ` ✗ Xe.CI.Full: failure for drm/xe/hwmon: expose fan speed (rev2) 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=Z8sDoWxu0dUEpAQ-@intel.com \
--to=rodrigo.vivi@intel.com \
--cc=andi.shyti@linux.intel.com \
--cc=anshuman.gupta@intel.com \
--cc=aravind.iddamsetty@linux.intel.com \
--cc=badal.nilawar@intel.com \
--cc=intel-xe@lists.freedesktop.org \
--cc=karthik.poosa@intel.com \
--cc=lucas.demarchi@intel.com \
--cc=matthew.d.roper@intel.com \
--cc=raag.jadav@intel.com \
--cc=riana.tauro@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 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.