Skip to content

Commit 5969c55

Browse files
emomaxdij-intel
authored andcommitted
platform/x86: hp-wmi: add locking for concurrent hwmon access
hp_wmi_hwmon_priv.mode and .pwm are written by hp_wmi_hwmon_write() in sysfs context and read by hp_wmi_hwmon_keep_alive_handler() in a workqueue. A concurrent write and keep-alive expiry can observe an inconsistent mode/pwm pair (e.g. mode=MANUAL with a stale pwm). Add a mutex to hp_wmi_hwmon_priv protecting mode and pwm. Hold it in hp_wmi_hwmon_write() across the field update and apply call, and in hp_wmi_hwmon_keep_alive_handler() before calling apply. In hp_wmi_hwmon_read(), only the pwm_enable path reads priv->mode; use scoped_guard() there to avoid holding the lock across unrelated WMI calls. Fixes: c203c59 ("platform/x86: hp-wmi: implement fan keep-alive") Suggested-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Emre Cecanpunar <emreleno@gmail.com> Link: https://patch.msgid.link/20260407142515.20683-6-emreleno@gmail.com Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
1 parent cb4daa4 commit 5969c55

1 file changed

Lines changed: 13 additions & 2 deletions

File tree

drivers/platform/x86/hp/hp-wmi.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ enum pwm_modes {
453453
};
454454

455455
struct hp_wmi_hwmon_priv {
456+
struct mutex lock; /* protects mode, pwm */
456457
u8 min_rpm;
457458
u8 max_rpm;
458459
int gpu_delta;
@@ -2422,6 +2423,7 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
24222423
{
24232424
struct hp_wmi_hwmon_priv *priv;
24242425
int rpm, ret;
2426+
u8 mode;
24252427

24262428
priv = dev_get_drvdata(dev);
24272429
switch (type) {
@@ -2445,11 +2447,13 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
24452447
*val = rpm_to_pwm(rpm / 100, priv);
24462448
return 0;
24472449
}
2448-
switch (priv->mode) {
2450+
scoped_guard(mutex, &priv->lock)
2451+
mode = priv->mode;
2452+
switch (mode) {
24492453
case PWM_MODE_MAX:
24502454
case PWM_MODE_MANUAL:
24512455
case PWM_MODE_AUTO:
2452-
*val = priv->mode;
2456+
*val = mode;
24532457
return 0;
24542458
default:
24552459
/* shouldn't happen */
@@ -2467,6 +2471,7 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
24672471
int rpm;
24682472

24692473
priv = dev_get_drvdata(dev);
2474+
guard(mutex)(&priv->lock);
24702475
switch (type) {
24712476
case hwmon_pwm:
24722477
if (attr == hwmon_pwm_input) {
@@ -2535,6 +2540,8 @@ static void hp_wmi_hwmon_keep_alive_handler(struct work_struct *work)
25352540

25362541
dwork = to_delayed_work(work);
25372542
priv = container_of(dwork, struct hp_wmi_hwmon_priv, keep_alive_dwork);
2543+
2544+
guard(mutex)(&priv->lock);
25382545
/*
25392546
* Re-apply the current hwmon context settings.
25402547
* NOTE: hp_wmi_apply_fan_settings will handle the re-scheduling.
@@ -2591,6 +2598,10 @@ static int hp_wmi_hwmon_init(void)
25912598
if (!priv)
25922599
return -ENOMEM;
25932600

2601+
ret = devm_mutex_init(dev, &priv->lock);
2602+
if (ret)
2603+
return ret;
2604+
25942605
ret = hp_wmi_setup_fan_settings(priv);
25952606
if (ret)
25962607
return ret;

0 commit comments

Comments
 (0)