Skip to content

Commit 9e2eae9

Browse files
emomaxdgregkh
authored andcommitted
platform/x86: hp-wmi: add locking for concurrent hwmon access
[ Upstream commit 5969c55 ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent e9fca2b commit 9e2eae9

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
@@ -458,6 +458,7 @@ enum pwm_modes {
458458
};
459459

460460
struct hp_wmi_hwmon_priv {
461+
struct mutex lock; /* protects mode, pwm */
461462
u8 min_rpm;
462463
u8 max_rpm;
463464
int gpu_delta;
@@ -2427,6 +2428,7 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
24272428
{
24282429
struct hp_wmi_hwmon_priv *priv;
24292430
int rpm, ret;
2431+
u8 mode;
24302432

24312433
priv = dev_get_drvdata(dev);
24322434
switch (type) {
@@ -2450,11 +2452,13 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
24502452
*val = rpm_to_pwm(rpm / 100, priv);
24512453
return 0;
24522454
}
2453-
switch (priv->mode) {
2455+
scoped_guard(mutex, &priv->lock)
2456+
mode = priv->mode;
2457+
switch (mode) {
24542458
case PWM_MODE_MAX:
24552459
case PWM_MODE_MANUAL:
24562460
case PWM_MODE_AUTO:
2457-
*val = priv->mode;
2461+
*val = mode;
24582462
return 0;
24592463
default:
24602464
/* shouldn't happen */
@@ -2472,6 +2476,7 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
24722476
int rpm;
24732477

24742478
priv = dev_get_drvdata(dev);
2479+
guard(mutex)(&priv->lock);
24752480
switch (type) {
24762481
case hwmon_pwm:
24772482
if (attr == hwmon_pwm_input) {
@@ -2540,6 +2545,8 @@ static void hp_wmi_hwmon_keep_alive_handler(struct work_struct *work)
25402545

25412546
dwork = to_delayed_work(work);
25422547
priv = container_of(dwork, struct hp_wmi_hwmon_priv, keep_alive_dwork);
2548+
2549+
guard(mutex)(&priv->lock);
25432550
/*
25442551
* Re-apply the current hwmon context settings.
25452552
* NOTE: hp_wmi_apply_fan_settings will handle the re-scheduling.
@@ -2596,6 +2603,10 @@ static int hp_wmi_hwmon_init(void)
25962603
if (!priv)
25972604
return -ENOMEM;
25982605

2606+
ret = devm_mutex_init(dev, &priv->lock);
2607+
if (ret)
2608+
return ret;
2609+
25992610
ret = hp_wmi_setup_fan_settings(priv);
26002611
if (ret)
26012612
return ret;

0 commit comments

Comments
 (0)