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.