RE: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Sowjanya Komatineni
> > +static int tegra_i2c_init_dma_param(struct tegra_i2c_dev *i2c_dev,
> > +   bool dma_to_memory)
> > +{
> > +   struct dma_chan *dma_chan;
> > +   u32 *dma_buf;
> > +   dma_addr_t dma_phys;
> > +   int ret;
> > +   const char *chan_name = dma_to_memory ? "rx" : "tx";
> > +
> > +   dma_chan = dma_request_slave_channel_reason(i2c_dev->dev, chan_name);
> > +   if (IS_ERR(dma_chan))
> > +   return PTR_ERR(dma_chan);
>
> Here shall be a check of whether dma_buf is already allocated, otherwise it 
> will be allocated twice and the first allocation turned into memleak:
>
>   if (i2c_dev->dma_buf)
>   return 0;

If dma_buf is allocated already then dma channels will be assigned and it will 
not perform init dma again.
So if dma buf allocation happens already then it will not come here again.

> > +
> > +   dma_buf = dma_alloc_coherent(i2c_dev->dev, i2c_dev->dma_buf_size,
> > +_phys, GFP_KERNEL);
> > +
>
> I'm wondering whether a write-combined DMA mapping will be more optimal than 
> having L2 flushes / invalidation for the "coherent" allocations. 
>
> And I'm now questioning whether there is any real benefit from the DMA 
> transferring at all, given the DMA bounce-buffer CPU read/write overhead. It 
> looks to me that the whole purpose of the I2C DMA transferring is to move 
> data from (to) some I2C device to a > > some device on the APB bus, bypassing 
> the CPU. If that's is the case, then this patch may not really worth the 
> effort and instead could only hurt the transferring performance. Please 
> provide some performance results or correct me if I'm wrong.
>
> [snip]

DMA transfer helps to reduce overhead only during large transfer which is very 
rare operation. Will check and provide some performance data...

> >  
> > if (!i2c_dev->hw->has_single_clk_source) {
> > fast_clk = devm_clk_get(>dev, "fast-clk"); @@ -1079,6 
> > +1402,15 @@ static int tegra_i2c_probe(struct platform_device *pdev)
> > }
> > }
> >  
> > +   if (i2c_dev->has_dma) {
> > +   ret = tegra_i2c_init_dma_param(i2c_dev, true);
> > +   if (ret == -EPROBE_DEFER)
> > +   goto disable_div_clk;
> > +   ret = tegra_i2c_init_dma_param(i2c_dev, false);
> > +   if (ret == -EPROBE_DEFER)
> > +   goto disable_div_clk;
>
> Missing dma_buf freeing and channel releasing in a case of error.

dma buf freeing and channel release happens inside init_dma when buffer 
allocation fails.
If dma_request_slave_channel_reason fails no need to release channel but if 
channel request succeeds and buffer allocation fails, then buffer free and 
channel release will happen.

> > +   }
> > +
> > ret = tegra_i2c_init(i2c_dev);
> > if (ret) {
> > dev_err(>dev, "Failed to initialize i2c controller\n");
> > 



Re: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Dmitry Osipenko
26.01.2019 3:28, Dmitry Osipenko пишет:
> 24.01.2019 23:51, Sowjanya Komatineni пишет:
>> This patch adds DMA support for Tegra I2C.
>>
>> Tegra I2C TX and RX FIFO depth is 8 words. PIO mode is used for
>> transfer size of the max FIFO depth and DMA mode is used for
>> transfer size higher than max FIFO depth to save CPU overhead.
>>
>> PIO mode needs full intervention of CPU to fill or empty FIFO's
>> and also need to service multiple data requests interrupt for the
>> same transaction adding overhead on CPU for large transfers.
>>
>> DMA mode is helpful for Large transfers during downloading or
>> uploading FW over I2C to some external devices.
>>
>> Signed-off-by: Sowjanya Komatineni 
>> ---
>>  [V2] : Updated based on V1 review feedback along with code cleanup for
>>  proper implementation of DMA.
>>
>>  drivers/i2c/busses/i2c-tegra.c | 366 
>> +++--
>>  1 file changed, 349 insertions(+), 17 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
>> index 13bce1411ddc..769700d5a7f3 100644
>> --- a/drivers/i2c/busses/i2c-tegra.c
>> +++ b/drivers/i2c/busses/i2c-tegra.c
>> @@ -9,6 +9,9 @@
>>  #include 
>>  #include 
>>  #include 
>> +#include 
>> +#include 
>> +#include 
>>  #include 
>>  #include 
>>  #include 
>> @@ -46,6 +49,8 @@
>>  #define I2C_FIFO_CONTROL_RX_FLUSH   BIT(0)
>>  #define I2C_FIFO_CONTROL_TX_TRIG_SHIFT  5
>>  #define I2C_FIFO_CONTROL_RX_TRIG_SHIFT  2
>> +#define I2C_FIFO_CONTROL_TX_TRIG(x) (((x) - 1) << 5)
>> +#define I2C_FIFO_CONTROL_RX_TRIG(x) (((x) - 1) << 2)
>>  #define I2C_FIFO_STATUS 0x060
>>  #define I2C_FIFO_STATUS_TX_MASK 0xF0
>>  #define I2C_FIFO_STATUS_TX_SHIFT4
>> @@ -120,6 +125,16 @@
>>  /* Packet header size in bytes */
>>  #define I2C_PACKET_HEADER_SIZE  12
>>  
>> +#define DATA_DMA_DIR_TX (1 << 0)
>> +#define DATA_DMA_DIR_RX (1 << 1)
>> +
>> +/*
>> + * Upto I2C_PIO_MODE_MAX_LEN bytes, controller will use PIO mode,
>> + * above this, controller will use DMA to fill FIFO.
>> + * MAX PIO len is 20 bytes excluding packet header.
>> + */
>> +#define I2C_PIO_MODE_MAX_LEN32
>> +
>>  /*
>>   * 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.
>> @@ -180,6 +195,7 @@ struct tegra_i2c_hw_feature {
>>   * @fast_clk: clock reference for fast clock of I2C controller
>>   * @rst: reset control for the I2C controller
>>   * @base: ioremapped registers cookie
>> + * @phys_addr: Physical address of I2C base address to use for DMA 
>> configuration
>>   * @cont_id: I2C controller ID, used for packet header
>>   * @irq: IRQ number of transfer complete interrupt
>>   * @irq_disabled: used to track whether or not the interrupt is enabled
>> @@ -193,6 +209,14 @@ struct tegra_i2c_hw_feature {
>>   * @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
>>   * @is_multimaster_mode: track if I2C controller is in multi-master mode
>>   * @xfer_lock: lock to serialize transfer submission and processing
>> + * @has_dma: indicated if controller supports DMA
>> + * @tx_dma_chan: DMA transmit channel
>> + * @rx_dma_chan: DMA receive channel
>> + * @dma_phys: handle to DMA resources
>> + * @dma_buf: pointer to allocated DMA buffer
>> + * @dma_buf_size: DMA buffer size
>> + * @is_curr_dma_xfer: indicates active DMA transfer
>> + * @dma_complete: DMA completion notifier
>>   */
>>  struct tegra_i2c_dev {
>>  struct device *dev;
>> @@ -202,6 +226,7 @@ struct tegra_i2c_dev {
>>  struct clk *fast_clk;
>>  struct reset_control *rst;
>>  void __iomem *base;
>> +phys_addr_t phys_addr;
>>  int cont_id;
>>  int irq;
>>  bool irq_disabled;
>> @@ -215,8 +240,18 @@ struct tegra_i2c_dev {
>>  u16 clk_divisor_non_hs_mode;
>>  bool is_multimaster_mode;
>>  spinlock_t xfer_lock;
>> +bool has_dma;
>> +struct dma_chan *tx_dma_chan;
>> +struct dma_chan *rx_dma_chan;
>> +dma_addr_t dma_phys;
>> +u32 *dma_buf;
>> +unsigned int dma_buf_size;
>> +bool is_curr_dma_xfer;
>> +struct completion dma_complete;
>>  };
>>  
>> +static struct dma_chan *chan;
>> +
>>  static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
>> unsigned long reg)
>>  {
>> @@ -283,6 +318,75 @@ static void tegra_i2c_unmask_irq(struct tegra_i2c_dev 
>> *i2c_dev, u32 mask)
>>  i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
>>  }
>>  
>> +static void tegra_i2c_dma_complete(void *args)
>> +{
>> +struct tegra_i2c_dev *i2c_dev = args;
>> +
>> +complete(_dev->dma_complete);
>> +}
>> +
>> +static int tegra_i2c_dma_submit(struct tegra_i2c_dev *i2c_dev, size_t len)
>> +{
>> +struct dma_async_tx_descriptor *dma_desc;
>> +enum dma_transfer_direction dir;
>> +
>> +

Re: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Dmitry Osipenko
24.01.2019 23:51, Sowjanya Komatineni пишет:
> This patch adds DMA support for Tegra I2C.
> 
> Tegra I2C TX and RX FIFO depth is 8 words. PIO mode is used for
> transfer size of the max FIFO depth and DMA mode is used for
> transfer size higher than max FIFO depth to save CPU overhead.
> 
> PIO mode needs full intervention of CPU to fill or empty FIFO's
> and also need to service multiple data requests interrupt for the
> same transaction adding overhead on CPU for large transfers.
> 
> DMA mode is helpful for Large transfers during downloading or
> uploading FW over I2C to some external devices.
> 
> Signed-off-by: Sowjanya Komatineni 
> ---
>  [V2] : Updated based on V1 review feedback along with code cleanup for
>   proper implementation of DMA.
> 
>  drivers/i2c/busses/i2c-tegra.c | 366 
> +++--
>  1 file changed, 349 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index 13bce1411ddc..769700d5a7f3 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
> @@ -9,6 +9,9 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -46,6 +49,8 @@
>  #define I2C_FIFO_CONTROL_RX_FLUSHBIT(0)
>  #define I2C_FIFO_CONTROL_TX_TRIG_SHIFT   5
>  #define I2C_FIFO_CONTROL_RX_TRIG_SHIFT   2
> +#define I2C_FIFO_CONTROL_TX_TRIG(x)  (((x) - 1) << 5)
> +#define I2C_FIFO_CONTROL_RX_TRIG(x)  (((x) - 1) << 2)
>  #define I2C_FIFO_STATUS  0x060
>  #define I2C_FIFO_STATUS_TX_MASK  0xF0
>  #define I2C_FIFO_STATUS_TX_SHIFT 4
> @@ -120,6 +125,16 @@
>  /* Packet header size in bytes */
>  #define I2C_PACKET_HEADER_SIZE   12
>  
> +#define DATA_DMA_DIR_TX  (1 << 0)
> +#define DATA_DMA_DIR_RX  (1 << 1)
> +
> +/*
> + * Upto I2C_PIO_MODE_MAX_LEN bytes, controller will use PIO mode,
> + * above this, controller will use DMA to fill FIFO.
> + * MAX PIO len is 20 bytes excluding packet header.
> + */
> +#define I2C_PIO_MODE_MAX_LEN 32
> +
>  /*
>   * 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.
> @@ -180,6 +195,7 @@ struct tegra_i2c_hw_feature {
>   * @fast_clk: clock reference for fast clock of I2C controller
>   * @rst: reset control for the I2C controller
>   * @base: ioremapped registers cookie
> + * @phys_addr: Physical address of I2C base address to use for DMA 
> configuration
>   * @cont_id: I2C controller ID, used for packet header
>   * @irq: IRQ number of transfer complete interrupt
>   * @irq_disabled: used to track whether or not the interrupt is enabled
> @@ -193,6 +209,14 @@ struct tegra_i2c_hw_feature {
>   * @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
>   * @is_multimaster_mode: track if I2C controller is in multi-master mode
>   * @xfer_lock: lock to serialize transfer submission and processing
> + * @has_dma: indicated if controller supports DMA
> + * @tx_dma_chan: DMA transmit channel
> + * @rx_dma_chan: DMA receive channel
> + * @dma_phys: handle to DMA resources
> + * @dma_buf: pointer to allocated DMA buffer
> + * @dma_buf_size: DMA buffer size
> + * @is_curr_dma_xfer: indicates active DMA transfer
> + * @dma_complete: DMA completion notifier
>   */
>  struct tegra_i2c_dev {
>   struct device *dev;
> @@ -202,6 +226,7 @@ struct tegra_i2c_dev {
>   struct clk *fast_clk;
>   struct reset_control *rst;
>   void __iomem *base;
> + phys_addr_t phys_addr;
>   int cont_id;
>   int irq;
>   bool irq_disabled;
> @@ -215,8 +240,18 @@ struct tegra_i2c_dev {
>   u16 clk_divisor_non_hs_mode;
>   bool is_multimaster_mode;
>   spinlock_t xfer_lock;
> + bool has_dma;
> + struct dma_chan *tx_dma_chan;
> + struct dma_chan *rx_dma_chan;
> + dma_addr_t dma_phys;
> + u32 *dma_buf;
> + unsigned int dma_buf_size;
> + bool is_curr_dma_xfer;
> + struct completion dma_complete;
>  };
>  
> +static struct dma_chan *chan;
> +
>  static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
>  unsigned long reg)
>  {
> @@ -283,6 +318,75 @@ static void tegra_i2c_unmask_irq(struct tegra_i2c_dev 
> *i2c_dev, u32 mask)
>   i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
>  }
>  
> +static void tegra_i2c_dma_complete(void *args)
> +{
> + struct tegra_i2c_dev *i2c_dev = args;
> +
> + complete(_dev->dma_complete);
> +}
> +
> +static int tegra_i2c_dma_submit(struct tegra_i2c_dev *i2c_dev, size_t len)
> +{
> + struct dma_async_tx_descriptor *dma_desc;
> + enum dma_transfer_direction dir;
> +
> + dev_dbg(i2c_dev->dev, "Starting DMA for length: %zu\n", len);
> + reinit_completion(_dev->dma_complete);
> + dir = i2c_dev->msg_read ? 

RE: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Sowjanya Komatineni


> > > >>> + if (i2c_dev->has_dma) {
> > > >>> + ret = tegra_i2c_init_dma_param(i2c_dev, true);
> > > >>> + if (ret == -EPROBE_DEFER)
> > > >>> + goto disable_div_clk;
> > > >>> + ret = tegra_i2c_init_dma_param(i2c_dev, false);
> > > >>> + if (ret == -EPROBE_DEFER)
> > > >>> + goto disable_div_clk;
> > > >>
> > > >> So tegra_i2c_init_dma_param() could fail, printing a error 
> > > >> message, and probe will succeed? If allocation fails during the 
> > > >> driver's probe, then just fail the probe. Please give the 
> > > >> rationale.
> > > > 
> > > > If APB DMA probe doesn’t happen prior to tegra i2c, DMA is not 
> > > > available by the time tegra_init_dma_param tries to request slave 
> > > > channel and in those cases dma_request_slave_channel_reason will 
> > > > return EPROBE_DEFER for tegra I2C probe to retry
> > > > 
> > > > In case if DMA is available but DMA buffer allocation fails, then 
> > > > tegra_i2c_init_dma_param returns ENOMEM and probe also fails 
> > > > returning same ENOMEM
> > >
> > > Is that what you're going to change in the next version? Your 
> > > current variant of the code doesn't fail the probe on ENOMEM and 
> > > there is duplicated attempt to invoke tegra_i2c_init_dma_param() 
> > > during the transfer.
> > 
> > Sorry correction to my previous reply.  If DMA buffer allocation 
> > fails, tegra_i2c_init_dma_param returns ENOMEM but probe will succeed 
> > as i2c transaction need to happen during  boot for some platform 
> > device programming for successful boot and they use PIO mode as xfer 
> > bytes is less and deferring i2c probe for ENOMEM causes boot to fail 
> > so during probe EPROBE_DEFER is only taken care.
> > 
> > Re-attempt of tegra_i2c_init_dma_param in xfer happens only if no 
> > successful DMA channel allocation happens prior to that ( during probe 
> > in case of ENOMEM).
> > DMA mode is mainly for large transfer, and i2c xfer returning failure 
> > due to failing DMA buffer allocation causes boot to hang as platform 
> > device programming need to happen which doesn’t need to use DMA.
> > Will fix this and will send updated patch to reattempt DMA request and 
> > buffer allocation during DMA mode transfer and will return fail for 
> > DMA mode I2C transfer...
>
> I'm wondering if we shouldn't gracefully to PIO if we fail to allocate DMA 
> buffers. Even if it is unlikely that large transfers (> than the threshold 
> that activates the DMA paths) will be needed by critical I2C clients, there's 
> really no reason why we can't do PIO if DMA > doesn't work for some reason.
>
> Thierry

Yes we can fall back to PIO mode incase of DMA buffer allocation failure. Will 
add this in next revised patch

Sowjanya


Re: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Thierry Reding
On Fri, Jan 25, 2019 at 09:11:54PM +, Sowjanya Komatineni wrote:
> 
> 
> > >>> +   if (i2c_dev->has_dma) {
> > >>> +   ret = tegra_i2c_init_dma_param(i2c_dev, true);
> > >>> +   if (ret == -EPROBE_DEFER)
> > >>> +   goto disable_div_clk;
> > >>> +   ret = tegra_i2c_init_dma_param(i2c_dev, false);
> > >>> +   if (ret == -EPROBE_DEFER)
> > >>> +   goto disable_div_clk;
> > >>
> > >> So tegra_i2c_init_dma_param() could fail, printing a error
> > >> message, and probe will succeed? If allocation fails during the
> > >> driver's probe, then just fail the probe. Please give the
> > >> rationale.
> > > 
> > > If APB DMA probe doesn’t happen prior to tegra i2c, DMA is not
> > > available by the time tegra_init_dma_param tries to request slave
> > > channel and in those cases dma_request_slave_channel_reason will
> > > return EPROBE_DEFER for tegra I2C probe to retry
> > > 
> > > In case if DMA is available but DMA buffer allocation fails, then
> > > tegra_i2c_init_dma_param returns ENOMEM and probe also fails
> > > returning same ENOMEM
> >
> > Is that what you're going to change in the next version? Your
> > current variant of the code doesn't fail the probe on ENOMEM and
> > there is duplicated attempt to invoke tegra_i2c_init_dma_param()
> > during the transfer.
> 
> Sorry correction to my previous reply.  If DMA buffer allocation
> fails, tegra_i2c_init_dma_param returns ENOMEM but probe will succeed
> as i2c transaction need to happen during  boot for some platform
> device programming for successful boot and they use PIO mode as xfer
> bytes is less and deferring i2c probe for ENOMEM causes boot to fail
> so during probe EPROBE_DEFER is only taken care.
> 
> Re-attempt of tegra_i2c_init_dma_param in xfer happens only if no
> successful DMA channel allocation happens prior to that ( during probe
> in case of ENOMEM).
> DMA mode is mainly for large transfer, and i2c xfer returning failure
> due to failing DMA buffer allocation causes boot to hang as platform
> device programming need to happen which doesn’t need to use DMA.
> Will fix this and will send updated patch to reattempt DMA request and
> buffer allocation during DMA mode transfer and will return fail for
> DMA mode I2C transfer...

I'm wondering if we shouldn't gracefully to PIO if we fail to allocate
DMA buffers. Even if it is unlikely that large transfers (> than the
threshold that activates the DMA paths) will be needed by critical I2C
clients, there's really no reason why we can't do PIO if DMA doesn't
work for some reason.

Thierry


signature.asc
Description: PGP signature


Re: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Dmitry Osipenko
24.01.2019 23:51, Sowjanya Komatineni пишет:
> This patch adds DMA support for Tegra I2C.
> 
> Tegra I2C TX and RX FIFO depth is 8 words. PIO mode is used for
> transfer size of the max FIFO depth and DMA mode is used for
> transfer size higher than max FIFO depth to save CPU overhead.
> 
> PIO mode needs full intervention of CPU to fill or empty FIFO's
> and also need to service multiple data requests interrupt for the
> same transaction adding overhead on CPU for large transfers.
> 
> DMA mode is helpful for Large transfers during downloading or
> uploading FW over I2C to some external devices.
> 
> Signed-off-by: Sowjanya Komatineni 
> ---
>  [V2] : Updated based on V1 review feedback along with code cleanup for
>   proper implementation of DMA.
> 
>  drivers/i2c/busses/i2c-tegra.c | 366 
> +++--
>  1 file changed, 349 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index 13bce1411ddc..769700d5a7f3 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
> @@ -9,6 +9,9 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -46,6 +49,8 @@
>  #define I2C_FIFO_CONTROL_RX_FLUSHBIT(0)
>  #define I2C_FIFO_CONTROL_TX_TRIG_SHIFT   5
>  #define I2C_FIFO_CONTROL_RX_TRIG_SHIFT   2
> +#define I2C_FIFO_CONTROL_TX_TRIG(x)  (((x) - 1) << 5)
> +#define I2C_FIFO_CONTROL_RX_TRIG(x)  (((x) - 1) << 2)
>  #define I2C_FIFO_STATUS  0x060
>  #define I2C_FIFO_STATUS_TX_MASK  0xF0
>  #define I2C_FIFO_STATUS_TX_SHIFT 4
> @@ -120,6 +125,16 @@
>  /* Packet header size in bytes */
>  #define I2C_PACKET_HEADER_SIZE   12
>  
> +#define DATA_DMA_DIR_TX  (1 << 0)
> +#define DATA_DMA_DIR_RX  (1 << 1)
> +
> +/*
> + * Upto I2C_PIO_MODE_MAX_LEN bytes, controller will use PIO mode,
> + * above this, controller will use DMA to fill FIFO.
> + * MAX PIO len is 20 bytes excluding packet header.
> + */
> +#define I2C_PIO_MODE_MAX_LEN 32
> +
>  /*
>   * 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.
> @@ -180,6 +195,7 @@ struct tegra_i2c_hw_feature {
>   * @fast_clk: clock reference for fast clock of I2C controller
>   * @rst: reset control for the I2C controller
>   * @base: ioremapped registers cookie
> + * @phys_addr: Physical address of I2C base address to use for DMA 
> configuration
>   * @cont_id: I2C controller ID, used for packet header
>   * @irq: IRQ number of transfer complete interrupt
>   * @irq_disabled: used to track whether or not the interrupt is enabled
> @@ -193,6 +209,14 @@ struct tegra_i2c_hw_feature {
>   * @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
>   * @is_multimaster_mode: track if I2C controller is in multi-master mode
>   * @xfer_lock: lock to serialize transfer submission and processing
> + * @has_dma: indicated if controller supports DMA
> + * @tx_dma_chan: DMA transmit channel
> + * @rx_dma_chan: DMA receive channel
> + * @dma_phys: handle to DMA resources
> + * @dma_buf: pointer to allocated DMA buffer
> + * @dma_buf_size: DMA buffer size
> + * @is_curr_dma_xfer: indicates active DMA transfer
> + * @dma_complete: DMA completion notifier
>   */
>  struct tegra_i2c_dev {
>   struct device *dev;
> @@ -202,6 +226,7 @@ struct tegra_i2c_dev {
>   struct clk *fast_clk;
>   struct reset_control *rst;
>   void __iomem *base;
> + phys_addr_t phys_addr;
>   int cont_id;
>   int irq;
>   bool irq_disabled;
> @@ -215,8 +240,18 @@ struct tegra_i2c_dev {
>   u16 clk_divisor_non_hs_mode;
>   bool is_multimaster_mode;
>   spinlock_t xfer_lock;
> + bool has_dma;
> + struct dma_chan *tx_dma_chan;
> + struct dma_chan *rx_dma_chan;
> + dma_addr_t dma_phys;
> + u32 *dma_buf;
> + unsigned int dma_buf_size;
> + bool is_curr_dma_xfer;
> + struct completion dma_complete;
>  };
>  
> +static struct dma_chan *chan;
> +
>  static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
>  unsigned long reg)
>  {
> @@ -283,6 +318,75 @@ static void tegra_i2c_unmask_irq(struct tegra_i2c_dev 
> *i2c_dev, u32 mask)
>   i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
>  }
>  
> +static void tegra_i2c_dma_complete(void *args)
> +{
> + struct tegra_i2c_dev *i2c_dev = args;
> +
> + complete(_dev->dma_complete);
> +}
> +
> +static int tegra_i2c_dma_submit(struct tegra_i2c_dev *i2c_dev, size_t len)
> +{
> + struct dma_async_tx_descriptor *dma_desc;
> + enum dma_transfer_direction dir;
> +
> + dev_dbg(i2c_dev->dev, "Starting DMA for length: %zu\n", len);
> + reinit_completion(_dev->dma_complete);
> + dir = i2c_dev->msg_read ? 

RE: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Sowjanya Komatineni


> > +   if (i2c_dev->has_dma) {
> > +   ret = tegra_i2c_init_dma_param(i2c_dev, true);
> > +   if (ret == -EPROBE_DEFER)
> > +   goto disable_div_clk;
> > +   ret = tegra_i2c_init_dma_param(i2c_dev, false);
> > +   if (ret == -EPROBE_DEFER)
> > +   goto disable_div_clk;
> 
>  So tegra_i2c_init_dma_param() could fail, printing a error message, and 
>  probe will succeed? If allocation fails during the driver's probe, then 
>  just fail the probe. Please give the rationale.
> >>>
> >>> If APB DMA probe doesn’t happen prior to tegra i2c, DMA is not available 
> >>> by the time tegra_init_dma_param tries to request slave channel and in 
> >>> those cases dma_request_slave_channel_reason will return EPROBE_DEFER for 
> >>> tegra I2C probe to retry
> >>>
> >>> In case if DMA is available but DMA buffer allocation fails, then 
> >>> tegra_i2c_init_dma_param returns ENOMEM and probe also fails returning 
> >>> same ENOMEM
> >>
> >> Is that what you're going to change in the next version? Your current 
> >> variant of the code doesn't fail the probe on ENOMEM and there is 
> >> duplicated attempt to invoke tegra_i2c_init_dma_param() during the 
> >> transfer.
> > 
> > Sorry correction to my previous reply.  If DMA buffer allocation fails, 
> > tegra_i2c_init_dma_param returns ENOMEM but probe will succeed as i2c 
> > transaction need to happen during  boot for some platform device 
> > programming for successful boot and they use PIO > mode as xfer bytes is 
> > less and deferring i2c probe for ENOMEM causes boot to fail so during probe 
> > EPROBE_DEFER is only taken care.
> > 
> > Re-attempt of tegra_i2c_init_dma_param in xfer happens only if no 
> > successful DMA channel allocation happens prior to that ( during probe in 
> > case of ENOMEM).
> > DMA mode is mainly for large transfer, and i2c xfer returning failure due 
> > to failing DMA buffer allocation causes boot to hang as platform device 
> > programming need to happen which doesn’t need to use DMA.
> > Will fix this and will send updated patch to reattempt DMA request and 
> > buffer allocation during DMA mode transfer and will return fail for DMA 
> > mode I2C transfer...
>
> 1) The chance to get ENOMEM during is miserable and likely that there are 
> much bigger problems in this case. Hence just fail the probe if 
> tegra_i2c_init_dma_param() fails with any error.

Agree. 

> 2) What is that super-critical platform device? It is possible to compile 
> tegra-i2c as a kernel module and seems nothing enforces CONFIG_I2C_TEGRA=y.
Some of the i2c device  access happens during boot for some tegra platforms 
like jetson tx1, tx2.. (Eg: I2C GPIO expanders, PMIC access...)

> 3) After applying these patches I2C transfers are failing on Tegra20 with 
> "tegra-i2c 7000c400.i2c: Failed to allocate the DMA buffer". 
This patch should not cause DMA buffer allocation failure to happen. But if 
allocation fails (it couldn’t allocate contiguous physical memory for some 
reason), then transfers will definitely fail with this patch.

Will send updated patch with not re-attempt and in probe to return on error so 
if it will either defer or fail in case of ENOMEM.


Re: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Dmitry Osipenko
26.01.2019 0:49, Dmitry Osipenko пишет:

> 3) After applying these patches I2C transfers are failing on Tegra20 with 
> "tegra-i2c 7000c400.i2c: Failed to allocate the DMA buffer". 
> 

Actually scratch the above, turned out I haven't applied patches correctly. In 
fact patches are failing to apply with:

# git apply --verbose V2-3-4-i2c-tegra-Add-DMA-Support.patch
Checking patch drivers/i2c/busses/i2c-tegra.c...
Hunk #4 succeeded at 198 (offset 3 lines).
Hunk #5 succeeded at 212 (offset 3 lines).
Hunk #6 succeeded at 229 (offset 3 lines).
Hunk #7 succeeded at 243 (offset 3 lines).
Hunk #8 succeeded at 321 (offset 3 lines).
Hunk #9 succeeded at 636 (offset 3 lines).
Hunk #10 succeeded at 751 (offset 3 lines).
Hunk #11 succeeded at 798 (offset 3 lines).
Hunk #12 succeeded at 968 (offset 3 lines).
Hunk #13 succeeded at 996 (offset 3 lines).
Hunk #14 succeeded at 1050 (offset 3 lines).
Hunk #15 succeeded at 1075 (offset 3 lines).
Hunk #16 succeeded at 1125 (offset 3 lines).
Hunk #17 succeeded at 1180 (offset 3 lines).
Hunk #18 succeeded at 1304 (offset 13 lines).
error: while searching for:
return -ENOMEM;

i2c_dev->base = base;
i2c_dev->div_clk = div_clk;
i2c_dev->adapter.algo = _i2c_algo;
i2c_dev->adapter.quirks = _i2c_quirks;
i2c_dev->irq = irq;
i2c_dev->cont_id = pdev->id;
i2c_dev->dev = >dev;

i2c_dev->rst = devm_reset_control_get_exclusive(>dev, "i2c");
if (IS_ERR(i2c_dev->rst)) {

error: patch failed: drivers/i2c/busses/i2c-tegra.c:1000
error: drivers/i2c/busses/i2c-tegra.c: patch does not apply


Please use "git format-patch -4 " and do not edit patches manually.


Re: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Dmitry Osipenko
24.01.2019 23:51, Sowjanya Komatineni пишет:
> This patch adds DMA support for Tegra I2C.
> 
> Tegra I2C TX and RX FIFO depth is 8 words. PIO mode is used for
> transfer size of the max FIFO depth and DMA mode is used for
> transfer size higher than max FIFO depth to save CPU overhead.
> 
> PIO mode needs full intervention of CPU to fill or empty FIFO's
> and also need to service multiple data requests interrupt for the
> same transaction adding overhead on CPU for large transfers.
> 
> DMA mode is helpful for Large transfers during downloading or
> uploading FW over I2C to some external devices.
> 
> Signed-off-by: Sowjanya Komatineni 
> ---
>  [V2] : Updated based on V1 review feedback along with code cleanup for
>   proper implementation of DMA.
> 
>  drivers/i2c/busses/i2c-tegra.c | 366 
> +++--
>  1 file changed, 349 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index 13bce1411ddc..769700d5a7f3 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
> @@ -9,6 +9,9 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -46,6 +49,8 @@
>  #define I2C_FIFO_CONTROL_RX_FLUSHBIT(0)
>  #define I2C_FIFO_CONTROL_TX_TRIG_SHIFT   5
>  #define I2C_FIFO_CONTROL_RX_TRIG_SHIFT   2
> +#define I2C_FIFO_CONTROL_TX_TRIG(x)  (((x) - 1) << 5)
> +#define I2C_FIFO_CONTROL_RX_TRIG(x)  (((x) - 1) << 2)
>  #define I2C_FIFO_STATUS  0x060
>  #define I2C_FIFO_STATUS_TX_MASK  0xF0
>  #define I2C_FIFO_STATUS_TX_SHIFT 4
> @@ -120,6 +125,16 @@
>  /* Packet header size in bytes */
>  #define I2C_PACKET_HEADER_SIZE   12
>  
> +#define DATA_DMA_DIR_TX  (1 << 0)
> +#define DATA_DMA_DIR_RX  (1 << 1)
> +
> +/*
> + * Upto I2C_PIO_MODE_MAX_LEN bytes, controller will use PIO mode,
> + * above this, controller will use DMA to fill FIFO.
> + * MAX PIO len is 20 bytes excluding packet header.
> + */
> +#define I2C_PIO_MODE_MAX_LEN 32
> +
>  /*
>   * 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.
> @@ -180,6 +195,7 @@ struct tegra_i2c_hw_feature {
>   * @fast_clk: clock reference for fast clock of I2C controller
>   * @rst: reset control for the I2C controller
>   * @base: ioremapped registers cookie
> + * @phys_addr: Physical address of I2C base address to use for DMA 
> configuration
>   * @cont_id: I2C controller ID, used for packet header
>   * @irq: IRQ number of transfer complete interrupt
>   * @irq_disabled: used to track whether or not the interrupt is enabled
> @@ -193,6 +209,14 @@ struct tegra_i2c_hw_feature {
>   * @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
>   * @is_multimaster_mode: track if I2C controller is in multi-master mode
>   * @xfer_lock: lock to serialize transfer submission and processing
> + * @has_dma: indicated if controller supports DMA
> + * @tx_dma_chan: DMA transmit channel
> + * @rx_dma_chan: DMA receive channel
> + * @dma_phys: handle to DMA resources
> + * @dma_buf: pointer to allocated DMA buffer
> + * @dma_buf_size: DMA buffer size
> + * @is_curr_dma_xfer: indicates active DMA transfer
> + * @dma_complete: DMA completion notifier
>   */
>  struct tegra_i2c_dev {
>   struct device *dev;
> @@ -202,6 +226,7 @@ struct tegra_i2c_dev {
>   struct clk *fast_clk;
>   struct reset_control *rst;
>   void __iomem *base;
> + phys_addr_t phys_addr;
>   int cont_id;
>   int irq;
>   bool irq_disabled;
> @@ -215,8 +240,18 @@ struct tegra_i2c_dev {
>   u16 clk_divisor_non_hs_mode;
>   bool is_multimaster_mode;
>   spinlock_t xfer_lock;
> + bool has_dma;
> + struct dma_chan *tx_dma_chan;
> + struct dma_chan *rx_dma_chan;
> + dma_addr_t dma_phys;
> + u32 *dma_buf;
> + unsigned int dma_buf_size;
> + bool is_curr_dma_xfer;
> + struct completion dma_complete;
>  };
>  
> +static struct dma_chan *chan;
> +
>  static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
>  unsigned long reg)
>  {
> @@ -283,6 +318,75 @@ static void tegra_i2c_unmask_irq(struct tegra_i2c_dev 
> *i2c_dev, u32 mask)
>   i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
>  }
>  
> +static void tegra_i2c_dma_complete(void *args)
> +{
> + struct tegra_i2c_dev *i2c_dev = args;
> +
> + complete(_dev->dma_complete);
> +}
> +
> +static int tegra_i2c_dma_submit(struct tegra_i2c_dev *i2c_dev, size_t len)
> +{
> + struct dma_async_tx_descriptor *dma_desc;
> + enum dma_transfer_direction dir;
> +
> + dev_dbg(i2c_dev->dev, "Starting DMA for length: %zu\n", len);
> + reinit_completion(_dev->dma_complete);
> + dir = i2c_dev->msg_read ? 

Re: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Dmitry Osipenko
26.01.2019 0:11, Sowjanya Komatineni пишет:
> 
> 
> + if (i2c_dev->has_dma) {
> + ret = tegra_i2c_init_dma_param(i2c_dev, true);
> + if (ret == -EPROBE_DEFER)
> + goto disable_div_clk;
> + ret = tegra_i2c_init_dma_param(i2c_dev, false);
> + if (ret == -EPROBE_DEFER)
> + goto disable_div_clk;

 So tegra_i2c_init_dma_param() could fail, printing a error message, and 
 probe will succeed? If allocation fails during the driver's probe, then 
 just fail the probe. Please give the rationale.
>>>
>>> If APB DMA probe doesn’t happen prior to tegra i2c, DMA is not available by 
>>> the time tegra_init_dma_param tries to request slave channel and in those 
>>> cases dma_request_slave_channel_reason will return EPROBE_DEFER for tegra 
>>> I2C probe to retry
>>>
>>> In case if DMA is available but DMA buffer allocation fails, then 
>>> tegra_i2c_init_dma_param returns ENOMEM and probe also fails returning same 
>>> ENOMEM
>>
>> Is that what you're going to change in the next version? Your current 
>> variant of the code doesn't fail the probe on ENOMEM and there is duplicated 
>> attempt to invoke tegra_i2c_init_dma_param() during the transfer.
> 
> Sorry correction to my previous reply.  If DMA buffer allocation fails, 
> tegra_i2c_init_dma_param returns ENOMEM but probe will succeed as i2c 
> transaction need to happen during  boot for some platform device programming 
> for successful boot and they use PIO mode as xfer bytes is less and deferring 
> i2c probe for ENOMEM causes boot to fail so during probe EPROBE_DEFER is only 
> taken care.
> 
> Re-attempt of tegra_i2c_init_dma_param in xfer happens only if no successful 
> DMA channel allocation happens prior to that ( during probe in case of 
> ENOMEM).
> DMA mode is mainly for large transfer, and i2c xfer returning failure due to 
> failing DMA buffer allocation causes boot to hang as platform device 
> programming need to happen which doesn’t need to use DMA.
> Will fix this and will send updated patch to reattempt DMA request and buffer 
> allocation during DMA mode transfer and will return fail for DMA mode I2C 
> transfer...

1) The chance to get ENOMEM during is miserable and likely that there are much 
bigger problems in this case. Hence just fail the probe if 
tegra_i2c_init_dma_param() fails with any error.

2) What is that super-critical platform device? It is possible to compile 
tegra-i2c as a kernel module and seems nothing enforces CONFIG_I2C_TEGRA=y.

3) After applying these patches I2C transfers are failing on Tegra20 with 
"tegra-i2c 7000c400.i2c: Failed to allocate the DMA buffer". 


RE: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Sowjanya Komatineni


> >>> + if (i2c_dev->has_dma) {
> >>> + ret = tegra_i2c_init_dma_param(i2c_dev, true);
> >>> + if (ret == -EPROBE_DEFER)
> >>> + goto disable_div_clk;
> >>> + ret = tegra_i2c_init_dma_param(i2c_dev, false);
> >>> + if (ret == -EPROBE_DEFER)
> >>> + goto disable_div_clk;
> >>
> >> So tegra_i2c_init_dma_param() could fail, printing a error message, and 
> >> probe will succeed? If allocation fails during the driver's probe, then 
> >> just fail the probe. Please give the rationale.
> > 
> > If APB DMA probe doesn’t happen prior to tegra i2c, DMA is not available by 
> > the time tegra_init_dma_param tries to request slave channel and in those 
> > cases dma_request_slave_channel_reason will return EPROBE_DEFER for tegra 
> > I2C probe to retry
> > 
> > In case if DMA is available but DMA buffer allocation fails, then 
> > tegra_i2c_init_dma_param returns ENOMEM and probe also fails returning same 
> > ENOMEM
>
> Is that what you're going to change in the next version? Your current variant 
> of the code doesn't fail the probe on ENOMEM and there is duplicated attempt 
> to invoke tegra_i2c_init_dma_param() during the transfer.

Sorry correction to my previous reply.  If DMA buffer allocation fails, 
tegra_i2c_init_dma_param returns ENOMEM but probe will succeed as i2c 
transaction need to happen during  boot for some platform device programming 
for successful boot and they use PIO mode as xfer bytes is less and deferring 
i2c probe for ENOMEM causes boot to fail so during probe EPROBE_DEFER is only 
taken care.

Re-attempt of tegra_i2c_init_dma_param in xfer happens only if no successful 
DMA channel allocation happens prior to that ( during probe in case of ENOMEM).
DMA mode is mainly for large transfer, and i2c xfer returning failure due to 
failing DMA buffer allocation causes boot to hang as platform device 
programming need to happen which doesn’t need to use DMA.
Will fix this and will send updated patch to reattempt DMA request and buffer 
allocation during DMA mode transfer and will return fail for DMA mode I2C 
transfer...

Thanks
Sowjanya


Re: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Dmitry Osipenko
25.01.2019 23:31, Sowjanya Komatineni пишет:
> 
>>> +   if (i2c_dev->has_dma) {
>>> +   ret = tegra_i2c_init_dma_param(i2c_dev, true);
>>> +   if (ret == -EPROBE_DEFER)
>>> +   goto disable_div_clk;
>>> +   ret = tegra_i2c_init_dma_param(i2c_dev, false);
>>> +   if (ret == -EPROBE_DEFER)
>>> +   goto disable_div_clk;
>>
>> So tegra_i2c_init_dma_param() could fail, printing a error message, and 
>> probe will succeed? If allocation fails during the driver's probe, then just 
>> fail the probe. Please give the rationale.
> 
> If APB DMA probe doesn’t happen prior to tegra i2c, DMA is not available by 
> the time tegra_init_dma_param tries to request slave channel and in those 
> cases dma_request_slave_channel_reason will return EPROBE_DEFER for tegra I2C 
> probe to retry
> 
> In case if DMA is available but DMA buffer allocation fails, then 
> tegra_i2c_init_dma_param returns ENOMEM and probe also fails returning same 
> ENOMEM

Is that what you're going to change in the next version? Your current variant 
of the code doesn't fail the probe on ENOMEM and there is duplicated attempt to 
invoke tegra_i2c_init_dma_param() during the transfer.


RE: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Sowjanya Komatineni

> > +   if (i2c_dev->has_dma) {
> > +   ret = tegra_i2c_init_dma_param(i2c_dev, true);
> > +   if (ret == -EPROBE_DEFER)
> > +   goto disable_div_clk;
> > +   ret = tegra_i2c_init_dma_param(i2c_dev, false);
> > +   if (ret == -EPROBE_DEFER)
> > +   goto disable_div_clk;
>
> So tegra_i2c_init_dma_param() could fail, printing a error message, and probe 
> will succeed? If allocation fails during the driver's probe, then just fail 
> the probe. Please give the rationale.

If APB DMA probe doesn’t happen prior to tegra i2c, DMA is not available by the 
time tegra_init_dma_param tries to request slave channel and in those cases 
dma_request_slave_channel_reason will return EPROBE_DEFER for tegra I2C probe 
to retry

In case if DMA is available but DMA buffer allocation fails, then 
tegra_i2c_init_dma_param returns ENOMEM and probe also fails returning same 
ENOMEM

Thanks
Sowjanya



Re: [PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-25 Thread Dmitry Osipenko
24.01.2019 23:51, Sowjanya Komatineni пишет:
> This patch adds DMA support for Tegra I2C.
> 
> Tegra I2C TX and RX FIFO depth is 8 words. PIO mode is used for
> transfer size of the max FIFO depth and DMA mode is used for
> transfer size higher than max FIFO depth to save CPU overhead.
> 
> PIO mode needs full intervention of CPU to fill or empty FIFO's
> and also need to service multiple data requests interrupt for the
> same transaction adding overhead on CPU for large transfers.
> 
> DMA mode is helpful for Large transfers during downloading or
> uploading FW over I2C to some external devices.
> 
> Signed-off-by: Sowjanya Komatineni 
> ---
>  [V2] : Updated based on V1 review feedback along with code cleanup for
>   proper implementation of DMA.
> 
>  drivers/i2c/busses/i2c-tegra.c | 366 
> +++--
>  1 file changed, 349 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
> index 13bce1411ddc..769700d5a7f3 100644
> --- a/drivers/i2c/busses/i2c-tegra.c
> +++ b/drivers/i2c/busses/i2c-tegra.c
> @@ -9,6 +9,9 @@
>  #include 
>  #include 
>  #include 
> +#include 
> +#include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -46,6 +49,8 @@
>  #define I2C_FIFO_CONTROL_RX_FLUSHBIT(0)
>  #define I2C_FIFO_CONTROL_TX_TRIG_SHIFT   5
>  #define I2C_FIFO_CONTROL_RX_TRIG_SHIFT   2
> +#define I2C_FIFO_CONTROL_TX_TRIG(x)  (((x) - 1) << 5)
> +#define I2C_FIFO_CONTROL_RX_TRIG(x)  (((x) - 1) << 2)
>  #define I2C_FIFO_STATUS  0x060
>  #define I2C_FIFO_STATUS_TX_MASK  0xF0
>  #define I2C_FIFO_STATUS_TX_SHIFT 4
> @@ -120,6 +125,16 @@
>  /* Packet header size in bytes */
>  #define I2C_PACKET_HEADER_SIZE   12
>  
> +#define DATA_DMA_DIR_TX  (1 << 0)
> +#define DATA_DMA_DIR_RX  (1 << 1)
> +
> +/*
> + * Upto I2C_PIO_MODE_MAX_LEN bytes, controller will use PIO mode,
> + * above this, controller will use DMA to fill FIFO.
> + * MAX PIO len is 20 bytes excluding packet header.
> + */
> +#define I2C_PIO_MODE_MAX_LEN 32
> +
>  /*
>   * 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.
> @@ -180,6 +195,7 @@ struct tegra_i2c_hw_feature {
>   * @fast_clk: clock reference for fast clock of I2C controller
>   * @rst: reset control for the I2C controller
>   * @base: ioremapped registers cookie
> + * @phys_addr: Physical address of I2C base address to use for DMA 
> configuration
>   * @cont_id: I2C controller ID, used for packet header
>   * @irq: IRQ number of transfer complete interrupt
>   * @irq_disabled: used to track whether or not the interrupt is enabled
> @@ -193,6 +209,14 @@ struct tegra_i2c_hw_feature {
>   * @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
>   * @is_multimaster_mode: track if I2C controller is in multi-master mode
>   * @xfer_lock: lock to serialize transfer submission and processing
> + * @has_dma: indicated if controller supports DMA
> + * @tx_dma_chan: DMA transmit channel
> + * @rx_dma_chan: DMA receive channel
> + * @dma_phys: handle to DMA resources
> + * @dma_buf: pointer to allocated DMA buffer
> + * @dma_buf_size: DMA buffer size
> + * @is_curr_dma_xfer: indicates active DMA transfer
> + * @dma_complete: DMA completion notifier
>   */
>  struct tegra_i2c_dev {
>   struct device *dev;
> @@ -202,6 +226,7 @@ struct tegra_i2c_dev {
>   struct clk *fast_clk;
>   struct reset_control *rst;
>   void __iomem *base;
> + phys_addr_t phys_addr;
>   int cont_id;
>   int irq;
>   bool irq_disabled;
> @@ -215,8 +240,18 @@ struct tegra_i2c_dev {
>   u16 clk_divisor_non_hs_mode;
>   bool is_multimaster_mode;
>   spinlock_t xfer_lock;
> + bool has_dma;
> + struct dma_chan *tx_dma_chan;
> + struct dma_chan *rx_dma_chan;
> + dma_addr_t dma_phys;
> + u32 *dma_buf;
> + unsigned int dma_buf_size;
> + bool is_curr_dma_xfer;
> + struct completion dma_complete;
>  };
>  
> +static struct dma_chan *chan;
> +
>  static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
>  unsigned long reg)
>  {
> @@ -283,6 +318,75 @@ static void tegra_i2c_unmask_irq(struct tegra_i2c_dev 
> *i2c_dev, u32 mask)
>   i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
>  }
>  
> +static void tegra_i2c_dma_complete(void *args)
> +{
> + struct tegra_i2c_dev *i2c_dev = args;
> +
> + complete(_dev->dma_complete);
> +}
> +
> +static int tegra_i2c_dma_submit(struct tegra_i2c_dev *i2c_dev, size_t len)
> +{
> + struct dma_async_tx_descriptor *dma_desc;
> + enum dma_transfer_direction dir;
> +
> + dev_dbg(i2c_dev->dev, "Starting DMA for length: %zu\n", len);
> + reinit_completion(_dev->dma_complete);
> + dir = i2c_dev->msg_read ? 

[PATCH V2 3/4] i2c: tegra: Add DMA Support

2019-01-24 Thread Sowjanya Komatineni
This patch adds DMA support for Tegra I2C.

Tegra I2C TX and RX FIFO depth is 8 words. PIO mode is used for
transfer size of the max FIFO depth and DMA mode is used for
transfer size higher than max FIFO depth to save CPU overhead.

PIO mode needs full intervention of CPU to fill or empty FIFO's
and also need to service multiple data requests interrupt for the
same transaction adding overhead on CPU for large transfers.

DMA mode is helpful for Large transfers during downloading or
uploading FW over I2C to some external devices.

Signed-off-by: Sowjanya Komatineni 
---
 [V2] : Updated based on V1 review feedback along with code cleanup for
proper implementation of DMA.

 drivers/i2c/busses/i2c-tegra.c | 366 +++--
 1 file changed, 349 insertions(+), 17 deletions(-)

diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 13bce1411ddc..769700d5a7f3 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -9,6 +9,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -46,6 +49,8 @@
 #define I2C_FIFO_CONTROL_RX_FLUSH  BIT(0)
 #define I2C_FIFO_CONTROL_TX_TRIG_SHIFT 5
 #define I2C_FIFO_CONTROL_RX_TRIG_SHIFT 2
+#define I2C_FIFO_CONTROL_TX_TRIG(x)(((x) - 1) << 5)
+#define I2C_FIFO_CONTROL_RX_TRIG(x)(((x) - 1) << 2)
 #define I2C_FIFO_STATUS0x060
 #define I2C_FIFO_STATUS_TX_MASK0xF0
 #define I2C_FIFO_STATUS_TX_SHIFT   4
@@ -120,6 +125,16 @@
 /* Packet header size in bytes */
 #define I2C_PACKET_HEADER_SIZE 12
 
+#define DATA_DMA_DIR_TX(1 << 0)
+#define DATA_DMA_DIR_RX(1 << 1)
+
+/*
+ * Upto I2C_PIO_MODE_MAX_LEN bytes, controller will use PIO mode,
+ * above this, controller will use DMA to fill FIFO.
+ * MAX PIO len is 20 bytes excluding packet header.
+ */
+#define I2C_PIO_MODE_MAX_LEN   32
+
 /*
  * 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.
@@ -180,6 +195,7 @@ struct tegra_i2c_hw_feature {
  * @fast_clk: clock reference for fast clock of I2C controller
  * @rst: reset control for the I2C controller
  * @base: ioremapped registers cookie
+ * @phys_addr: Physical address of I2C base address to use for DMA 
configuration
  * @cont_id: I2C controller ID, used for packet header
  * @irq: IRQ number of transfer complete interrupt
  * @irq_disabled: used to track whether or not the interrupt is enabled
@@ -193,6 +209,14 @@ struct tegra_i2c_hw_feature {
  * @clk_divisor_non_hs_mode: clock divider for non-high-speed modes
  * @is_multimaster_mode: track if I2C controller is in multi-master mode
  * @xfer_lock: lock to serialize transfer submission and processing
+ * @has_dma: indicated if controller supports DMA
+ * @tx_dma_chan: DMA transmit channel
+ * @rx_dma_chan: DMA receive channel
+ * @dma_phys: handle to DMA resources
+ * @dma_buf: pointer to allocated DMA buffer
+ * @dma_buf_size: DMA buffer size
+ * @is_curr_dma_xfer: indicates active DMA transfer
+ * @dma_complete: DMA completion notifier
  */
 struct tegra_i2c_dev {
struct device *dev;
@@ -202,6 +226,7 @@ struct tegra_i2c_dev {
struct clk *fast_clk;
struct reset_control *rst;
void __iomem *base;
+   phys_addr_t phys_addr;
int cont_id;
int irq;
bool irq_disabled;
@@ -215,8 +240,18 @@ struct tegra_i2c_dev {
u16 clk_divisor_non_hs_mode;
bool is_multimaster_mode;
spinlock_t xfer_lock;
+   bool has_dma;
+   struct dma_chan *tx_dma_chan;
+   struct dma_chan *rx_dma_chan;
+   dma_addr_t dma_phys;
+   u32 *dma_buf;
+   unsigned int dma_buf_size;
+   bool is_curr_dma_xfer;
+   struct completion dma_complete;
 };
 
+static struct dma_chan *chan;
+
 static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val,
   unsigned long reg)
 {
@@ -283,6 +318,75 @@ static void tegra_i2c_unmask_irq(struct tegra_i2c_dev 
*i2c_dev, u32 mask)
i2c_writel(i2c_dev, int_mask, I2C_INT_MASK);
 }
 
+static void tegra_i2c_dma_complete(void *args)
+{
+   struct tegra_i2c_dev *i2c_dev = args;
+
+   complete(_dev->dma_complete);
+}
+
+static int tegra_i2c_dma_submit(struct tegra_i2c_dev *i2c_dev, size_t len)
+{
+   struct dma_async_tx_descriptor *dma_desc;
+   enum dma_transfer_direction dir;
+
+   dev_dbg(i2c_dev->dev, "Starting DMA for length: %zu\n", len);
+   reinit_completion(_dev->dma_complete);
+   dir = i2c_dev->msg_read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
+   dma_desc = dmaengine_prep_slave_single(chan, i2c_dev->dma_phys,
+  len, dir, DMA_PREP_INTERRUPT |
+  DMA_CTRL_ACK);
+   if