Skip to content

Commit a94a098

Browse files
smaeulvinodkoul
authored andcommitted
dmaengine: sun4i: Set the maximum segment size
The sun4i DMA engine supports transfer sizes up to 128k for normal DMA and 16M for dedicated DMA, as documented in the A10 and A20 manuals. Since this is larger than the default segment size limit (64k), exposing the real limit reduces the number of transfers needed for a transaction. However, because the device can only report one segment size limit, we have to expose the smaller limit from normal DMA. One complication is that the driver combines pairs of periodic transfers to reduce programming overhead. This only works when the period size is at most half of the maximum transfer size. With the default 64k segment size limit, this was always the case, but for normal DMA it is no longer guaranteed. Skip the optimization if the period is too long; even without it, the overhead is less than before. Signed-off-by: Samuel Holland <samuel@sholland.org> Link: https://lore.kernel.org/r/20220621031350.36187-1-samuel@sholland.org Signed-off-by: Vinod Koul <vkoul@kernel.org>
1 parent 9bef492 commit a94a098

1 file changed

Lines changed: 27 additions & 5 deletions

File tree

drivers/dma/sun4i-dma.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/bitmap.h>
88
#include <linux/bitops.h>
99
#include <linux/clk.h>
10+
#include <linux/dma-mapping.h>
1011
#include <linux/dmaengine.h>
1112
#include <linux/dmapool.h>
1213
#include <linux/interrupt.h>
@@ -122,6 +123,15 @@
122123
SUN4I_DDMA_PARA_DST_WAIT_CYCLES(2) | \
123124
SUN4I_DDMA_PARA_SRC_WAIT_CYCLES(2))
124125

126+
/*
127+
* Normal DMA supports individual transfers (segments) up to 128k.
128+
* Dedicated DMA supports transfers up to 16M. We can only report
129+
* one size limit, so we have to use the smaller value.
130+
*/
131+
#define SUN4I_NDMA_MAX_SEG_SIZE SZ_128K
132+
#define SUN4I_DDMA_MAX_SEG_SIZE SZ_16M
133+
#define SUN4I_DMA_MAX_SEG_SIZE SUN4I_NDMA_MAX_SEG_SIZE
134+
125135
struct sun4i_dma_pchan {
126136
/* Register base of channel */
127137
void __iomem *base;
@@ -155,7 +165,8 @@ struct sun4i_dma_contract {
155165
struct virt_dma_desc vd;
156166
struct list_head demands;
157167
struct list_head completed_demands;
158-
int is_cyclic;
168+
bool is_cyclic : 1;
169+
bool use_half_int : 1;
159170
};
160171

161172
struct sun4i_dma_dev {
@@ -372,7 +383,7 @@ static int __execute_vchan_pending(struct sun4i_dma_dev *priv,
372383
if (promise) {
373384
vchan->contract = contract;
374385
vchan->pchan = pchan;
375-
set_pchan_interrupt(priv, pchan, contract->is_cyclic, 1);
386+
set_pchan_interrupt(priv, pchan, contract->use_half_int, 1);
376387
configure_pchan(pchan, promise);
377388
}
378389

@@ -735,12 +746,21 @@ sun4i_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf, size_t len,
735746
*
736747
* Which requires half the engine programming for the same
737748
* functionality.
749+
*
750+
* This only works if two periods fit in a single promise. That will
751+
* always be the case for dedicated DMA, where the hardware has a much
752+
* larger maximum transfer size than advertised to clients.
738753
*/
739-
nr_periods = DIV_ROUND_UP(len / period_len, 2);
754+
if (vchan->is_dedicated || period_len <= SUN4I_NDMA_MAX_SEG_SIZE / 2) {
755+
period_len *= 2;
756+
contract->use_half_int = 1;
757+
}
758+
759+
nr_periods = DIV_ROUND_UP(len, period_len);
740760
for (i = 0; i < nr_periods; i++) {
741761
/* Calculate the offset in the buffer and the length needed */
742-
offset = i * period_len * 2;
743-
plength = min((len - offset), (period_len * 2));
762+
offset = i * period_len;
763+
plength = min((len - offset), period_len);
744764
if (dir == DMA_MEM_TO_DEV)
745765
src = buf + offset;
746766
else
@@ -1149,6 +1169,8 @@ static int sun4i_dma_probe(struct platform_device *pdev)
11491169
platform_set_drvdata(pdev, priv);
11501170
spin_lock_init(&priv->lock);
11511171

1172+
dma_set_max_seg_size(&pdev->dev, SUN4I_DMA_MAX_SEG_SIZE);
1173+
11521174
dma_cap_zero(priv->slave.cap_mask);
11531175
dma_cap_set(DMA_PRIVATE, priv->slave.cap_mask);
11541176
dma_cap_set(DMA_MEMCPY, priv->slave.cap_mask);

0 commit comments

Comments
 (0)