Devicetree
 help / color / mirror / Atom feed
From: "Javier Carrasco" <javier.carrasco.cruz@gmail.com>
To: <sashiko-reviews@lists.linux.dev>,
	"Javier Carrasco" <javier.carrasco.cruz@gmail.com>
Cc: <robh@kernel.org>, <devicetree@vger.kernel.org>, <conor+dt@kernel.org>
Subject: Re: [PATCH v5 4/4] iio: light: veml6031x00: add support for events and trigger
Date: Sat, 08 Aug 2026 08:35:08 +0200	[thread overview]
Message-ID: <DKJCQRNBH477.3C9CC4KCFAMNK@gmail.com> (raw)
In-Reply-To: <20260807150823.49A101F000E9@smtp.kernel.org>

On Fri Aug 7, 2026 at 5:08 PM CEST, sashiko-bot wrote:
> Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
> - [High] Unbalanced PM runtime usage counter causes an underflow on device unbind or probe error.
> - [High] Uninitialized padding in the local `scan` buffer leaks kernel stack memory to userspace.
> - [High] Spurious interrupts cause I2C reads while the device is runtime suspended.
> - [High] Initialization order and use-after-destroy race due to early IRQ/trigger registration.
> - [High] Triggered buffer is unconditionally registered on the no-IRQ path with a malformed channels array.
> - [Medium] Missing timestamp acquisition for nested trigger handler.
> - [Medium] Trigger disable sequence violates hardware constraints by clearing AF before AF_TRIG.
> --
>
> --- Patch [4]: [PATCH v5 4/4] iio: light: veml6031x00: add support for events and trigger ---
> commit aeccd415dcc79cfa9463cf8b5eec2292ee46dfab
> Author: Javier Carrasco <javier.carrasco.cruz@gmail.com>
>
> iio: light: veml6031x00: add support for events and trigger
>
> The device provides a shared interrupt line for to notify events and
> data ready, which can be used as a trigger. The interrupt line is not a
> requirement for the device to work. Implement variants for the cases
> whether the interrupt line is provided or not.
>
>> diff --git a/drivers/iio/light/veml6031x00.c b/drivers/iio/light/veml6031x00.c
>> index 0cccd40d729eb..e193f87e6740f 100644
>> --- a/drivers/iio/light/veml6031x00.c
>> +++ b/drivers/iio/light/veml6031x00.c
> [ ... ]
>> @@ -494,13 +686,205 @@ static int veml6031x00_write_raw_get_fmt(struct iio_dev *indio_dev,
> [ ... ]
>> +static irqreturn_t veml6031x00_interrupt(int irq, void *private)
>> +{
>> +	struct iio_dev *iio = private;
>> +	struct veml6031x00_data *data = iio_priv(iio);
>> +	s64 timestamp;
>> +	int regval, ret;
>> +	bool trigger_poll;
>> +
>> +	scoped_guard(mutex, &data->irq_lock) {
>> +		ret = regmap_read(data->regmap, VEML6031X00_REG_INT, &regval);
>
> [Severity: High]
> If a spurious interrupt fires while both ev_en and trig_en are false,
> could this unconditionally read from the I2C bus while the device is
> runtime suspended?
>
> It looks like this might hit a powered-off device since it doesn't
> use pm_runtime_get_if_active() or check software state before
> the register read.
>

The I2C interface stays accessible even while the device is powered down,
so this read doesn't fail or have side effects in case of a spurious
interrupt.

>> +		if (ret) {
>> +			dev_dbg(regmap_get_device(data->regmap),
>> +				"Failed to read interrupt register %d\n", ret);
>> +			return IRQ_NONE;
>> +		}
> [ ... ]
>> @@ -535,11 +919,78 @@ static int veml6031x00_buffer_postdisable(struct iio_dev *iio)
>>  	return 0;
>>  }
>>
>> +static int veml6031x00_set_trigger_state(struct iio_trigger *trig, bool state)
>> +{
>> +	struct iio_dev *iio = iio_trigger_get_drvdata(trig);
>> +	struct veml6031x00_data *data = iio_priv(iio);
>> +	int ret;
>> +
>> +	guard(mutex)(&data->irq_lock);
>> +
>> +	if (state == data->trig_en)
>> +		return 0;
>> +
>> +	ret = veml6031x00_set_interrupt(data, state);
>> +	if (ret)
>> +		return ret;
>> +
>> +	/* The AF bit must be set before setting AF_TRIG */
>> +	ret = regmap_update_bits(data->regmap, VEML6031X00_REG_CONF0,
>> +				 VEML6031X00_CONF0_AF,
>> +				 FIELD_PREP(VEML6031X00_CONF0_AF, state));
>
> [Severity: Medium]
> Since the AF bit must be set before setting AF_TRIG, does the
> disable sequence need to happen in reverse order?
>
> When state is false, this clears the AF bit first, creating a window
> where AF_TRIG is still active but AF is disabled.
>

Disabling AF is what actually turns off auto-force mode, so it should be
done in the current order.

>> +	if (ret) {
>> +		veml6031x00_set_interrupt(data, !state);
>> +
>> +		return ret;
>> +	}
>> +
>> +	ret = regmap_update_bits(data->regmap, VEML6031X00_REG_CONF0,
>> +				 VEML6031X00_CONF0_AF_TRIG,
>> +				 FIELD_PREP(VEML6031X00_CONF0_AF_TRIG, state));
> [ ... ]
>> +static irqreturn_t veml6031x00_trig_handler(int irq, void *p)
>> +{
>> +	struct iio_poll_func *pf = p;
>> +	struct iio_dev *iio = pf->indio_dev;
>> +	struct veml6031x00_data *data = iio_priv(iio);
>> +	IIO_DECLARE_BUFFER_WITH_TS(__le16, scan, 2);
>
> [Severity: High]
> Could this leak uninitialized kernel stack memory to userspace?
>
> The IIO_DECLARE_BUFFER_WITH_TS macro allocates the buffer on the stack
> without zeroing the padding bytes between the channel data and the
> timestamp.
>

Already addressed in the reply to Sashiko's feedback about [3/4].

>> +	unsigned int i = 0;
>> +	int ch, ret;
>> +
>> +	if (test_bit(VEML6031X00_SCAN_ALS, iio->active_scan_mask) &&
>> +	    test_bit(VEML6031X00_SCAN_IR, iio->active_scan_mask)) {
>> +		ret = regmap_bulk_read(data->regmap,
>> +				       VEML6031X00_REG_ALS_L,
>> +				       scan,
>> +				       2 * sizeof(*scan));
>> +		if (ret)
>> +			goto done;
>> +	} else {
>> +		iio_for_each_active_channel(iio, ch) {
>> +			ret = regmap_bulk_read(data->regmap,
>> +					       iio->channels[ch].address,
>> +					       &scan[i++],
>> +					       sizeof(*scan));
>> +			if (ret)
>> +				goto done;
>> +		}
>> +	}
>> +
>> +	iio_push_to_buffers_with_ts(iio, scan, sizeof(scan), pf->timestamp);
>
> [Severity: Medium]
> Since this trigger handler is executed synchronously from the interrupt
> handler via iio_trigger_poll_nested() bypassing the top-half
> iio_pollfunc_store_time(), will pf->timestamp always be zero here?
>

The timestamp is already captured in the interrupt handler. I will assign
it to pollfunc->timestamp before calling iio_trigger_poll_nested().

>> +
>> +done:
>> +	iio_trigger_notify_done(iio->trig);
>> +
>> +	return IRQ_HANDLED;
>> +}
> [ ... ]
>> @@ -636,15 +1142,29 @@ static int veml6031x00_probe(struct i2c_client *i2c)
>>  				     "Failed to set regmap\n");
>>
>>  	iio->name = data->chip->name;
>> -	iio->channels = veml6031x00_channels;
>> -	iio->num_channels = ARRAY_SIZE(veml6031x00_channels);
>>  	iio->modes = INDIO_DIRECT_MODE;
>> -	iio->info = &veml6031x00_info;
>> +	if (i2c->irq) {
>> +		iio->channels = veml6031x00_channels_irq;
>> +		iio->num_channels = ARRAY_SIZE(veml6031x00_channels_irq);
>> +		ret = veml6031x00_setup_irq(i2c, iio);
>
> [Severity: High]
> Does registering the IRQ and trigger here expose a race condition?
>
> veml6031x00_setup_irq() requests the threaded IRQ before devm_mutex_init()
> allocates data->irq_lock and veml6031x00_regfield_init() allocates
> data->rf.int_en. If an interrupt fires immediately, the handler will try
> to lock an uninitialized mutex.
>
> Additionally, since devres cleans up in reverse order, won't the mutex
> be destroyed before the IRQ is unregistered during unbind?
>

For V6: mutex_init and regfield_init moved before setup_irq().

>> +		if (ret)
>> +			return ret;
>> +
>> +		iio->info = &veml6031x00_info;
>> +	} else {
>> +		iio->channels = veml6031x00_channels;
>
> [Severity: High]
> If the device does not provide an interrupt, it falls back to
> veml6031x00_channels which lacks scan_index and scan_type definitions.
>
> Will setting up a triggered buffer unconditionally at the end of probe
> cause IIO core undefined behavior if a user attaches an external
> sysfs/hrtimer trigger, since both channels would default to a
> scan_index of 0 and 0 storage bits?
>

Already addressed in the reply to Sashiko's feedback about [3/4].

>> +		iio->num_channels = ARRAY_SIZE(veml6031x00_channels);
>> +		iio->info = &veml6031x00_info_no_irq;
>> +	}
>>
>>  	ret = devm_mutex_init(&i2c->dev, &data->scale_lock);
>>  	if (ret)
>>  		return ret;
>>
>> +	ret = devm_mutex_init(&i2c->dev, &data->irq_lock);
>> +	if (ret)
>> +		return ret;
>> +
>>  	ret = veml6031x00_regfield_init(data);
>>  	if (ret)
>>  		return dev_err_probe(&i2c->dev, ret, "Failed to init regfield\n");
>> @@ -672,6 +1192,12 @@ static int veml6031x00_probe(struct i2c_client *i2c)
>>  	if (ret)
>>  		return dev_err_probe(&i2c->dev, ret, "Failed to get runtime PM\n");
>>
>
> [Severity: High]
> Could the devm_pm_runtime_get_noresume() call just above this hunk cause
> a usage counter underflow?
>
> The devres action will eventually call pm_runtime_put_noidle() during
> driver unbind. However, the driver also manually calls
> pm_runtime_put_autosuspend() at the end of veml6031x00_probe() to drop
> the initial reference.
>
> This double-put could underflow the usage counter to -1 and corrupt
> device power management. If the driver manually manages the initial
> reference, should it use the non-devm pm_runtime_get_noresume() variant?
>

Already addressed in the reply to Sashiko's feedback about [3/4].


Best regards,
Javier

      reply	other threads:[~2026-08-08  6:35 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-07 13:51 [PATCH v5 0/4] iio: light: add support for veml6031x00 ALS series Javier Carrasco
2026-08-07 13:51 ` [PATCH v5 1/4] dt-bindings: iio: light: veml6030: add " Javier Carrasco
2026-08-07 14:06   ` sashiko-bot
2026-08-07 14:34     ` Javier Carrasco
2026-08-07 15:33   ` Rob Herring (Arm)
2026-08-07 13:51 ` [PATCH v5 2/4] iio: light: add support for " Javier Carrasco
2026-08-07 14:19   ` sashiko-bot
2026-08-07 14:53     ` Javier Carrasco
2026-08-07 21:02   ` Uwe Kleine-König
2026-08-07 13:51 ` [PATCH v5 3/4] iio: light: veml6031x00: add support for triggered buffers Javier Carrasco
2026-08-07 14:49   ` sashiko-bot
2026-08-07 20:33     ` Javier Carrasco
2026-08-07 13:51 ` [PATCH v5 4/4] iio: light: veml6031x00: add support for events and trigger Javier Carrasco
2026-08-07 15:08   ` sashiko-bot
2026-08-08  6:35     ` Javier Carrasco [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=DKJCQRNBH477.3C9CC4KCFAMNK@gmail.com \
    --to=javier.carrasco.cruz@gmail.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox