summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2026-06-29 16:08:00 -0700
committerGuenter Roeck <linux@roeck-us.net>2026-06-29 16:25:27 -0700
commit9ef7dacd44216bf5ea05c8aef49eba4d145f4047 (patch)
tree1cdedcc0df833dff563ca7d8c8c905ab61c0d429 /drivers
parent72a69101032d2932ba5bde38494a325cc6b5d614 (diff)
downloadlinux-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.c13
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;
}
}
}