Re: [PATCH RESEND v5 4/6] iio: accel: mma8452: Support interrupt sharing

Esben Haabendal <[email protected]>
Newsgroups dev.linux.lists.sashiko-reviews,org.kernel.vger.linux-devicetree
Message-ID <[email protected]>
<[email protected]> writes:

> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
>
> New issues:
> - [High] Failed runtime suspend leaves the `suspended` flag set to `true`,
> causing an unrecoverable PM usage counter leak and a potential interrupt storm.
> - [Low] Compilation Error: undeclared variable `client` used in `mma8452_runtime_suspend`.
>
> Pre-existing issues:
> - [High] Unbalanced `regulator_disable()` calls and I2C writes to a powered-off device in `mma8452_remove()`.
> --
>
> --- Patch [4]: [PATCH RESEND v5 4/6] iio: accel: mma8452: Support interrupt sharing ---
> commit 79ad9089167d804daaa97086d058cd3a0e2f4199
> Author: Esben Haabendal <[email protected]>
>
> iio: accel: mma8452: Support interrupt sharing
>
> This commit adds handling of runtime PM suspension in the interrupt handler
> to allow sharing interrupts with other devices. It introduces a suspended flag
> and uses synchronize_irq() to protect against race conditions during runtime
> suspend and device removal.
>
>> diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
>> index 1fb43c5b0b72f..25bb2dd69381e 100644
>> --- a/drivers/iio/accel/mma8452.c
>> +++ b/drivers/iio/accel/mma8452.c
> [ ... ]
>> @@ -1056,14 +1057,19 @@ static irqreturn_t mma8452_interrupt(int irq, void *p)
>>  	struct iio_dev *indio_dev = p;
>>  	struct mma8452_data *data = iio_priv(indio_dev);
>>  	irqreturn_t ret = IRQ_NONE;
>> +	int pm_status;
>>  	int src;
>>
>> +	pm_status = pm_runtime_get_if_active(&data->client->dev);
>> +	if (pm_status == 0 || READ_ONCE(data->suspended))
>> +		return IRQ_NONE; /* device is powered down or being removed */
>> +
>
> [Severity: High]
> If mma8452_runtime_suspend() in drivers/iio/accel/mma8452.c fails and
> leaves data->suspended set to true, can this early return cause a PM
> usage counter leak and an interrupt storm?
>
> If the device is kept in the RPM_ACTIVE state after a suspend failure,
> pm_runtime_get_if_active() will return 1. Because data->suspended is true,
> the handler will return IRQ_NONE immediately.
>
> This skips pm_runtime_put_autosuspend(), leaking the usage counter. Also,
> by returning IRQ_NONE on a shared level-triggered IRQ without clearing the
> hardware interrupt, wouldn't this trigger an interrupt storm?

Yes, I make sure to call pm_runtime_put_autosuspend() when
pm_runtime_get_active() returns 0 and suspended flag is set.

Also, I guess we should not set the suspended flag until after checking
the return value from mma8452_standby() in mma8452_runtime_suspend().

In case one of the regulator_disable() calls fails, the suspended flag
will be left set to true. But as the device is in standby, no interrupt
storm should happen.

> [ ... ]
>> @@ -1768,12 +1778,15 @@ static int mma8452_runtime_suspend(struct device *dev)
>>
>>  	mutex_lock(&data->lock);
>>  	ret = mma8452_standby(data);
>> +	WRITE_ONCE(data->suspended, true);
>>  	mutex_unlock(&data->lock);
>>  	if (ret < 0) {
>>  		dev_err(&data->client->dev, "powering off device failed\n");
>>  		return -EAGAIN;
>>  	}
>
> [Severity: High]
> If mma8452_standby() fails, should data->suspended be reverted to false?
>
> When returning -EAGAIN on failure in drivers/iio/accel/mma8452.c,
> leaving data->suspended set to true creates the inconsistent state that
> breaks mma8452_interrupt() as noted above.

I will move the WRITE_ONCE() to after checking the ret value, so we
don't leave suspended set to true in this case.

>> +	synchronize_irq(client->irq);
>> +
>
> [Severity: Low]
> Does this code compile?
>
> There is no local variable named client in mma8452_runtime_suspend() in
> drivers/iio/accel/mma8452.c. The I2C client is available via
> data->client or to_i2c_client(dev), so using client->irq directly
> appears to cause a compilation failure.
>
> [ ... ]
>
> [Severity: High]
> This is a pre-existing issue, but I noticed a potential problem during
> device removal in mma8452_remove() in drivers/iio/accel/mma8452.c:
>
> drivers/iio/accel/mma8452.c:mma8452_remove() {
>     ...
> 	pm_runtime_disable(&client->dev);
> 	pm_runtime_set_suspended(&client->dev);
>     ...
> 	mma8452_standby(iio_priv(indio_dev));
>
> 	regulator_disable(data->vddio_reg);
> 	regulator_disable(data->vdd_reg);
> }
>
> If the device is already in the RPM_SUSPENDED state when mma8452_remove() is
> called, its regulators have already been disabled by
> mma8452_runtime_suspend().
>
> Because pm_runtime_disable() does not resume the device, calling
> regulator_disable() again will underflow the regulator enable count. Could
> this forcefully disable shared regulators and cause system instability?
>
> Additionally, mma8452_standby() performs an I2C write. Is it safe to
> unconditionally access the hardware when it might be powered off?
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.