changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/9/bcm/dma.c

changeset 7249: 3d3af63a444a
parent: bee572b18071
child: 55d93e47a2de
author: cinap_lenrek@felloff.net
date: Sun, 19 May 2019 16:54:50 +0200
permissions: -rw-r--r--
description: bcm, bcm64: fix cache operations for dma and emmc

always clean AND invalidate caches before dma read,
never just invalidate as the buffer might not be
aligned to cache lines...

we have to invalidate caches again *AFTER* the dma
read has completed. the processor can bring in data
speculatively into the cache while the dma in in
flight.
1 /*
2  * bcm2835 dma controller
3  *
4  * simplest to use only channels 0-6
5  * channels 7-14 have reduced functionality
6  * channel 15 is at a weird address
7  * channels 0 and 15 have an "external 128 bit 8 word read FIFO"
8  * for memory to memory transfers
9  *
10  * Experiments show that only channels 2-5,11-12 work with mmc
11  */
12 
13 #include "u.h"
14 #include "../port/lib.h"
15 #include "../port/error.h"
16 #include "mem.h"
17 #include "dat.h"
18 #include "fns.h"
19 #include "io.h"
20 
21 #define DMAREGS (VIRTIO+0x7000)
22 
23 #define DBG if(Dbg)
24 
25 enum {
26  Nchan = 7, /* number of dma channels */
27  Regsize = 0x100, /* size of regs for each chan */
28  Cbalign = 64, /* control block byte alignment (allow for 64-byte cache on bcm2836) */
29  Dbg = 0,
30 
31  /* registers for each dma controller */
32  Cs = 0x00>>2,
33  Conblkad = 0x04>>2,
34  Ti = 0x08>>2,
35  Sourcead = 0x0c>>2,
36  Destad = 0x10>>2,
37  Txfrlen = 0x14>>2,
38  Stride = 0x18>>2,
39  Nextconbk = 0x1c>>2,
40  Debug = 0x20>>2,
41 
42  /* collective registers */
43  Intstatus = 0xfe0>>2,
44  Enable = 0xff0>>2,
45 
46  /* Cs */
47  Reset = 1<<31,
48  Abort = 1<<30,
49  Error = 1<<8,
50  Waitwrite = 1<<6,
51  Waitdreq = 1<<5,
52  Paused = 1<<4,
53  Dreq = 1<<3,
54  Int = 1<<2,
55  End = 1<<1,
56  Active = 1<<0,
57 
58  /* Ti */
59  Permapshift= 16,
60  Srcignore = 1<<11,
61  Srcdreq = 1<<10,
62  Srcwidth128 = 1<<9,
63  Srcinc = 1<<8,
64  Destignore = 1<<7,
65  Destdreq = 1<<6,
66  Destwidth128 = 1<<5,
67  Destinc = 1<<4,
68  Waitresp = 1<<3,
69  Tdmode = 1<<1,
70  Inten = 1<<0,
71 
72  /* Debug */
73  Lite = 1<<28,
74  Clrerrors = 7<<0,
75 };
76 
77 typedef struct Ctlr Ctlr;
78 typedef struct Cb Cb;
79 
80 struct Ctlr {
81  u32int *regs;
82  Cb *cb;
83  Rendez r;
84  int dmadone;
85 };
86 
87 struct Cb {
88  u32int ti;
89  u32int sourcead;
90  u32int destad;
91  u32int txfrlen;
92  u32int stride;
93  u32int nextconbk;
94  u32int reserved[2];
95 };
96 
97 static Ctlr dma[Nchan];
98 static u32int *dmaregs = (u32int*)DMAREGS;
99 
100 uintptr
101 dmaaddr(void *va)
102 {
103  if(va == nil)
104  return soc.busdram;
105  return soc.busdram | (PADDR(va) - PHYSDRAM);
106 }
107 
108 static uintptr
109 dmaioaddr(void *va)
110 {
111  return soc.busio | ((uintptr)va - VIRTIO);
112 }
113 
114 static void
115 dump(char *msg, uchar *p, int n)
116 {
117  print("%s", msg);
118  while(n-- > 0)
119  print(" %2.2x", *p++);
120  print("\n");
121 }
122 
123 static void
124 dumpdregs(char *msg, u32int *r)
125 {
126  int i;
127 
128  print("%s: %#p =", msg, r);
129  for(i = 0; i < 9; i++)
130  print(" %8.8uX", r[i]);
131  print("\n");
132 }
133 
134 static int
135 dmadone(void *a)
136 {
137  return ((Ctlr*)a)->dmadone;
138 }
139 
140 static void
141 dmainterrupt(Ureg*, void *a)
142 {
143  Ctlr *ctlr;
144 
145  ctlr = a;
146  ctlr->regs[Cs] = Int;
147  ctlr->dmadone = 1;
148  wakeup(&ctlr->r);
149 }
150 
151 void
152 dmastart(int chan, int dev, int dir, void *src, void *dst, int len)
153 {
154  Ctlr *ctlr;
155  Cb *cb;
156  int ti;
157 
158  ctlr = &dma[chan];
159  if(ctlr->regs == nil){
160  ctlr->regs = (u32int*)(DMAREGS + chan*Regsize);
161  ctlr->cb = xspanalloc(sizeof(Cb), Cbalign, 0);
162  assert(ctlr->cb != nil);
163  dmaregs[Enable] |= 1<<chan;
164  ctlr->regs[Cs] = Reset;
165  while(ctlr->regs[Cs] & Reset)
166  ;
167  intrenable(IRQDMA(chan), dmainterrupt, ctlr, 0, "dma");
168  }
169  cb = ctlr->cb;
170  ti = 0;
171  switch(dir){
172  case DmaD2M:
173  cachedwbinvse(dst, len);
174  ti = Srcdreq | Destinc;
175  cb->sourcead = dmaioaddr(src);
176  cb->destad = dmaaddr(dst);
177  break;
178  case DmaM2D:
179  cachedwbse(src, len);
180  ti = Destdreq | Srcinc;
181  cb->sourcead = dmaaddr(src);
182  cb->destad = dmaioaddr(dst);
183  break;
184  case DmaM2M:
185  cachedwbse(src, len);
186  cachedwbinvse(dst, len);
187  ti = Srcinc | Destinc;
188  cb->sourcead = dmaaddr(src);
189  cb->destad = dmaaddr(dst);
190  break;
191  }
192  cb->ti = ti | dev<<Permapshift | Inten;
193  cb->txfrlen = len;
194  cb->stride = 0;
195  cb->nextconbk = 0;
196  cachedwbse(cb, sizeof(Cb));
197  ctlr->regs[Cs] = 0;
198  microdelay(1);
199  ctlr->regs[Conblkad] = dmaaddr(cb);
200  DBG print("dma start: %ux %ux %ux %ux %ux %ux\n",
201  cb->ti, cb->sourcead, cb->destad, cb->txfrlen,
202  cb->stride, cb->nextconbk);
203  DBG print("intstatus %ux\n", dmaregs[Intstatus]);
204  dmaregs[Intstatus] = 0;
205  ctlr->regs[Cs] = Int;
206  microdelay(1);
207  coherence();
208  DBG dumpdregs("before Active", ctlr->regs);
209  ctlr->regs[Cs] = Active;
210  DBG dumpdregs("after Active", ctlr->regs);
211 }
212 
213 int
214 dmawait(int chan)
215 {
216  Ctlr *ctlr;
217  u32int *r;
218  int s;
219 
220  ctlr = &dma[chan];
221  tsleep(&ctlr->r, dmadone, ctlr, 3000);
222  ctlr->dmadone = 0;
223  r = ctlr->regs;
224  DBG dumpdregs("after sleep", r);
225  s = r[Cs];
226  if((s & (Active|End|Error)) != End){
227  print("dma chan %d %s Cs %ux Debug %ux\n", chan,
228  (s&End)? "error" : "timeout", s, r[Debug]);
229  r[Cs] = Reset;
230  r[Debug] = Clrerrors;
231  return -1;
232  }
233  r[Cs] = Int|End;
234  return 0;
235 }