Skip to content

Commit 0b2b665

Browse files
fancerbroonie
authored andcommitted
spi: dw: Use DMA max burst to set the request thresholds
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. Signed-off-by: Serge Semin <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Cc: Alexey Malahov <[email protected]> Cc: Thomas Bogendoerfer <[email protected]> Cc: Arnd Bergmann <[email protected]> Cc: Feng Tang <[email protected]> Cc: Rob Herring <[email protected]> Cc: [email protected] Cc: [email protected] Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent c534df9 commit 0b2b665

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

drivers/spi/spi-dw-mid.c

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,31 @@ static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
3636
return true;
3737
}
3838

39+
static void mid_spi_maxburst_init(struct dw_spi *dws)
40+
{
41+
struct dma_slave_caps caps;
42+
u32 max_burst, def_burst;
43+
int ret;
44+
45+
def_burst = dws->fifo_len / 2;
46+
47+
ret = dma_get_slave_caps(dws->rxchan, &caps);
48+
if (!ret && caps.max_burst)
49+
max_burst = caps.max_burst;
50+
else
51+
max_burst = RX_BURST_LEVEL;
52+
53+
dws->rxburst = min(max_burst, def_burst);
54+
55+
ret = dma_get_slave_caps(dws->txchan, &caps);
56+
if (!ret && caps.max_burst)
57+
max_burst = caps.max_burst;
58+
else
59+
max_burst = TX_BURST_LEVEL;
60+
61+
dws->txburst = min(max_burst, def_burst);
62+
}
63+
3964
static int mid_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
4065
{
4166
struct dw_dma_slave slave = {
@@ -73,6 +98,8 @@ static int mid_spi_dma_init_mfld(struct device *dev, struct dw_spi *dws)
7398

7499
init_completion(&dws->dma_completion);
75100

101+
mid_spi_maxburst_init(dws);
102+
76103
return 0;
77104

78105
free_rxchan:
@@ -100,6 +127,8 @@ static int mid_spi_dma_init_generic(struct device *dev, struct dw_spi *dws)
100127

101128
init_completion(&dws->dma_completion);
102129

130+
mid_spi_maxburst_init(dws);
131+
103132
return 0;
104133
}
105134

@@ -229,7 +258,7 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws,
229258
memset(&txconf, 0, sizeof(txconf));
230259
txconf.direction = DMA_MEM_TO_DEV;
231260
txconf.dst_addr = dws->dma_addr;
232-
txconf.dst_maxburst = TX_BURST_LEVEL;
261+
txconf.dst_maxburst = dws->txburst;
233262
txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
234263
txconf.dst_addr_width = convert_dma_width(dws->n_bytes);
235264
txconf.device_fc = false;
@@ -321,7 +350,7 @@ static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws,
321350
memset(&rxconf, 0, sizeof(rxconf));
322351
rxconf.direction = DMA_DEV_TO_MEM;
323352
rxconf.src_addr = dws->dma_addr;
324-
rxconf.src_maxburst = RX_BURST_LEVEL;
353+
rxconf.src_maxburst = dws->rxburst;
325354
rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
326355
rxconf.src_addr_width = convert_dma_width(dws->n_bytes);
327356
rxconf.device_fc = false;
@@ -346,8 +375,8 @@ static int mid_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
346375
{
347376
u16 imr = 0, dma_ctrl = 0;
348377

349-
dw_writel(dws, DW_SPI_DMARDLR, RX_BURST_LEVEL - 1);
350-
dw_writel(dws, DW_SPI_DMATDLR, TX_BURST_LEVEL);
378+
dw_writel(dws, DW_SPI_DMARDLR, dws->rxburst - 1);
379+
dw_writel(dws, DW_SPI_DMATDLR, dws->fifo_len - dws->txburst);
351380

352381
if (xfer->tx_buf) {
353382
dma_ctrl |= SPI_DMA_TDMAE;

drivers/spi/spi-dw.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,9 @@ struct dw_spi {
142142

143143
/* DMA info */
144144
struct dma_chan *txchan;
145+
u32 txburst;
145146
struct dma_chan *rxchan;
147+
u32 rxburst;
146148
unsigned long dma_chan_busy;
147149
dma_addr_t dma_addr; /* phy address of the Data register */
148150
const struct dw_spi_dma_ops *dma_ops;

0 commit comments

Comments
 (0)