2024-05-31 14:52:18

by Stefan Eichenberger

[permalink] [raw]
Subject: [RFC PATCH] i2c: imx: avoid rescheduling when waiting for bus not busy

From: Stefan Eichenberger <[email protected]>

On our i.MX8M Mini based module we have an ADS1015 I2C ADC connected to
the I2C bus. The ADS1015 I2C ADC will timeout after 25ms when the I2C
bus is idle. The imx i2c driver will call schedule when waiting for the
bus to become idle after switching to master mode. When the i2c
controller switches to master mode it pulls SCL and SDA low, if the
ADS1015 I2C ADC sees this for more than 25 ms without seeing SCL
clocking, it will timeout and ignore all signals until the next start
condition occurs (SCL and SDA low). This can occur when the system load
is high and schedule returns after more than 25 ms.

This rfc tries to solve the problem by using a udelay for the first 10
ms before calling schedule. This reduces the chance that we will
reschedule. However, it is still theoretically possible for the problem
to occur. To properly solve the problem, we would also need to disable
interrupts during the transfer.

After some internal discussion, we see three possible solutions:
1. Use udelay as shown in this rfc and also disable the interrupts
during the transfer. This would solve the problem but disable the
interrupts. Also, we would have to re-enable the interrupts if the
timeout is longer than 1ms (TBD).
2. We use a retry mechanism in the ti-ads1015 driver. When we see a
timeout, we try again.
3. We use the suggested solution and accept that there is an edge case
where the timeout can happen.

There may be a better way to do this, which is why this is an RFC.

Signed-off-by: Stefan Eichenberger <[email protected]>
---
drivers/i2c/busses/i2c-imx.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 3842e527116b7..179f8367490a5 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -503,10 +503,18 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool a
"<%s> I2C bus is busy\n", __func__);
return -ETIMEDOUT;
}
- if (atomic)
+ if (atomic) {
udelay(100);
- else
- schedule();
+ } else {
+ /*
+ * Avoid rescheduling in the first 10 ms to avoid
+ * timeouts for SMBus like devices
+ */
+ if (time_before(jiffies, orig_jiffies + msecs_to_jiffies(10)))
+ udelay(10);
+ else
+ schedule();
+ }
}

return 0;
--
2.40.1



2024-06-02 14:31:54

by Andrew Lunn

[permalink] [raw]
Subject: Re: [RFC PATCH] i2c: imx: avoid rescheduling when waiting for bus not busy

On Fri, May 31, 2024 at 04:24:37PM +0200, Stefan Eichenberger wrote:
> From: Stefan Eichenberger <[email protected]>
>
> On our i.MX8M Mini based module we have an ADS1015 I2C ADC connected to
> the I2C bus. The ADS1015 I2C ADC will timeout after 25ms when the I2C
> bus is idle. The imx i2c driver will call schedule when waiting for the
> bus to become idle after switching to master mode. When the i2c
> controller switches to master mode it pulls SCL and SDA low, if the
> ADS1015 I2C ADC sees this for more than 25 ms without seeing SCL
> clocking, it will timeout and ignore all signals until the next start
> condition occurs (SCL and SDA low).

Does the I2C specification say anything about this behaviour, or is it
specific to this device?

> This rfc tries to solve the problem by using a udelay for the first 10
> ms before calling schedule. This reduces the chance that we will
> reschedule. However, it is still theoretically possible for the problem
> to occur. To properly solve the problem, we would also need to disable
> interrupts during the transfer.
>
> After some internal discussion, we see three possible solutions:
> 1. Use udelay as shown in this rfc and also disable the interrupts
> during the transfer. This would solve the problem but disable the
> interrupts. Also, we would have to re-enable the interrupts if the
> timeout is longer than 1ms (TBD).
> 2. We use a retry mechanism in the ti-ads1015 driver. When we see a
> timeout, we try again.
> 3. We use the suggested solution and accept that there is an edge case
> where the timeout can happen.

2. has the advantage you fix it for any system with this device, not
just those using an IMX. Once question would be, is such a retry safe
in all conditions. Does the timeout happen before any non idempotent
operation is performed?

If the I2C specification allows this behaviour, maybe a more generic
solution is needed, since it could affect more devices?

Andrew

2024-06-03 07:36:27

by Stefan Eichenberger

[permalink] [raw]
Subject: Re: [RFC PATCH] i2c: imx: avoid rescheduling when waiting for bus not busy

On Sun, Jun 02, 2024 at 04:31:27PM +0200, Andrew Lunn wrote:
> On Fri, May 31, 2024 at 04:24:37PM +0200, Stefan Eichenberger wrote:
> > From: Stefan Eichenberger <[email protected]>
> >
> > On our i.MX8M Mini based module we have an ADS1015 I2C ADC connected to
> > the I2C bus. The ADS1015 I2C ADC will timeout after 25ms when the I2C
> > bus is idle. The imx i2c driver will call schedule when waiting for the
> > bus to become idle after switching to master mode. When the i2c
> > controller switches to master mode it pulls SCL and SDA low, if the
> > ADS1015 I2C ADC sees this for more than 25 ms without seeing SCL
> > clocking, it will timeout and ignore all signals until the next start
> > condition occurs (SCL and SDA low).
>
> Does the I2C specification say anything about this behaviour, or is it
> specific to this device?
>

The timeouting mechanism is normally used in SMBus mode. However, for
this specific device they still call it I2C which is a bit confusing.
The difference between I2C and SMBus is that SMBus has a timeout while
the I2C uses a recovery mechanism. Besides that the two protocols are
identical.

> > This rfc tries to solve the problem by using a udelay for the first 10
> > ms before calling schedule. This reduces the chance that we will
> > reschedule. However, it is still theoretically possible for the problem
> > to occur. To properly solve the problem, we would also need to disable
> > interrupts during the transfer.
> >
> > After some internal discussion, we see three possible solutions:
> > 1. Use udelay as shown in this rfc and also disable the interrupts
> > during the transfer. This would solve the problem but disable the
> > interrupts. Also, we would have to re-enable the interrupts if the
> > timeout is longer than 1ms (TBD).
> > 2. We use a retry mechanism in the ti-ads1015 driver. When we see a
> > timeout, we try again.
> > 3. We use the suggested solution and accept that there is an edge case
> > where the timeout can happen.
>
> 2. has the advantage you fix it for any system with this device, not
> just those using an IMX. Once question would be, is such a retry safe
> in all conditions. Does the timeout happen before any non idempotent
> operation is performed?
>
> If the I2C specification allows this behaviour, maybe a more generic
> solution is needed, since it could affect more devices?

Maybe I could add a smbus_xfer function to the i2c driver and then
change the ti-ads1015 driver to use the smbus_xfer function instead of
i2c. However, I would still have to disable preemption while the SMBus
transfer is happening which concerns me a bit.

Regards,
Stefan