From: Guenter Roeck <linux@roeck-us.net>
To: linux-hwmon@vger.kernel.org
Cc: Guenter Roeck <linux@roeck-us.net>, Sashiko <sashiko@sashiko.dev>
Subject: [PATCH] hwmon: (gpio-fan) Fix runtime PM imbalance in probe and teardown
Date: Thu, 5 Nov 2026 10:24:27 -0800 [thread overview]
Message-ID: <20261105182427.2369928-1-linux@roeck-us.net> (raw)
In gpio_fan_probe(), gpio_fan_stop() is registered conditionally as a
devres action before runtime PM is initialized, while gpio_fan_stop()
unconditionally calls pm_runtime_disable(). This breaks runtime PM
disable_depth and usage_count invariants across several paths:
- On alarm-only devices without control GPIOs, gpio_fan_stop() is never
registered, leaving pm_runtime_enable() unbalanced on unbind and
triggering "Unbalanced pm_runtime_enable!" on subsequent binds.
- When control GPIOs are present and devm_add_action_or_reset(), hwmon
registration, or fan_alarm_init() fails, gpio_fan_stop() runs before
pm_runtime_enable(), incrementing disable_depth to 2 (leaving runtime
PM permanently disabled on re-probe) and, if speed_index > 0,
underflowing usage_count via pm_runtime_put_sync().
- If pm_runtime_resume_and_get() fails when speed_index > 0, it drops
its reference while speed_index remains non-zero, causing
gpio_fan_stop() to call pm_runtime_put_sync() and underflow
usage_count.
- Registering the hwmon device before enabling runtime PM exposes sysfs
attributes that can invoke set_fan_speed() before runtime PM state is
initialized.
Initialize runtime PM upfront with pm_runtime_set_suspended() and
devm_pm_runtime_enable(), remove pm_runtime_disable() from
gpio_fan_stop(), and acquire the initial active runtime PM reference
before registering gpio_fan_stop() and the hwmon device.
Fixes: 0d01110e6356 ("hwmon: (gpio-fan) Add regulator support")
Reported-by: Sashiko <sashiko@sashiko.dev>
Link: https://sashiko.dev/#/bug/linux-349aa3ba-30c3-4c3c-b47e-f52839af2b8d
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
---
drivers/hwmon/gpio-fan.c | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index 08b58b49be5b..402cc000bc3f 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -531,8 +531,6 @@ static void gpio_fan_stop(void *data)
mutex_lock(&fan_data->lock);
set_fan_speed(data, 0);
mutex_unlock(&fan_data->lock);
-
- pm_runtime_disable(fan_data->dev);
}
static int gpio_fan_probe(struct platform_device *pdev)
@@ -560,6 +558,11 @@ static int gpio_fan_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(fan_data->supply),
"Failed to get fan-supply");
+ pm_runtime_set_suspended(dev);
+ err = devm_pm_runtime_enable(dev);
+ if (err)
+ return err;
+
/* Configure control GPIOs if available. */
if (fan_data->gpios && fan_data->num_gpios > 0) {
if (!fan_data->speed || fan_data->num_speed <= 1)
@@ -567,6 +570,12 @@ static int gpio_fan_probe(struct platform_device *pdev)
err = fan_ctrl_init(fan_data);
if (err)
return err;
+ /* If current GPIO state is active, mark RPM as active as well */
+ if (fan_data->speed_index > 0) {
+ err = pm_runtime_resume_and_get(dev);
+ if (err)
+ return err;
+ }
err = devm_add_action_or_reset(dev, gpio_fan_stop, fan_data);
if (err)
return err;
@@ -587,17 +596,6 @@ static int gpio_fan_probe(struct platform_device *pdev)
return err;
}
- pm_runtime_set_suspended(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
- /* If current GPIO state is active, mark RPM as active as well */
- if (fan_data->speed_index > 0) {
- int ret;
-
- ret = pm_runtime_resume_and_get(&pdev->dev);
- if (ret)
- return ret;
- }
-
/* Optional cooling device register for Device tree platforms */
fan_data->cdev = devm_thermal_of_child_cooling_device_register(dev, np,
"gpio-fan",
--
2.45.2
next reply other threads:[~2026-11-05 18:24 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 18:24 Guenter Roeck [this message]
2026-11-05 18:29 ` [PATCH] hwmon: (gpio-fan) Fix runtime PM imbalance in probe and teardown sashiko-bot
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=20261105182427.2369928-1-linux@roeck-us.net \
--to=linux@roeck-us.net \
--cc=linux-hwmon@vger.kernel.org \
--cc=sashiko@sashiko.dev \
/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.