diff options
| author | Guenter Roeck <linux@roeck-us.net> | 2026-06-29 16:08:00 -0700 |
|---|---|---|
| committer | Guenter Roeck <linux@roeck-us.net> | 2026-06-29 16:25:27 -0700 |
| commit | 9ef7dacd44216bf5ea05c8aef49eba4d145f4047 (patch) | |
| tree | 1cdedcc0df833dff563ca7d8c8c905ab61c0d429 /drivers | |
| parent | 72a69101032d2932ba5bde38494a325cc6b5d614 (diff) | |
| download | linux-9ef7dacd44216bf5ea05c8aef49eba4d145f4047.tar.gz linux-9ef7dacd44216bf5ea05c8aef49eba4d145f4047.zip | |
hwmon: (pmbus) Fix passing events to regulator core
Sashiko reports:
Commit 754bd2b4a084 ("hwmon: (pmbus/core) Protect regulator operations with
mutex") introduced a worker to batch regulator events over time using
atomic_or(). The delayed worker then passes the combined bitmask unmodified
to regulator_notifier_call_chain().
The core regulator subsystem's regulator_handle_critical() function
evaluates the event parameter using a strict switch statement. If
multiple distinct faults occur before the worker runs (e.g.,
REGULATOR_EVENT_UNDER_VOLTAGE | REGULATOR_EVENT_OVER_CURRENT), the combined
bitmask fails to match any case. This leaves the reason as NULL and
completely bypasses the critical hw_protection_trigger().
Fix the problem by passing events bit by bit to the regulator event
handler.
Reported-by: Sashiko <sashiko-bot@kernel.org>
Fixes: 754bd2b4a084 ("hwmon: (pmbus/core) Protect regulator operations with mutex")
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/hwmon/pmbus/pmbus_core.c | 13 |
1 files changed, 9 insertions, 4 deletions
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 8123a568af40..3143b9e0316c 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -3347,18 +3347,23 @@ static void pmbus_regulator_notify_worker(struct work_struct *work) int i, j; for (i = 0; i < data->info->pages; i++) { - int event; + unsigned int event; event = atomic_xchg(&data->regulator_events[i], 0); if (!event) continue; for (j = 0; j < data->info->num_regulators; j++) { - if (i == rdev_get_id(data->rdevs[j])) { + if (i != rdev_get_id(data->rdevs[j])) + continue; + while (event) { + unsigned int _event = BIT(__ffs(event)); + regulator_notifier_call_chain(data->rdevs[j], - event, NULL); - break; + _event, NULL); + event &= ~_event; } + break; } } } |
