RE: [PATCH 2/5] i2c: xiic: Drop broken interrupt handler

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Marek,

> -----Original Message-----
> From: Marek Vasut <marex@xxxxxxx>
> Sent: Tuesday, June 30, 2020 3:20 AM
> To: Raviteja Narayanam <rna@xxxxxxxxxx>; linux-i2c@xxxxxxxxxxxxxxx
> Cc: Michal Simek <michals@xxxxxxxxxx>; Shubhrajyoti Datta
> <shubhraj@xxxxxxxxxx>; Wolfram Sang <wsa@xxxxxxxxxx>
> Subject: Re: [PATCH 2/5] i2c: xiic: Drop broken interrupt handler
> 
> On 6/29/20 2:52 PM, Raviteja Narayanam wrote:
> 
> Hi,
> 
> [...]
> 
> >>>> diff --git a/drivers/i2c/busses/i2c-xiic.c
> >>>> b/drivers/i2c/busses/i2c-xiic.c index
> >>>> 0777e577720db..6db71c0fb6583 100644
> >>>> --- a/drivers/i2c/busses/i2c-xiic.c
> >>>> +++ b/drivers/i2c/busses/i2c-xiic.c
> >>>> @@ -543,7 +543,6 @@ static void xiic_start_recv(struct xiic_i2c *i2c)  {
> >>>>  	u8 rx_watermark;
> >>>>  	struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg;
> >>>> -	unsigned long flags;
> >>>>
> >>>>  	/* Clear and enable Rx full interrupt. */
> >>>>  	xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK |
> >>>> XIIC_INTR_TX_ERROR_MASK); @@ -559,7 +558,6 @@ static void
> >>>> xiic_start_recv(struct xiic_i2c *i2c)
> >>>>  		rx_watermark = IIC_RX_FIFO_DEPTH;
> >>>>  	xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rx_watermark - 1);
> >>>>
> >>>> -	local_irq_save(flags);
> >>>
> >>> It is added as part of (i2c: xiic: Make the start and the byte count
> >>> write atomic - ae7304c3ea28a3ba47a7a8312c76c654ef24967e) commit to
> >> make the below 2 register writes atomic so that the controller
> >> doesn't produce a wrong transaction.
> >>
> >> Two consecutive register writes are not atomic, they are posted as
> >> two consecutive writes on the bus and will reach the hardware IP as
> >> two separate writes with arbitrary delay between them.
> >>
> >> I think the intention of the patch ae7304c3ea28 ("i2c: xiic: Make the
> >> start and the byte count write atomic") is to make sure that there
> >> will be no read/write register access to the XIIC IP while those
> >> registers in
> >> local_irq_save()/local_irq_restore() block are written, and that makes sense.
> >>
> >> However, local_irq_save()/local_irq_restore() is local to one CPU
> >> core, it does not prevent another CPU core from posting register
> >> read/write access to the XIIC IP (for example from xiic_process()
> >> threaded interrupt handler, which might just be running on that other CPU
> core).
> >>
> >> The &i2c->lock mutex is locked by both the xiic_start() and
> >> xiic_process(), and therefore guarantees that no other thread can
> >> post read/write register access to the XIIC IP while xiic_start()
> >> (and thus xiic_recv_start(), which is called from
> >> it) is running.
> >>
> >> And so, I think this local_irq_save()/local_irq_restore() can be removed.
> >>
> >>> (If there is a delay between the 2 register writes, controller is
> >>> messing up with the transaction). It is not intended for locking
> >>> between this
> >> function and isr. So, this can't be removed.
> >>
> >> But the bus can insert arbitrary delay between two consecutive
> >> register writes to the XIIC IP, so if the timing between the two
> >> register writes is really critical, then I don't see how to guarantee
> >> the timing requirement. Do you happen to have more details on what
> >> really happens on the hardware level here , maybe some errata document
> for the XIIC IP?
> >
> > From the commit description of "i2c: xiic: Make the start and the byte
> > count write atomic"(ae7304c3ea28a3ba47a7a8312c76c654ef24967e),
> >
> > [Disable interrupts while configuring the transfer and enable them back.
> >
> > We have below as the programming sequence 1. start and slave address
> > 2. byte count and stop
> >
> > In some customer platform there was a lot of interrupts between 1 and
> > 2 and after slave address (around 7 clock cyles) if 2 is not executed
> > then the transaction is nacked.
> 
> Is that a hardware property of the XIIC IP, that the transaction is NACKed after
> 7 clock cycles of the XIIC IP ?

Yes, it is from IP. 

> 
> > To fix this case make the 2 writes atomic.]
> 
> But using local_irq_save()/local_irq_restore() will not make two separate
> register writes atomic, they will still be two separate consecutive register
> writes.
> 
> Also note that another CPU core can very well be generating a lot of traffic on
> the bus between current CPU core and the XIIC IP, so the first write from
> current CPU core to the XIIC IP would arrive at the XIIC IP, then the bus will be
> busy for a long time with other requiests (more than 7 cycles), and then the
> second write to the XIIC IP will arrive at the XIIC IP. The
> local_irq_save()/local_irq_restore() can not prevent this scenario, but this is
> very real on a system under load.

Yeah, such possibility is there. local_irq_save()/local_irq_restore() can't be the right solution
as you said.

> 
> > So, this local_irq_save()/local_irq_restore() is not related to
> > exclusive access in the driver (xiic_process vs xiic_start), but to supply the
> byte count to controller before it completes transmitting START and slave
> address.
> 
> But then shouldn't the XIIC IP be fixed / extended with support for such an
> atomic update instead ?

I have started communicating with the hardware team on why the IP behavior is like this. 
But, that will take more time to get to a conclusion. We can continue this discussion here.
So, how about we remove this patch from the current series and go ahead with the rest of patches?
In that case please send a v2 with the minimal changes suggested in other patches (4 and 5)?

Thanks
Raviteja N
> 
> >> Thanks
> >>
> >>>>  	if (!(msg->flags & I2C_M_NOSTART))
> >>>>  		/* write the address */
> >>>>  		xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, @@ -569,7 +567,6
> >>
> >> [...]




[Index of Archives]     [Linux GPIO]     [Linux SPI]     [Linux Hardward Monitoring]     [LM Sensors]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux