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 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.