RE: [PATCH 01/12] i2c: xiic: Add standard mode support for > 255 byte read transfers

From: Guntupalli, Manikanta
Date: Tue Jul 26 2022 - 06:36:06 EST


Hi Krzysztof,

> -----Original Message-----
> From: Krzysztof Adamski <krzysztof.adamski@xxxxxxxxx>
> Sent: Wednesday, July 20, 2022 3:56 PM
> To: Guntupalli, Manikanta <manikanta.guntupalli@xxxxxxx>; Manikanta
> Guntupalli <manikanta.guntupalli@xxxxxxxxxx>; michal.simek@xxxxxxxxxx;
> Simek, Michal <michal.simek@xxxxxxx>; linux-arm-
> kernel@xxxxxxxxxxxxxxxxxxx; linux-i2c@xxxxxxxxxxxxxxx; linux-
> kernel@xxxxxxxxxxxxxxx; git (AMD-Xilinx) <git@xxxxxxx>
> Cc: Raviteja Narayanam <raviteja.narayanam@xxxxxxxxxx>
> Subject: Re: [PATCH 01/12] i2c: xiic: Add standard mode support for > 255
> byte read transfers
>
> Hi Manikanta,
>
> W dniu 13.07.2022 o 09:54, Guntupalli, Manikanta pisze:
> > Hi Krzysztof,
> >> [...]
> >>> @@ -579,31 +681,99 @@ static int xiic_busy(struct xiic_i2c *i2c)
> >>> static void xiic_start_recv(struct xiic_i2c *i2c)
> >>> {
> >>> u16 rx_watermark;
> >>> + u8 cr = 0, rfd_set = 0;
> >>> 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);
> >>> + dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n",
> >>> + __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET),
> >>> + xiic_getreg8(i2c, XIIC_CR_REG_OFFSET));
> >>>
> >>> - /* we want to get all but last byte, because the TX_ERROR IRQ is used
> >>> - * to inidicate error ACK on the address, and negative ack on the last
> >>> - * received byte, so to not mix them receive all but last.
> >>> - * In the case where there is only one byte to receive
> >>> - * we can check if ERROR and RX full is set at the same time
> >>> - */
> >>> - rx_watermark = msg->len;
> >>> - if (rx_watermark > IIC_RX_FIFO_DEPTH)
> >>> - rx_watermark = IIC_RX_FIFO_DEPTH;
> >>> - xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, (u8)(rx_watermark - 1));
> >> Do we really want to write 255 to RFD if msg->len == 0? That will set
> >> the compare value in the RX_FIFO_PIRQ register to max value (15) but
> >> I don't understand why we would like to do this.
> >> Also, bits 31:4 are reserved so I think we should not try to touch them.
> >>
> > Here comparing and taking minimum value of msg->len and
> IIC_RX_FIFO_DEPTH. The value of IIC_RX_FIFO_DEPTH is 16, while writing
> into register performed -1, so maximum value writing into RX_FIFO_PIRQ is
> 15.
> >
> I'm not sure you got my point - my point was that if the provided
> msg->len is 0, then rx_watermark will also be 0 and thus we will set the
> XIIC_RFD_REG_OFFSET to value 255 which seems illegal.

We will fix in V2.

> >>> + /* Disable Tx interrupts */
> >>> + xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK |
> >>> + XIIC_INTR_TX_EMPTY_MASK);
> >>>
> >>> - if (!(msg->flags & I2C_M_NOSTART))
> >>> - /* write the address */
> >>> - xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
> >>> - i2c_8bit_addr_from_msg(msg) |
> XIIC_TX_DYN_START_MASK);
> >>>
> >>> - xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
> >>> + if (i2c->dynamic) {
> >>> + u8 bytes;
> >>> + u16 val;
> >>>
> >>> - xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
> >>> - msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0));
> >>> + /* Clear and enable Rx full interrupt. */
> >>> + xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK |
> >>> + XIIC_INTR_TX_ERROR_MASK);
> >>> +
> >>> + /*
> >>> + * We want to get all but last byte, because the TX_ERROR IRQ
> >>> + * is used to indicate error ACK on the address, and
> >>> + * negative ack on the last received byte, so to not mix
> >>> + * them receive all but last.
> >>> + * In the case where there is only one byte to receive
> >>> + * we can check if ERROR and RX full is set at the same time
> >>> + */
> >>> + rx_watermark = msg->len;
> >>> + bytes = min_t(u8, rx_watermark, IIC_RX_FIFO_DEPTH);
> >>> + bytes--;
> >> Again, do we really want to write 255 to RFD if msg->len == 0?
> >>
> > Here comparing and taking minimum value of msg->len and
> IIC_RX_FIFO_DEPTH. The value of IIC_RX_FIFO_DEPTH is 16, before writing
> into register performed decrement, so maximum value writing into
> RX_FIFO_PIRQ is 15.
> You are not correct - in case the msg->len is 0, the value written into the
> register will be 255 (if you decrement 0, you will get 255 in case of u8). Unless
> there is some check making sure msg->len is never 0, that I do not see.

