From: "Nilawar, Badal" <badal.nilawar@intel.com>
To: Karthik Poosa <karthik.poosa@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 8/9] drm/xe/hwmon: preserve fan user table across suspend resume
Date: Mon, 10 Aug 2026 11:23:36 +0530 [thread overview]
Message-ID: <027a204a-82fe-4146-9e33-3fda70406906@intel.com> (raw)
In-Reply-To: <20260717041757.2759084-9-karthik.poosa@intel.com>
On 17-07-2026 09:47, Karthik Poosa wrote:
> Save and restore active fan user tables over suspend/resume via new
> xe_hwmon PM hooks, and run restore, only when d3cold is allowed.
>
> Signed-off-by: Karthik Poosa <karthik.poosa@intel.com>
> Assisted-by: Codex:gpt-5-3
> ---
> drivers/gpu/drm/xe/xe_hwmon.c | 133 ++++++++++++++++++++++++++++++++++
> drivers/gpu/drm/xe/xe_hwmon.h | 4 +
> drivers/gpu/drm/xe/xe_pm.c | 9 +++
> 3 files changed, 146 insertions(+)
>
> diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c
> index 770f07fb6511..65f356c741f5 100644
> --- a/drivers/gpu/drm/xe/xe_hwmon.c
> +++ b/drivers/gpu/drm/xe/xe_hwmon.c
> @@ -229,6 +229,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;
> };
>
> /**
> @@ -2785,4 +2787,135 @@ int xe_hwmon_register(struct xe_device *xe)
>
> return 0;
> }
> +
> +/**
> + * 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 < hwmon->num_fans; fan++) {
> + struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
> + u32 point_count;
> + int ret;
> +
> + /*
> + * Record whether this fan was using the user table
> + * so resume can restore it if firmware state is reset.
> + */
> + fi->restore_user_table = (fi->pwm_enable_mode != XE_FAN_PWM_AUTO_STOCK_TABLE);
> +
> + xe_dbg(hwmon->xe, "fan %d user table restore flag set to %d\n", fan,
> + fi->restore_user_table);
> +
> + if (!fi->restore_user_table)
> + continue;
> +
> + ret = xe_hwmon_get_fan_point_count(hwmon, fan, &point_count, USER_FAN_TABLE);
> + if (ret || !point_count) {
> + xe_warn(hwmon->xe,
> + "fan %d point count read before suspend failed, ret=%d, val =%u\n",
> + fan, ret, point_count);
> + continue;
> + }
> +
> + fi->fan_table[USER_FAN_TABLE].fan_control_point_count =
> + min_t(u32, point_count, MAX_FAN_CONTROL_POINTS);
> +
> + for (int point = 0; point < fi->fan_table[USER_FAN_TABLE].fan_control_point_count;
> + point++) {
> + u32 fcp = FCP_INDEX(USER_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_warn(hwmon->xe,
> + "fan %d user point %d before suspend failed, ret=%d\n",
> + fan, point, ret);
> + continue;
> + }
> +
> + fi->fan_table[USER_FAN_TABLE].fcp[point].temp =
> + REG_FIELD_GET(FAN_CONTROL_POINT_TEMP_MASK, fcp);
> + fi->fan_table[USER_FAN_TABLE].fcp[point].speed =
> + REG_FIELD_GET(FAN_CONTROL_POINT_SPEED_MASK, fcp);
> + }
> + xe_dbg(hwmon->xe,
> + "fan %d user table snapshot taken before suspend, point_count=%u\n", fan,
> + fi->fan_table[USER_FAN_TABLE].fan_control_point_count);
> + }
The above loop appears to save the fan table when restore_user_table is
set. Is this required? It seems restoring the table during resume should
be sufficient, as the fan points are already cached.
Thanks,
Badal
> +
> + 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 < hwmon->num_fans; fan++) {
> + struct xe_hwmon_fan_info *fi = &hwmon->fi[fan];
> + int ret;
> +
> + 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);
> +
> + 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 99562f691080..23a78fa4a71e 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.
> @@ -724,6 +731,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);
>
next prev parent reply other threads:[~2026-08-10 5:53 UTC|newest]
Thread overview: 21+ 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-11 13:11 ` Nilawar, Badal
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-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 [this message]
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-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=027a204a-82fe-4146-9e33-3fda70406906@intel.com \
--to=badal.nilawar@intel.com \
--cc=anshuman.gupta@intel.com \
--cc=intel-xe@lists.freedesktop.org \
--cc=karthik.poosa@intel.com \
--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