Messages in this thread | | | Subject | Re: [PATCH] i2c: designware: call i2c_dw_read_clear_intrbits_slave() once | From | Jarkko Nikula <> | Date | Wed, 21 Oct 2020 15:22:13 +0300 |
| |
Hi
On 10/20/20 11:33 AM, Michael Wu wrote: > i2c_dw_read_clear_intrbits_slave() was called per each interrupt handle. > It caused some interrupt bits which haven't been handled yet were cleared, > the corresponding handlers would do nothing due to interrupt bits been > discarded. For example, > > $ i2cset -f -y 2 0x42 0x00 0x41; dmesg -c > [0][clear_intrbits]0x1 STATUS SLAVE_ACTIVITY=0x1 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4 > [1][irq_handler ]0x1 STATUS SLAVE_ACTIVITY=0x1 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4 > WRITE_RECEIVED > [0][clear_intrbits]0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x714 : INTR_STAT=0x204 > [1][irq_handler ]0x1 STATUS SLAVE_ACTIVITY=0x0 : RAW_INTR_STAT=0x514 : INTR_STAT=0x4 > WRITE_RECEIVED > > t1: ISR with the 1st IC_INTR_RX_FULL. > t2: Clear listed IC_INTR bits by i2c_dw_read_clear_intrbits_slave(). > t3: Enter i2c_dw_irq_handler_slave() and then do > i2c_slave_event(WRITE_RECEIVED) because > if (stat & DW_IC_INTR_RX_FULL). > t4: ISR with both IC_INTR_STOP_DET and the 2nd IC_INTR_RX_FULL. > t5: Clear listed IC_INTR bits by i2c_dw_read_clear_intrbits_slave(). The > current IC_INTR_STOP_DET is cleared by this > i2c_dw_read_clear_intrbits_slave(). > t6: Enter i2c_dw_irq_handler_slave() and then do > i2c_slave_event(WRITE_RECEIVED) because > if (stat & DW_IC_INTR_RX_FULL). > t7: i2c_slave_event(STOP) never be done because IC_INTR_STOP_DET was > cleared in t5. > > The root cause is that i2c_dw_read_clear_intrbits_slave() was called many > times. Calling i2c_dw_read_clear_intrbits_slave() once in one ISR and take > the returned stat for later handling is the solution. > > Signed-off-by: Michael Wu <michael.wu@vatics.com> > --- > drivers/i2c/busses/i2c-designware-slave.c | 16 +++++----------- > 1 file changed, 5 insertions(+), 11 deletions(-) > > diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c > index 44974b53a626..02e7c5171827 100644 > --- a/drivers/i2c/busses/i2c-designware-slave.c > +++ b/drivers/i2c/busses/i2c-designware-slave.c > @@ -159,7 +159,6 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev) > u32 raw_stat, stat, enabled, tmp; > u8 val = 0, slave_activity; > > - regmap_read(dev->map, DW_IC_INTR_STAT, &stat); > regmap_read(dev->map, DW_IC_ENABLE, &enabled); > regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_stat); > regmap_read(dev->map, DW_IC_STATUS, &tmp); > @@ -168,13 +167,11 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev) > if (!enabled || !(raw_stat & ~DW_IC_INTR_ACTIVITY) || !dev->slave) > return 0; > > + stat = i2c_dw_read_clear_intrbits_slave(dev); > dev_dbg(dev->dev, > "%#x STATUS SLAVE_ACTIVITY=%#x : RAW_INTR_STAT=%#x : INTR_STAT=%#x\n", > enabled, slave_activity, raw_stat, stat); > > - if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET)) > - i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val); > -
...
> + > + if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET)) > + i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
Was this move a leftover that got committed by accident? I think it's better to have this logic change in another patch. Or was it even questionable to move the I2C_SLAVE_WRITE_REQUESTED reporting after all other?
Jarkko
| |