mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
hwmon: chipcap2: fix IRQ teardown ordering
The threaded IRQs are currently requested before the hwmon device
is registered. Since devres releases resources in reverse order,
the hwmon device is unregistered before the IRQs are freed during
driver teardown. An IRQ may therefore still run after the hwmon
device has been released and access the stale data->hwmon pointer.
Separate IRQ discovery from IRQ registration so that the IRQ numbers
and alarm visibility flags are initialized before registering the
hwmon device while the IRQs are released before the hwmon device
during devres cleanup.
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-5-27ebfc2c5b9e@gmail.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
parent
b5a1412618
commit
d2a66c515d
|
|
@ -631,32 +631,47 @@ static int cc2_write(struct device *dev, enum hwmon_sensor_types type, u32 attr,
|
|||
}
|
||||
}
|
||||
|
||||
static int cc2_request_ready_irq(struct cc2_data *data, struct device *dev)
|
||||
static int cc2_get_irqs(struct cc2_data *data, struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
data->irq_ready = fwnode_irq_get_byname(dev_fwnode(dev), "ready");
|
||||
if (data->irq_ready == -EPROBE_DEFER)
|
||||
return data->irq_ready;
|
||||
if (data->irq_ready > 0) {
|
||||
if (data->irq_ready > 0)
|
||||
init_completion(&data->complete);
|
||||
|
||||
data->irq_low = fwnode_irq_get_byname(dev_fwnode(dev), "low");
|
||||
if (data->irq_low == -EPROBE_DEFER)
|
||||
return data->irq_low;
|
||||
if (data->irq_low > 0)
|
||||
data->rh_alarm.low_alarm_visible = true;
|
||||
|
||||
data->irq_high = fwnode_irq_get_byname(dev_fwnode(dev), "high");
|
||||
if (data->irq_high == -EPROBE_DEFER)
|
||||
return data->irq_high;
|
||||
if (data->irq_high > 0)
|
||||
data->rh_alarm.high_alarm_visible = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cc2_request_data_ready(struct cc2_data *data, struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (data->irq_ready > 0)
|
||||
ret = devm_request_threaded_irq(dev, data->irq_ready, NULL,
|
||||
cc2_ready_interrupt,
|
||||
IRQF_ONESHOT |
|
||||
IRQF_TRIGGER_RISING,
|
||||
dev_name(dev), data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cc2_request_alarm_irqs(struct cc2_data *data, struct device *dev)
|
||||
static int cc2_request_alarms(struct cc2_data *data, struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
data->irq_low = fwnode_irq_get_byname(dev_fwnode(dev), "low");
|
||||
if (data->irq_low == -EPROBE_DEFER)
|
||||
return data->irq_low;
|
||||
if (data->irq_low > 0) {
|
||||
ret = devm_request_threaded_irq(dev, data->irq_low, NULL,
|
||||
cc2_low_interrupt,
|
||||
|
|
@ -665,13 +680,8 @@ static int cc2_request_alarm_irqs(struct cc2_data *data, struct device *dev)
|
|||
dev_name(dev), data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->rh_alarm.low_alarm_visible = true;
|
||||
}
|
||||
|
||||
data->irq_high = fwnode_irq_get_byname(dev_fwnode(dev), "high");
|
||||
if (data->irq_high == -EPROBE_DEFER)
|
||||
return data->irq_high;
|
||||
if (data->irq_high > 0) {
|
||||
ret = devm_request_threaded_irq(dev, data->irq_high, NULL,
|
||||
cc2_high_interrupt,
|
||||
|
|
@ -680,8 +690,6 @@ static int cc2_request_alarm_irqs(struct cc2_data *data, struct device *dev)
|
|||
dev_name(dev), data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
data->rh_alarm.high_alarm_visible = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
@ -732,14 +740,14 @@ static int cc2_probe(struct i2c_client *client)
|
|||
|
||||
device_property_read_string(dev, "label", &data->label);
|
||||
|
||||
ret = cc2_request_ready_irq(data, dev);
|
||||
ret = cc2_get_irqs(data, dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to get IRQs\n");
|
||||
|
||||
ret = cc2_request_data_ready(data, dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to request ready irq\n");
|
||||
|
||||
ret = cc2_request_alarm_irqs(data, dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to request alarm irqs\n");
|
||||
|
||||
data->hwmon = devm_hwmon_device_register_with_info(dev, client->name,
|
||||
data, &cc2_chip_info,
|
||||
NULL);
|
||||
|
|
@ -747,6 +755,10 @@ static int cc2_probe(struct i2c_client *client)
|
|||
return dev_err_probe(dev, PTR_ERR(data->hwmon),
|
||||
"Failed to register hwmon device\n");
|
||||
|
||||
ret = cc2_request_alarms(data, dev);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to request alarm irqs\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user