26.01.2019 0:25, Dmitry Osipenko пишет:
> 25.01.2019 23:20, Sowjanya Komatineni пишет:
>>
>>
>>>> This patch prepares the buffer with the message bytes to be 
>>>> transmitted along with the packet header information and then performs 
>>>> i2c transfer in PIO mode.
>>>>
>>>> Signed-off-by: Sowjanya Komatineni <[email protected]>
>>>> ---
>>>>  [V2] : DMA support changes include preparing buffer with message bytes and
>>>>    and header before sending them through DMA. So splitted the whole
>>>>    change into 2 seperate patches in this series.
>>>>
>>>>  drivers/i2c/busses/i2c-tegra.c | 97 
>>>> +++++++++++++++++++++++++++++-------------
>>>>  1 file changed, 68 insertions(+), 29 deletions(-)
>>>>
>>>> diff --git a/drivers/i2c/busses/i2c-tegra.c 
>>>> b/drivers/i2c/busses/i2c-tegra.c index ef854be4c837..13bce1411ddc 
>>>> 100644
>>>> --- a/drivers/i2c/busses/i2c-tegra.c
>>>> +++ b/drivers/i2c/busses/i2c-tegra.c
>>>> @@ -117,6 +117,9 @@
>>>>  #define I2C_MST_FIFO_STATUS_TX_MASK               0xff0000
>>>>  #define I2C_MST_FIFO_STATUS_TX_SHIFT              16
>>>>  
>>>> +/* Packet header size in bytes */
>>>> +#define I2C_PACKET_HEADER_SIZE                    12
>>>> +
>>>>  /*
>>>>   * msg_end_type: The bus control which need to be send at end of transfer.
>>>>   * @MSG_END_STOP: Send stop pulse at end of transfer.
>>>> @@ -677,35 +680,69 @@ static irqreturn_t tegra_i2c_isr(int irq, void 
>>>> *dev_id)
>>>>    return IRQ_HANDLED;
>>>>  }
>>>>  
>>>> +static int tegra_i2c_start_pio_xfer(struct tegra_i2c_dev *i2c_dev) {
>>>> +  u32 *buffer = (u32 *)i2c_dev->msg_buf;
>>>> +  unsigned long flags;
>>>> +  u32 int_mask;
>>>> +
>>>> +  spin_lock_irqsave(&i2c_dev->xfer_lock, flags);
>>>> +
>>>> +  int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST;
>>>> +  tegra_i2c_unmask_irq(i2c_dev, int_mask);
>>>> +
>>>> +  i2c_writel(i2c_dev, *(buffer++), I2C_TX_FIFO);
>>>> +  i2c_writel(i2c_dev, *(buffer++), I2C_TX_FIFO);
>>>> +  i2c_writel(i2c_dev, *(buffer++), I2C_TX_FIFO);
>>>> +
>>>> +  i2c_dev->msg_buf = (u8 *) buffer;
>>>> +
>>>> +  if (!i2c_dev->msg_read)
>>>> +          tegra_i2c_fill_tx_fifo(i2c_dev);
>>>> +
>>>> +  if (i2c_dev->hw->has_per_pkt_xfer_complete_irq)
>>>> +          int_mask |= I2C_INT_PACKET_XFER_COMPLETE;
>>>> +  if (i2c_dev->msg_read)
>>>> +          int_mask |= I2C_INT_RX_FIFO_DATA_REQ;
>>>> +  else if (i2c_dev->msg_buf_remaining)
>>>> +          int_mask |= I2C_INT_TX_FIFO_DATA_REQ;
>>>> +
>>>> +  tegra_i2c_unmask_irq(i2c_dev, int_mask);
>>>> +  spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags);
>>>> +  dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
>>>> +          i2c_readl(i2c_dev, I2C_INT_MASK));
>>>> +
>>>> +  return 0;
>>>> +}
>>>> +
>>>>  static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
>>>>    struct i2c_msg *msg, enum msg_end_type end_state)  {
>>>>    u32 packet_header;
>>>>    u32 int_mask;
>>>>    unsigned long time_left;
>>>> -  unsigned long flags;
>>>> +  u32 *buffer;
>>>> +  int ret = 0;
>>>> +
>>>> +  buffer = kmalloc(ALIGN(msg->len, BYTES_PER_FIFO_WORD) +
>>>> +                                  I2C_PACKET_HEADER_SIZE, GFP_KERNEL);
>>>> +  if (!buffer)
>>>> +          return -ENOMEM;
>>>
>>> Isn't it possible to avoid "buffer" allocation / copying overhead and keep 
>>> code as-is for the PIO mode?
>>>
>>
>> Keeping PIO mode code as is and adding DMA mode will have redundant code for 
>> header generation and msg complete timeout sections.
>> Also in existing PIO mode implementation, TX FIFO is filled as soon as the 
>> word is ready but for DMA mode need to put all msg bytes along with header 
>> together to send thru DMA.
>> So created common buffer to perform PIO/DMA to reduce redundancy.
>>
> 
> Okay, what about something like in this sketch:
> 
> ...
>       if (msg->flags & I2C_M_RD)
>               xfer_size = msg->len;
>       else
>               xfer_size = ALIGN(msg->len, BYTES_PER_FIFO_WORD) +
>                           I2C_PACKET_HEADER_SIZE;
> 
>       dma = ((xfer_size > I2C_PIO_MODE_MAX_LEN) &&
>               i2c_dev->tx_dma_chan && i2c_dev->rx_dma_chan);
> 
>       if (dma) {
>               buffer = kmalloc(ALIGN(msg->len, BYTES_PER_FIFO_WORD) +
>                               I2C_PACKET_HEADER_SIZE, GFP_KERNEL);
>               i2c_dev->msg_buf = (u8 *)buffer;
>       }
> 
>       packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) |
>                               PACKET_HEADER0_PROTOCOL_I2C |
>                               (i2c_dev->cont_id << 
> PACKET_HEADER0_CONT_ID_SHIFT) |
>                               (1 << PACKET_HEADER0_PACKET_ID_SHIFT);
>               i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
> 
>       if (dma)
>               (*buffer++) = packet_header;
>       else
>               i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO);
> 
> ... and so on.
> 
> Likely that kmalloc overhead will be bigger than the above variant. Please 
> consider to avoid kmalloc and copying for the PIO case in the next version.
> 

Also, is the intermediate kmalloc "buffer" really needed at all? Why just not 
to write directly into the DMA buffer?

Reply via email to