iio: common: st_sensors: Fix use of uninitialize device structs
Throughout the various probe functions &indio_dev->dev is used before it is initialized. This caused a kernel panic in st_sensors_power_enable() when the call to devm_regulator_bulk_get_enable() fails and then calls dev_err_probe() with the uninitialized device. This seems to only cause a panic with dev_err_probe(), dev_err(), dev_warn() and dev_info() don't seem to cause a panic, but are fixed as well. The issue is reported and traced here: [1] Link: https://lore.kernel.org/all/AM7P189MB100986A83D2F28AF3FFAF976E39EA@AM7P189MB1009.EURP189.PROD.OUTLOOK.COM/ [1] Cc: stable@vger.kernel.org Signed-off-by: Maud Spierings <maudspierings@gocontroll.com> Reviewed-by: Andy Shevchenko <andy@kernel.org> Link: https://... [1] Link: https://patch.msgid.link/20250527-st_iio_fix-v4-1-12d89801c761@gocontroll.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>pull/1104/head^2
parent
6ac609d1fb
commit
9f92e93e25
|
|
@ -1353,6 +1353,7 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev)
|
||||||
union acpi_object *ont;
|
union acpi_object *ont;
|
||||||
union acpi_object *elements;
|
union acpi_object *elements;
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
|
struct device *parent = indio_dev->dev.parent;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
@ -1371,7 +1372,7 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
adev = ACPI_COMPANION(indio_dev->dev.parent);
|
adev = ACPI_COMPANION(parent);
|
||||||
if (!adev)
|
if (!adev)
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
|
|
@ -1380,8 +1381,7 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev)
|
||||||
if (status == AE_NOT_FOUND) {
|
if (status == AE_NOT_FOUND) {
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
} else if (ACPI_FAILURE(status)) {
|
} else if (ACPI_FAILURE(status)) {
|
||||||
dev_warn(&indio_dev->dev, "failed to execute _ONT: %d\n",
|
dev_warn(parent, "failed to execute _ONT: %d\n", status);
|
||||||
status);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1457,12 +1457,12 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
dev_info(&indio_dev->dev, "computed mount matrix from ACPI\n");
|
dev_info(parent, "computed mount matrix from ACPI\n");
|
||||||
|
|
||||||
out:
|
out:
|
||||||
kfree(buffer.pointer);
|
kfree(buffer.pointer);
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_dbg(&indio_dev->dev,
|
dev_dbg(parent,
|
||||||
"failed to apply ACPI orientation data: %d\n", ret);
|
"failed to apply ACPI orientation data: %d\n", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
st_accel_set_fullscale_error:
|
st_accel_set_fullscale_error:
|
||||||
dev_err(&indio_dev->dev, "failed to set new fullscale.\n");
|
dev_err(indio_dev->dev.parent, "failed to set new fullscale.\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,8 +231,7 @@ int st_sensors_power_enable(struct iio_dev *indio_dev)
|
||||||
ARRAY_SIZE(regulator_names),
|
ARRAY_SIZE(regulator_names),
|
||||||
regulator_names);
|
regulator_names);
|
||||||
if (err)
|
if (err)
|
||||||
return dev_err_probe(&indio_dev->dev, err,
|
return dev_err_probe(parent, err, "unable to enable supplies\n");
|
||||||
"unable to enable supplies\n");
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -241,13 +240,14 @@ EXPORT_SYMBOL_NS(st_sensors_power_enable, "IIO_ST_SENSORS");
|
||||||
static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
|
static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
|
||||||
struct st_sensors_platform_data *pdata)
|
struct st_sensors_platform_data *pdata)
|
||||||
{
|
{
|
||||||
|
struct device *parent = indio_dev->dev.parent;
|
||||||
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
||||||
|
|
||||||
/* Sensor does not support interrupts */
|
/* Sensor does not support interrupts */
|
||||||
if (!sdata->sensor_settings->drdy_irq.int1.addr &&
|
if (!sdata->sensor_settings->drdy_irq.int1.addr &&
|
||||||
!sdata->sensor_settings->drdy_irq.int2.addr) {
|
!sdata->sensor_settings->drdy_irq.int2.addr) {
|
||||||
if (pdata->drdy_int_pin)
|
if (pdata->drdy_int_pin)
|
||||||
dev_info(&indio_dev->dev,
|
dev_info(parent,
|
||||||
"DRDY on pin INT%d specified, but sensor does not support interrupts\n",
|
"DRDY on pin INT%d specified, but sensor does not support interrupts\n",
|
||||||
pdata->drdy_int_pin);
|
pdata->drdy_int_pin);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -256,29 +256,27 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev,
|
||||||
switch (pdata->drdy_int_pin) {
|
switch (pdata->drdy_int_pin) {
|
||||||
case 1:
|
case 1:
|
||||||
if (!sdata->sensor_settings->drdy_irq.int1.mask) {
|
if (!sdata->sensor_settings->drdy_irq.int1.mask) {
|
||||||
dev_err(&indio_dev->dev,
|
dev_err(parent, "DRDY on INT1 not available.\n");
|
||||||
"DRDY on INT1 not available.\n");
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
sdata->drdy_int_pin = 1;
|
sdata->drdy_int_pin = 1;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (!sdata->sensor_settings->drdy_irq.int2.mask) {
|
if (!sdata->sensor_settings->drdy_irq.int2.mask) {
|
||||||
dev_err(&indio_dev->dev,
|
dev_err(parent, "DRDY on INT2 not available.\n");
|
||||||
"DRDY on INT2 not available.\n");
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
sdata->drdy_int_pin = 2;
|
sdata->drdy_int_pin = 2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(&indio_dev->dev, "DRDY on pdata not valid.\n");
|
dev_err(parent, "DRDY on pdata not valid.\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdata->open_drain) {
|
if (pdata->open_drain) {
|
||||||
if (!sdata->sensor_settings->drdy_irq.int1.addr_od &&
|
if (!sdata->sensor_settings->drdy_irq.int1.addr_od &&
|
||||||
!sdata->sensor_settings->drdy_irq.int2.addr_od)
|
!sdata->sensor_settings->drdy_irq.int2.addr_od)
|
||||||
dev_err(&indio_dev->dev,
|
dev_err(parent,
|
||||||
"open drain requested but unsupported.\n");
|
"open drain requested but unsupported.\n");
|
||||||
else
|
else
|
||||||
sdata->int_pin_open_drain = true;
|
sdata->int_pin_open_drain = true;
|
||||||
|
|
@ -336,6 +334,7 @@ EXPORT_SYMBOL_NS(st_sensors_dev_name_probe, "IIO_ST_SENSORS");
|
||||||
int st_sensors_init_sensor(struct iio_dev *indio_dev,
|
int st_sensors_init_sensor(struct iio_dev *indio_dev,
|
||||||
struct st_sensors_platform_data *pdata)
|
struct st_sensors_platform_data *pdata)
|
||||||
{
|
{
|
||||||
|
struct device *parent = indio_dev->dev.parent;
|
||||||
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
||||||
struct st_sensors_platform_data *of_pdata;
|
struct st_sensors_platform_data *of_pdata;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
@ -343,7 +342,7 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
|
||||||
mutex_init(&sdata->odr_lock);
|
mutex_init(&sdata->odr_lock);
|
||||||
|
|
||||||
/* If OF/DT pdata exists, it will take precedence of anything else */
|
/* If OF/DT pdata exists, it will take precedence of anything else */
|
||||||
of_pdata = st_sensors_dev_probe(indio_dev->dev.parent, pdata);
|
of_pdata = st_sensors_dev_probe(parent, pdata);
|
||||||
if (IS_ERR(of_pdata))
|
if (IS_ERR(of_pdata))
|
||||||
return PTR_ERR(of_pdata);
|
return PTR_ERR(of_pdata);
|
||||||
if (of_pdata)
|
if (of_pdata)
|
||||||
|
|
@ -370,7 +369,7 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
} else
|
} else
|
||||||
dev_info(&indio_dev->dev, "Full-scale not possible\n");
|
dev_info(parent, "Full-scale not possible\n");
|
||||||
|
|
||||||
err = st_sensors_set_odr(indio_dev, sdata->odr);
|
err = st_sensors_set_odr(indio_dev, sdata->odr);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
|
@ -405,7 +404,7 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev,
|
||||||
mask = sdata->sensor_settings->drdy_irq.int2.mask_od;
|
mask = sdata->sensor_settings->drdy_irq.int2.mask_od;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(&indio_dev->dev,
|
dev_info(parent,
|
||||||
"set interrupt line to open drain mode on pin %d\n",
|
"set interrupt line to open drain mode on pin %d\n",
|
||||||
sdata->drdy_int_pin);
|
sdata->drdy_int_pin);
|
||||||
err = st_sensors_write_data_with_mask(indio_dev, addr,
|
err = st_sensors_write_data_with_mask(indio_dev, addr,
|
||||||
|
|
@ -593,21 +592,20 @@ EXPORT_SYMBOL_NS(st_sensors_get_settings_index, "IIO_ST_SENSORS");
|
||||||
int st_sensors_verify_id(struct iio_dev *indio_dev)
|
int st_sensors_verify_id(struct iio_dev *indio_dev)
|
||||||
{
|
{
|
||||||
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
struct st_sensor_data *sdata = iio_priv(indio_dev);
|
||||||
|
struct device *parent = indio_dev->dev.parent;
|
||||||
int wai, err;
|
int wai, err;
|
||||||
|
|
||||||
if (sdata->sensor_settings->wai_addr) {
|
if (sdata->sensor_settings->wai_addr) {
|
||||||
err = regmap_read(sdata->regmap,
|
err = regmap_read(sdata->regmap,
|
||||||
sdata->sensor_settings->wai_addr, &wai);
|
sdata->sensor_settings->wai_addr, &wai);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(&indio_dev->dev,
|
return dev_err_probe(parent, err,
|
||||||
"failed to read Who-Am-I register.\n");
|
"failed to read Who-Am-I register.\n");
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sdata->sensor_settings->wai != wai) {
|
if (sdata->sensor_settings->wai != wai) {
|
||||||
dev_warn(&indio_dev->dev,
|
dev_warn(parent, "%s: WhoAmI mismatch (0x%x).\n",
|
||||||
"%s: WhoAmI mismatch (0x%x).\n",
|
indio_dev->name, wai);
|
||||||
indio_dev->name, wai);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
|
||||||
sdata->trig = devm_iio_trigger_alloc(parent, "%s-trigger",
|
sdata->trig = devm_iio_trigger_alloc(parent, "%s-trigger",
|
||||||
indio_dev->name);
|
indio_dev->name);
|
||||||
if (sdata->trig == NULL) {
|
if (sdata->trig == NULL) {
|
||||||
dev_err(&indio_dev->dev, "failed to allocate iio trigger.\n");
|
dev_err(parent, "failed to allocate iio trigger.\n");
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,7 +143,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
|
||||||
case IRQF_TRIGGER_FALLING:
|
case IRQF_TRIGGER_FALLING:
|
||||||
case IRQF_TRIGGER_LOW:
|
case IRQF_TRIGGER_LOW:
|
||||||
if (!sdata->sensor_settings->drdy_irq.addr_ihl) {
|
if (!sdata->sensor_settings->drdy_irq.addr_ihl) {
|
||||||
dev_err(&indio_dev->dev,
|
dev_err(parent,
|
||||||
"falling/low specified for IRQ but hardware supports only rising/high: will request rising/high\n");
|
"falling/low specified for IRQ but hardware supports only rising/high: will request rising/high\n");
|
||||||
if (irq_trig == IRQF_TRIGGER_FALLING)
|
if (irq_trig == IRQF_TRIGGER_FALLING)
|
||||||
irq_trig = IRQF_TRIGGER_RISING;
|
irq_trig = IRQF_TRIGGER_RISING;
|
||||||
|
|
@ -156,21 +156,19 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
|
||||||
sdata->sensor_settings->drdy_irq.mask_ihl, 1);
|
sdata->sensor_settings->drdy_irq.mask_ihl, 1);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
dev_info(&indio_dev->dev,
|
dev_info(parent,
|
||||||
"interrupts on the falling edge or active low level\n");
|
"interrupts on the falling edge or active low level\n");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IRQF_TRIGGER_RISING:
|
case IRQF_TRIGGER_RISING:
|
||||||
dev_info(&indio_dev->dev,
|
dev_info(parent, "interrupts on the rising edge\n");
|
||||||
"interrupts on the rising edge\n");
|
|
||||||
break;
|
break;
|
||||||
case IRQF_TRIGGER_HIGH:
|
case IRQF_TRIGGER_HIGH:
|
||||||
dev_info(&indio_dev->dev,
|
dev_info(parent, "interrupts active high level\n");
|
||||||
"interrupts active high level\n");
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* This is the most preferred mode, if possible */
|
/* This is the most preferred mode, if possible */
|
||||||
dev_err(&indio_dev->dev,
|
dev_err(parent,
|
||||||
"unsupported IRQ trigger specified (%lx), enforce rising edge\n", irq_trig);
|
"unsupported IRQ trigger specified (%lx), enforce rising edge\n", irq_trig);
|
||||||
irq_trig = IRQF_TRIGGER_RISING;
|
irq_trig = IRQF_TRIGGER_RISING;
|
||||||
}
|
}
|
||||||
|
|
@ -179,7 +177,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
|
||||||
if (irq_trig == IRQF_TRIGGER_FALLING ||
|
if (irq_trig == IRQF_TRIGGER_FALLING ||
|
||||||
irq_trig == IRQF_TRIGGER_RISING) {
|
irq_trig == IRQF_TRIGGER_RISING) {
|
||||||
if (!sdata->sensor_settings->drdy_irq.stat_drdy.addr) {
|
if (!sdata->sensor_settings->drdy_irq.stat_drdy.addr) {
|
||||||
dev_err(&indio_dev->dev,
|
dev_err(parent,
|
||||||
"edge IRQ not supported w/o stat register.\n");
|
"edge IRQ not supported w/o stat register.\n");
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
@ -214,13 +212,13 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev,
|
||||||
sdata->trig->name,
|
sdata->trig->name,
|
||||||
sdata->trig);
|
sdata->trig);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&indio_dev->dev, "failed to request trigger IRQ.\n");
|
dev_err(parent, "failed to request trigger IRQ.\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = devm_iio_trigger_register(parent, sdata->trig);
|
err = devm_iio_trigger_register(parent, sdata->trig);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
dev_err(&indio_dev->dev, "failed to register iio trigger.\n");
|
dev_err(parent, "failed to register iio trigger.\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
indio_dev->trig = iio_trigger_get(sdata->trig);
|
indio_dev->trig = iio_trigger_get(sdata->trig);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue