Re: [PATCH v3 07/16] spi: dw: Use DMA max burst to set the request thresholds

From: Andy Shevchenko
Date: Thu May 21 2020 - 06:49:08 EST


On Thu, May 21, 2020 at 04:21:57AM +0300, Serge Semin wrote:
> Each channel of DMA controller may have a limited length of burst
> transaction (number of IO operations performed at ones in a single
> DMA client request). This parameter can be used to setup the most
> optimal DMA Tx/Rx data level values. In order to avoid the Tx buffer
> overrun we can set the DMA Tx level to be of FIFO depth minus the
> maximum burst transactions length. To prevent the Rx buffer underflow
> the DMA Rx level should be set to the maximum burst transactions length.
> This commit setups the DMA channels and the DW SPI DMA Tx/Rx levels
> in accordance with these rules.

Besides one bikeshedding point, looks good to me.
Feel free to add

Reviewed-by: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>

>
> Signed-off-by: Serge Semin <Sergey.Semin@xxxxxxxxxxxxxxxxxxxx>
> Cc: Alexey Malahov <Alexey.Malahov@xxxxxxxxxxxxxxxxxxxx>
> Cc: Thomas Bogendoerfer <tsbogend@xxxxxxxxxxxxxxxx>
> Cc: Paul Burton <paulburton@xxxxxxxxxx>
> Cc: Ralf Baechle <ralf@xxxxxxxxxxxxxx>
> Cc: Arnd Bergmann <arnd@xxxxxxxx>
> Cc: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx>
> Cc: Rob Herring <robh+dt@xxxxxxxxxx>
> Cc: linux-mips@xxxxxxxxxxxxxxx
> Cc: devicetree@xxxxxxxxxxxxxxx
>
> ---
>
> Changelog v3:
> - Use min() method to calculate the optimal burst values.
> ---
> drivers/spi/spi-dw-mid.c | 37 +++++++++++++++++++++++++++++++++----
> drivers/spi/spi-dw.h | 2 ++
> 2 files changed, 35 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
> index be02fedd87cb..0e95d8bc85c5 100644
> --- a/drivers/spi/spi-dw-mid.c
> +++ b/drivers/spi/spi-dw-mid.c
> @@ -34,6 +34,31 @@ static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
> return true;
> }
>
> +static void mid_spi_maxburst_init(struct dw_spi *dws)
> +{
> + struct dma_slave_caps caps;
> + u32 max_burst, def_burst;
> + int ret;
> +
> + def_burst = dws->fifo_len / 2;
> +
> + ret = dma_get_slave_caps(dws->rxchan, &caps);
> + if (!ret && caps.max_burst)
> + max_burst = caps.max_burst;
> + else
> + max_burst = RX_BURST_LEVEL;
> +
> + dws->rxburst = min(max_burst, def_burst);
> +
> + ret = dma_get_slave_caps(dws->txchan, &caps);
> + if (!ret && caps.max_burst)
> + max_burst = caps.max_burst;
> + else
> + max_burst = TX_BURST_LEVEL;
> +
> + dws->txburst = min(max_burst, def_burst);
> +}
> +
> static int mid_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
> {
> struct dw_dma_slave slave = {
> @@ -69,6 +94,8 @@ static int mid_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
> dws->master->dma_rx = dws->rxchan;
> dws->master->dma_tx = dws->txchan;
>
> + mid_spi_maxburst_init(dws);
> +
> return 0;
>
> free_rxchan:
> @@ -94,6 +121,8 @@ static int mid_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
> dws->master->dma_rx = dws->rxchan;
> dws->master->dma_tx = dws->txchan;
>
> + mid_spi_maxburst_init(dws);
> +
> return 0;
> }
>
> @@ -216,7 +245,7 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws,
> memset(&txconf, 0, sizeof(txconf));
> txconf.direction = DMA_MEM_TO_DEV;
> txconf.dst_addr = dws->dma_addr;
> - txconf.dst_maxburst = TX_BURST_LEVEL;
> + txconf.dst_maxburst = dws->txburst;
> txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> txconf.dst_addr_width = convert_dma_width(dws->n_bytes);
> txconf.device_fc = false;
> @@ -290,7 +319,7 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws,
> memset(&rxconf, 0, sizeof(rxconf));
> rxconf.direction = DMA_DEV_TO_MEM;
> rxconf.src_addr = dws->dma_addr;
> - rxconf.src_maxburst = RX_BURST_LEVEL;
> + rxconf.src_maxburst = dws->rxburst;
> rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
> rxconf.src_addr_width = convert_dma_width(dws->n_bytes);
> rxconf.device_fc = false;
> @@ -315,8 +344,8 @@ static int mid_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
> {
> u16 imr = 0, dma_ctrl = 0;
>
> - dw_writel(dws, DW_SPI_DMARDLR, RX_BURST_LEVEL - 1);
> - dw_writel(dws, DW_SPI_DMATDLR, TX_BURST_LEVEL);
> + dw_writel(dws, DW_SPI_DMARDLR, dws->rxburst - 1);
> + dw_writel(dws, DW_SPI_DMATDLR, dws->fifo_len - dws->txburst);
>
> if (xfer->tx_buf) {
> dma_ctrl |= SPI_DMA_TDMAE;
> diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
> index 4902f937c3d7..d0c8b7d3a5d2 100644
> --- a/drivers/spi/spi-dw.h
> +++ b/drivers/spi/spi-dw.h
> @@ -141,7 +141,9 @@ struct dw_spi {
>
> /* DMA info */
> struct dma_chan *txchan;
> + u32 txburst;
> struct dma_chan *rxchan;
> + u32 rxburst;
> unsigned long dma_chan_busy;
> dma_addr_t dma_addr; /* phy address of the Data register */
> const struct dw_spi_dma_ops *dma_ops;
> --
> 2.25.1
>

--
With Best Regards,
Andy Shevchenko