1532b783ce64239f0fc36e181b5498f5d8ab6d8d
[openwrt/staging/ldir.git] /
1 From 793023dc148830c18c437b58d88a118a72091038 Mon Sep 17 00:00:00 2001
2 From: Maxime Ripard <maxime@cerno.tech>
3 Date: Thu, 13 Apr 2023 16:47:10 +0200
4 Subject: [PATCH] dmaengine: bcm2835: Fix descriptors usage for 40-bits
5 channels
6
7 The bcm2835_dma_create_cb_chain() function is in charge of building up
8 the descriptors chain for a given transfer.
9
10 It was initially supporting only the BCM2835-style DMA controller, and
11 was later expanded to support controllers with 40-bits channels that use
12 a different descriptor layout.
13
14 However, some part of the function only use the old style descriptor,
15 even when building a chain of new-style descriptors, resulting in weird
16 bugs.
17
18 Fixes: 9a52a9918306 ("bcm2835-dma: Add proper 40-bit DMA support")
19 Signed-off-by: Maxime Ripard <maxime@cerno.tech>
20 ---
21 drivers/dma/bcm2835-dma.c | 69 ++++++++++++++++++++++++++++-----------
22 1 file changed, 50 insertions(+), 19 deletions(-)
23
24 --- a/drivers/dma/bcm2835-dma.c
25 +++ b/drivers/dma/bcm2835-dma.c
26 @@ -543,7 +543,10 @@ static struct bcm2835_desc *bcm2835_dma_
27 cyclic ? finalextrainfo : 0);
28
29 /* calculate new remaining length */
30 - len -= control_block->length;
31 + if (c->is_40bit_channel)
32 + len -= ((struct bcm2711_dma40_scb *)control_block)->len;
33 + else
34 + len -= control_block->length;
35 }
36
37 /* link this the last controlblock */
38 @@ -555,10 +558,19 @@ static struct bcm2835_desc *bcm2835_dma_
39 d->cb_list[frame - 1].cb->next = cb_entry->paddr;
40
41 /* update src and dst and length */
42 - if (src && (info & BCM2835_DMA_S_INC))
43 - src += control_block->length;
44 - if (dst && (info & BCM2835_DMA_D_INC))
45 - dst += control_block->length;
46 + if (src && (info & BCM2835_DMA_S_INC)) {
47 + if (c->is_40bit_channel)
48 + src += ((struct bcm2711_dma40_scb *)control_block)->len;
49 + else
50 + src += control_block->length;
51 + }
52 +
53 + if (dst && (info & BCM2835_DMA_D_INC)) {
54 + if (c->is_40bit_channel)
55 + dst += ((struct bcm2711_dma40_scb *)control_block)->len;
56 + else
57 + dst += control_block->length;
58 + }
59
60 /* Length of total transfer */
61 if (c->is_40bit_channel)
62 @@ -779,20 +791,39 @@ static size_t bcm2835_dma_desc_size_pos(
63 unsigned int i;
64 size_t size;
65
66 - for (size = i = 0; i < d->frames; i++) {
67 - struct bcm2835_dma_cb *control_block = d->cb_list[i].cb;
68 - size_t this_size = control_block->length;
69 - dma_addr_t dma;
70 -
71 - if (d->dir == DMA_DEV_TO_MEM)
72 - dma = control_block->dst;
73 - else
74 - dma = control_block->src;
75 -
76 - if (size)
77 - size += this_size;
78 - else if (addr >= dma && addr < dma + this_size)
79 - size += dma + this_size - addr;
80 + if (d->c->is_40bit_channel) {
81 + for (size = i = 0; i < d->frames; i++) {
82 + struct bcm2711_dma40_scb *control_block =
83 + (struct bcm2711_dma40_scb *)d->cb_list[i].cb;
84 + size_t this_size = control_block->len;
85 + dma_addr_t dma;
86 +
87 + if (d->dir == DMA_DEV_TO_MEM)
88 + dma = control_block->dst;
89 + else
90 + dma = control_block->src;
91 +
92 + if (size)
93 + size += this_size;
94 + else if (addr >= dma && addr < dma + this_size)
95 + size += dma + this_size - addr;
96 + }
97 + } else {
98 + for (size = i = 0; i < d->frames; i++) {
99 + struct bcm2835_dma_cb *control_block = d->cb_list[i].cb;
100 + size_t this_size = control_block->length;
101 + dma_addr_t dma;
102 +
103 + if (d->dir == DMA_DEV_TO_MEM)
104 + dma = control_block->dst;
105 + else
106 + dma = control_block->src;
107 +
108 + if (size)
109 + size += this_size;
110 + else if (addr >= dma && addr < dma + this_size)
111 + size += dma + this_size - addr;
112 + }
113 }
114
115 return size;