mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 10:04:04 +02:00
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: c203c59fb5 ("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>
This commit is contained in:
parent
cb4daa450f
commit
5969c55e21
|
|
@ -453,6 +453,7 @@ enum pwm_modes {
|
|||
};
|
||||
|
||||
struct hp_wmi_hwmon_priv {
|
||||
struct mutex lock; /* protects mode, pwm */
|
||||
u8 min_rpm;
|
||||
u8 max_rpm;
|
||||
int gpu_delta;
|
||||
|
|
@ -2422,6 +2423,7 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
{
|
||||
struct hp_wmi_hwmon_priv *priv;
|
||||
int rpm, ret;
|
||||
u8 mode;
|
||||
|
||||
priv = dev_get_drvdata(dev);
|
||||
switch (type) {
|
||||
|
|
@ -2445,11 +2447,13 @@ static int hp_wmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
|||
*val = rpm_to_pwm(rpm / 100, priv);
|
||||
return 0;
|
||||
}
|
||||
switch (priv->mode) {
|
||||
scoped_guard(mutex, &priv->lock)
|
||||
mode = priv->mode;
|
||||
switch (mode) {
|
||||
case PWM_MODE_MAX:
|
||||
case PWM_MODE_MANUAL:
|
||||
case PWM_MODE_AUTO:
|
||||
*val = priv->mode;
|
||||
*val = mode;
|
||||
return 0;
|
||||
default:
|
||||
/* shouldn't happen */
|
||||
|
|
@ -2467,6 +2471,7 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
int rpm;
|
||||
|
||||
priv = dev_get_drvdata(dev);
|
||||
guard(mutex)(&priv->lock);
|
||||
switch (type) {
|
||||
case hwmon_pwm:
|
||||
if (attr == hwmon_pwm_input) {
|
||||
|
|
@ -2535,6 +2540,8 @@ static void hp_wmi_hwmon_keep_alive_handler(struct work_struct *work)
|
|||
|
||||
dwork = to_delayed_work(work);
|
||||
priv = container_of(dwork, struct hp_wmi_hwmon_priv, keep_alive_dwork);
|
||||
|
||||
guard(mutex)(&priv->lock);
|
||||
/*
|
||||
* Re-apply the current hwmon context settings.
|
||||
* NOTE: hp_wmi_apply_fan_settings will handle the re-scheduling.
|
||||
|
|
@ -2591,6 +2598,10 @@ static int hp_wmi_hwmon_init(void)
|
|||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_mutex_init(dev, &priv->lock);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = hp_wmi_setup_fan_settings(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user