Agreed, we will fix in V2.

> >
> >>> +
> >>> + xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, bytes);
> >>> +
> >>> + local_irq_save(flags);
> >>> + if (!(msg->flags & I2C_M_NOSTART))
> >>> + /* write the address */
> >>> + xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET,
> >>> + i2c_8bit_addr_from_msg(msg) |
> >>> + XIIC_TX_DYN_START_MASK);
> >> When reviewing this patch, I tried to understand how the controller
> >> knows if it should work in dynamic or in stanard mode.
> > For receive operation with byte count greater than 255, we will switch to
> standard mode else always in the dynamic mode only.
> >
> >> My understanding is that in
> >> order to start the dynamic mode logic, we have to set the DYN_START
> >> bit in the TX FIFO when we write an address there. Is this correct?
> > After deciding dynamic mode based on above logic, we need to set the
> DYN_START bit along with address in the TX FIFO to start the transfer.
> >
> >> But we don't do
> >> that if I2C_M_NOSTART flag is set so how is this supposed to work
> >> with this flag? I mean, does the controller really supports doing
> >> I2C_M_NOSTART in dynamic mode?
> >>
> > I2C controller supports I2C_M_NOSTART in dynamic mode.
> >
> >> Or does it support it at all? After all, when we skip this, we will
> >> still write to the TX_FIFO register 5 lines below. How is the
> >> controller supposed to know that the len that we write there is *not*
> actually an address?
> >>
> > Below notes mentioned in I2C_M_NOSTART section of kernel
> > documentation(link mentioned below), " If you set the I2C_M_NOSTART
> variable for the first partial message,
> > we do not generate Addr, but we do generate the startbit S. This will
> > probably confuse all other clients on your bus, so don't try this."
> >
> > https://www.kernel.org/doc/Documentation/i2c/i2c-protocol
> >
> > So I2C_M_NOSTART flag need to use in second i2c_msg or in later
> i2c_msgs, but not in first i2c_msg. During first i2c_msg dynamic mode starts,
> so again no need to set start bit TX_FIFO.
>
> But what happens if somebody passes the I2C_M_NOSTART bit in the first
> message? There seems to be no check for that. I know the documentation
> says that this should be avioded but it also states what should happen (S bit
> is generated by no address is sent) and as far as I understand this is not what
> will happen in i2c-xiic. What will happen is that the address *will* be
> generated and it will be the first byte from the buf.
>

As per kernel documentation it's recommended to use I2C_M_NOSTART flag from second message onwards, but not mandatory.
Dynamic mode won't start if someone passes I2C_M_NOSTART flag in first message.

> >
> >> That being said, we do not annouce the I2C_FUNC_NOSTART support so
> >> maybe we should not care at all and just remove the code handling the
> >> I2C_M_NOSTART flag?
> > Since it supports I2C_M_NOSTART flag, need to keep code handling flag.
> But if it supports it, that should be annouced in xiic_func.

Since we are not announcing I2C_FUNC_NOSTART, we will remove I2C_M_NOSTART flag handling checks in V2.

> >
> >>> +
> >>> + xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK);
> >>> +
> >>> + /* If last message, include dynamic stop bit with length */
> >>> + val = (i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0;
> >>> + val |= msg->len;
> >>> +
> >>> + xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, val);
> >>> + local_irq_restore(flags);
> >>> + } else {
> >>> + cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET);
> >>> +
> >>> + /* Set Receive fifo depth */
> >>> + rx_watermark = msg->len;
> >>> + if (rx_watermark > IIC_RX_FIFO_DEPTH) {
> >>> + rfd_set = IIC_RX_FIFO_DEPTH - 1;
> >>> + } else if ((rx_watermark == 1) || (rx_watermark == 0)) {
> >>> + rfd_set = rx_watermark - 1;
> >> Again, do we really want to write 255 to RFD if msg->len == 0?
> > Here comparing and taking minimum value of msg->len and
> IIC_RX_FIFO_DEPTH. The value of IIC_RX_FIFO_DEPTH is 16, before writing
> into register performed -1, so maximum value writing into RX_FIFO_PIRQ is
> 15.
> >
> Again, only if msg->len is not 0, which is not ensured.
>

Agreed, we will fix in V2.

> Krzysztof