1 From ce56098eb4dc2985f27f30ad7b7f5aed6bcf7fb1 Mon Sep 17 00:00:00 2001
2 From: Jonathan Bell <jonathan@raspberrypi.com>
3 Date: Fri, 19 Jul 2024 15:55:56 +0100
4 Subject: [PATCH 1193/1215] drivers: dw-axi-dmac: make more sensible choices
7 There's no real need to constrain MEM access widths to 32-bit (or
8 narrower), as the DMAC is intelligent enough to size memory accesses
9 appropriately. Wider accesses are more efficient.
11 Similarly, MEM burst lengths don't need to be a function of DEV burst
12 lengths - the DMAC packs/unpacks data into/from its internal channel
13 FIFOs appropriately. Longer accesses are more efficient.
15 However, the DMAC doesn't have complete support for unaligned accesses,
16 and blocks are always defined in integer multiples of SRC_WIDTH, so odd
17 source lengths or buffer alignments will prevent wide accesses being
20 There is an implicit requirement to limit requested DEV read burst
21 lengths to less than the hardware's maximum configured MSIZE - otherwise
22 RX data will be left over at the end of a block. There is no config
23 register that reports this value, so the AXI burst length parameter is
24 used to produce a facsimile of it. Warn if such a request arrives that
27 Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
29 .../dma/dw-axi-dmac/dw-axi-dmac-platform.c | 38 ++++++++++++-------
30 1 file changed, 25 insertions(+), 13 deletions(-)
32 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
33 +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
34 @@ -261,6 +261,15 @@ static u32 axi_chan_get_xfer_width(struc
35 return __ffs(src | dst | len | BIT(max_width));
38 +static u32 axi_dma_encode_msize(u32 max_burst)
41 + return DWAXIDMAC_BURST_TRANS_LEN_1;
42 + if (max_burst > 1024)
43 + return DWAXIDMAC_BURST_TRANS_LEN_1024;
44 + return fls(max_burst) - 2;
47 static inline const char *axi_chan_name(struct axi_dma_chan *chan)
49 return dma_chan_name(&chan->vc.chan);
50 @@ -685,41 +694,41 @@ static int dw_axi_dma_set_hw_desc(struct
55 + u32 burst_len = 0, mem_burst_msize, reg_burst_msize;
57 axi_block_ts = chan->chip->dw->hdata->block_size[chan->id];
59 mem_width = __ffs(data_width | mem_addr | len);
60 - if (mem_width > DWAXIDMAC_TRANS_WIDTH_32)
61 - mem_width = DWAXIDMAC_TRANS_WIDTH_32;
63 if (!IS_ALIGNED(mem_addr, 4)) {
64 dev_err(chan->chip->dev, "invalid buffer alignment\n");
68 + /* Use a reasonable upper limit otherwise residue reporting granularity grows large */
69 + mem_burst_msize = axi_dma_encode_msize(16);
71 switch (chan->direction) {
73 + reg_burst_msize = axi_dma_encode_msize(chan->config.dst_maxburst);
74 reg_width = __ffs(chan->config.dst_addr_width);
75 device_addr = phys_to_dma(chan->chip->dev, chan->config.dst_addr);
76 ctllo = reg_width << CH_CTL_L_DST_WIDTH_POS |
77 mem_width << CH_CTL_L_SRC_WIDTH_POS |
78 - DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_DST_MSIZE_POS |
79 - DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_SRC_MSIZE_POS |
80 + reg_burst_msize << CH_CTL_L_DST_MSIZE_POS |
81 + mem_burst_msize << CH_CTL_L_SRC_MSIZE_POS |
82 DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_DST_INC_POS |
83 DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_SRC_INC_POS;
84 block_ts = len >> mem_width;
87 + reg_burst_msize = axi_dma_encode_msize(chan->config.src_maxburst);
88 reg_width = __ffs(chan->config.src_addr_width);
89 - /* Prevent partial access units getting lost */
90 - if (mem_width > reg_width)
91 - mem_width = reg_width;
92 device_addr = phys_to_dma(chan->chip->dev, chan->config.src_addr);
93 ctllo = reg_width << CH_CTL_L_SRC_WIDTH_POS |
94 mem_width << CH_CTL_L_DST_WIDTH_POS |
95 - DWAXIDMAC_BURST_TRANS_LEN_4 << CH_CTL_L_DST_MSIZE_POS |
96 - DWAXIDMAC_BURST_TRANS_LEN_1 << CH_CTL_L_SRC_MSIZE_POS |
97 + mem_burst_msize << CH_CTL_L_DST_MSIZE_POS |
98 + reg_burst_msize << CH_CTL_L_SRC_MSIZE_POS |
99 DWAXIDMAC_CH_CTL_L_INC << CH_CTL_L_DST_INC_POS |
100 DWAXIDMAC_CH_CTL_L_NOINC << CH_CTL_L_SRC_INC_POS;
101 block_ts = len >> reg_width;
102 @@ -760,6 +769,12 @@ static int dw_axi_dma_set_hw_desc(struct
103 set_desc_src_master(hw_desc);
107 + if (burst_len && (chan->config.src_maxburst > burst_len))
108 + dev_warn_ratelimited(chan2dev(chan),
109 + "%s: requested source burst length %u exceeds supported burst length %u - data may be lost\n",
110 + axi_chan_name(chan), chan->config.src_maxburst, burst_len);
115 @@ -776,9 +791,6 @@ static size_t calculate_block_len(struct
117 data_width = BIT(chan->chip->dw->hdata->m_data_width);
118 mem_width = __ffs(data_width | dma_addr | buf_len);
119 - if (mem_width > DWAXIDMAC_TRANS_WIDTH_32)
120 - mem_width = DWAXIDMAC_TRANS_WIDTH_32;
122 block_len = axi_block_ts << mem_width;