mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
hwmon: chipcap2: serialize access to the alarm indicators
low_alarm and high_alarm are accessed from the threaded interrupt
handlers and from sysfs without any locking, which can lead to lost
alarms.
Add a mutex to serialize the access to the alarm indicators and to
process_irqs, which the handlers use to decide whether an interrupt
belongs to an ongoing operation.
Fixes: 3af350929e ("hwmon: Add support for Amphenol ChipCap 2")
Cc: stable@vger.kernel.org
Signed-off-by: Javier Carrasco <javier.carrasco.cruz@gmail.com>
Link: https://patch.msgid.link/20261014-chipcap2_locks-v3-10-27ebfc2c5b9e@gmail.com
[groeck: Dropped obsolete 'Assisted-by: tag]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
parent
22aecf164e
commit
bed5f0c075
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
|
@ -91,6 +92,8 @@ struct cc2_data {
|
|||
int irq_low;
|
||||
int irq_high;
|
||||
bool process_irqs;
|
||||
/* protects process_irqs and the alarm indicators */
|
||||
struct mutex irq_lock;
|
||||
bool regulator_enabled;
|
||||
};
|
||||
|
||||
|
|
@ -122,7 +125,8 @@ static int cc2_enable(struct cc2_data *data)
|
|||
|
||||
/* exclusive regulator, check in case a disable failed */
|
||||
if (data->regulator_enabled) {
|
||||
data->process_irqs = true;
|
||||
scoped_guard(mutex, &data->irq_lock)
|
||||
data->process_irqs = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -137,7 +141,8 @@ static int cc2_enable(struct cc2_data *data)
|
|||
|
||||
usleep_range(CC2_STARTUP_TIME_US, CC2_STARTUP_TIME_US + 125);
|
||||
|
||||
data->process_irqs = true;
|
||||
scoped_guard(mutex, &data->irq_lock)
|
||||
data->process_irqs = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -154,7 +159,8 @@ static void cc2_disable(struct cc2_data *data)
|
|||
synchronize_irq(data->irq_high);
|
||||
|
||||
/* ignore alarms triggered by voltage toggling when powering up */
|
||||
data->process_irqs = false;
|
||||
scoped_guard(mutex, &data->irq_lock)
|
||||
data->process_irqs = false;
|
||||
|
||||
/* exclusive regulator, check in case an enable failed */
|
||||
if (!data->regulator_enabled)
|
||||
|
|
@ -514,10 +520,12 @@ static irqreturn_t cc2_low_interrupt(int irq, void *data)
|
|||
{
|
||||
struct cc2_data *cc2 = data;
|
||||
|
||||
if (cc2->process_irqs) {
|
||||
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
|
||||
hwmon_humidity_min_alarm, 0);
|
||||
cc2->rh_alarm.low_alarm = true;
|
||||
scoped_guard(mutex, &cc2->irq_lock) {
|
||||
if (cc2->process_irqs) {
|
||||
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
|
||||
hwmon_humidity_min_alarm, 0);
|
||||
cc2->rh_alarm.low_alarm = true;
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
|
@ -527,10 +535,12 @@ static irqreturn_t cc2_high_interrupt(int irq, void *data)
|
|||
{
|
||||
struct cc2_data *cc2 = data;
|
||||
|
||||
if (cc2->process_irqs) {
|
||||
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
|
||||
hwmon_humidity_max_alarm, 0);
|
||||
cc2->rh_alarm.high_alarm = true;
|
||||
scoped_guard(mutex, &cc2->irq_lock) {
|
||||
if (cc2->process_irqs) {
|
||||
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
|
||||
hwmon_humidity_max_alarm, 0);
|
||||
cc2->rh_alarm.high_alarm = true;
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
|
@ -546,11 +556,13 @@ static int cc2_humidity_min_alarm_status(struct cc2_data *data, long *val)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (data->rh_alarm.low_alarm) {
|
||||
*val = (measurement < min_hyst) ? 1 : 0;
|
||||
data->rh_alarm.low_alarm = *val;
|
||||
} else {
|
||||
*val = 0;
|
||||
scoped_guard(mutex, &data->irq_lock) {
|
||||
if (data->rh_alarm.low_alarm) {
|
||||
*val = (measurement < min_hyst) ? 1 : 0;
|
||||
data->rh_alarm.low_alarm = *val;
|
||||
} else {
|
||||
*val = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -566,11 +578,13 @@ static int cc2_humidity_max_alarm_status(struct cc2_data *data, long *val)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (data->rh_alarm.high_alarm) {
|
||||
*val = (measurement > max_hyst) ? 1 : 0;
|
||||
data->rh_alarm.high_alarm = *val;
|
||||
} else {
|
||||
*val = 0;
|
||||
scoped_guard(mutex, &data->irq_lock) {
|
||||
if (data->rh_alarm.high_alarm) {
|
||||
*val = (measurement > max_hyst) ? 1 : 0;
|
||||
data->rh_alarm.high_alarm = *val;
|
||||
} else {
|
||||
*val = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -753,6 +767,8 @@ static int cc2_probe(struct i2c_client *client)
|
|||
|
||||
i2c_set_clientdata(client, data);
|
||||
|
||||
mutex_init(&data->irq_lock);
|
||||
|
||||
data->client = client;
|
||||
|
||||
data->regulator = devm_regulator_get_exclusive(dev, "vdd");
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user