1 #include "u.h"
2 #include "lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7
8 /*
9 * on the 405EP the MAL is used only by the Ethernet
10 * but we keep it separate even so
11 */
12
13 enum {
14 Nrxchan= 2,
15 Ntxchan= 4,
16 Maxchan = 4
17 };
18
19 enum {
20 /* device control registers */
21 Cfg= 0x180, /* configuration register */
22 Esr= 0x181, /* error status register */
23 Ier= 0x182, /* interrupt enable register */
24 Txcasr= 0x184, /* transmit channel active set register */
25 Txcarr= 0x185, /* transmit channel active reset register */
26 Txeobisr= 0x186, /* transmit end of buffer interrupt status register */
27 Txdeir= 0x187, /* transmit descriptor error interrupt register */
28 Rxcasr= 0x190, /* receive channel active set register */
29 Rxcarr= 0x191, /* receive channel active reset register */
30 Rxeobisr= 0x192, /* receive channel descriptor error interrupt register */
31 Rxdeir= 0x193, /* receive descriptor error interrupt register */
32 };
33
34 #define TXCTPR(n) (0x1A0+(n)) /* transmit channel table pointer register */
35 #define RXCTPR(n) (0x1C0+(n)) /* receive channel table pointer register */
36 #define RCBS(n) (0x1E0+(n)) /* receive channel buffer size register */
37
38 enum {
39 /* configuration */
40 CfgSr= 1<<31, /* software reset */
41 CfgPlbp0= 0<<22, /* PLB priority (0=lowest) */
42 CfgPlbp1= 1<<22,
43 CfgPlbp2= 2<<22,
44 CfgPlbp3= 3<<22,
45 CfgGa= 1<<21, /* guarded */
46 CfgOa= 1<<20, /* ordered */
47 CfgPlble= 1<<19, /* lock error */
48 CfgPlbt_f= 0xF<<15, /* latency timer field */
49 CfgPlbt_s= 15, /* latency timer (shift) */
50 CfgPlbb= 1<<14, /* burst enable */
51 CfgOpbbl= 1<<7, /* OPB locked */
52 CfgOepie= 1<<2, /* interrupt on every end of packet */
53 CfgLea= 1<<1, /* locked error active */
54 CfgSd= 1<<0, /* scroll to next packet on early termination */
55
56 /* error status */
57 EsrEvb= 1<<31, /* error valid bit */
58 EsrCid_f= 0x7F<<25, /* field: channel ID causing lock error */
59 EsrDe= 1<<20, /* descriptor error */
60 EsrOne= 1<<19, /* OPB non-fullword error */
61 EsrOte= 1<<18, /* OPB timeout error */
62 EsrOse= 1<<17, /* OPB slave error */
63 EsrPein= 1<<16, /* PLB bus error indication */
64 EsrDei= 1<<4, /* descriptor error interrupt */
65 EsrOnei= 1<<3, /* OPB non-fulword error interrupt */
66 EsrOtei= 1<<2, /* OPB timeout error interrupt */
67 EsrOsei= 1<<1, /* OPB slave error interrupt */
68 EsrPbei= 1<<0, /* OPB bus error interrupt */
69
70 };
71
72 typedef struct Malmem Malmem;
73 struct Malmem {
74 Lock;
75 BD* base;
76 BD* limit;
77 BD* avail;
78 };
79
80 static Malmem malmem;
81
82 static Mal* malchans[2][Maxchan];
83
84 static void
errorintr(Ureg *,void *)85 errorintr(Ureg*, void*)
86 {
87 ulong esr, rxdeir, txdeir;
88
89 /* mal de tête */
90 esr = getdcr(Esr);
91 txdeir = getdcr(Txdeir);
92 rxdeir = getdcr(Rxdeir);
93 iprint("mal: esr=%8.8lux txdeir=%8.8lux rxdeir=%8.8lux\n", esr, txdeir, rxdeir);
94 putdcr(Rxdeir, rxdeir);
95 putdcr(Txdeir, txdeir);
96 putdcr(Esr, esr);
97 }
98
99 static void
scanintr(Ureg * ur,ulong ir,Mal * chans[])100 scanintr(Ureg *ur, ulong ir, Mal *chans[])
101 {
102 Mal *ml;
103 int i;
104
105 for(i=0; ir != 0 && i < Maxchan; i++)
106 if(ir & IBIT(i)){
107 ir &= ~IBIT(i);
108 ml = chans[i];
109 if(ml != nil && ml->interrupt != nil)
110 ml->interrupt(ur, ml->arg);
111 /* unexpected interrupt otherwise */
112 }
113 }
114
115 static void
txinterrupt(Ureg * ur,void *)116 txinterrupt(Ureg *ur, void*)
117 {
118 ulong ir;
119
120 ir = getdcr(Txeobisr);
121 putdcr(Txeobisr, ir);
122 scanintr(ur, ir, malchans[1]);
123 }
124
125 static void
rxinterrupt(Ureg * ur,void *)126 rxinterrupt(Ureg *ur, void*)
127 {
128 ulong ir;
129
130 ir = getdcr(Rxeobisr);
131 putdcr(Rxeobisr, ir);
132 scanintr(ur, ir, malchans[0]);
133 }
134
135 void
ioinit(void)136 ioinit(void)
137 {
138 int i;
139
140 putdcr(Txcarr, ~0);
141 putdcr(Rxcarr, ~0);
142
143 /* reset */
144 putdcr(Cfg, CfgSr);
145 while(getdcr(Cfg) & CfgSr)
146 ; /* at most one system clock */
147
148 /* clear these out whilst we're at it */
149 for(i=0; i<Nrxchan; i++){
150 putdcr(RCBS(i), 0);
151 putdcr(RXCTPR(i), 0);
152 }
153 for(i=0; i<Ntxchan; i++)
154 putdcr(TXCTPR(i), 0);
155
156 putdcr(Cfg, (0xF<<CfgPlbt_s)|CfgPlbb); /* TO DO: check */
157
158 /* Ier */
159 intrenable(VectorMALSERR, errorintr, nil, BUSUNKNOWN, "malserr");
160 intrenable(VectorMALTXDE, errorintr, nil, BUSUNKNOWN, "maltxde");
161 intrenable(VectorMALRXDE, errorintr, nil, BUSUNKNOWN, "malrxde");
162 intrenable(VectorMALTXEOB, txinterrupt, nil, BUSUNKNOWN, "maltxeob");
163 intrenable(VectorMALRXEOB, rxinterrupt, nil, BUSUNKNOWN, "malrxeob");
164 putdcr(Ier, EsrDei | EsrOnei | EsrOtei | EsrOsei | EsrPbei);
165 }
166
167 Mal*
malchannel(int n,int tx,void (* intr)(Ureg *,void *),void * arg)168 malchannel(int n, int tx, void (*intr)(Ureg*, void*), void *arg)
169 {
170 Mal *ml;
171
172 if((ml = malchans[tx][n]) == nil){
173 ml = malloc(sizeof(*m));
174 malchans[tx][n] = ml;
175 }
176 ml->n = n;
177 ml->tx = tx;
178 ml->len = 1;
179 ml->arg = arg;
180 ml->interrupt = intr;
181 return ml;
182 }
183
184 void
maltxreset(Mal * ml)185 maltxreset(Mal *ml)
186 {
187 putdcr(Txcarr, IBIT(ml->n));
188 }
189
190 void
maltxinit(Mal * ml,Ring * r)191 maltxinit(Mal *ml, Ring *r)
192 {
193 putdcr(TXCTPR(ml->n), PADDR(r->tdr));
194 }
195
196 void
maltxenable(Mal * ml)197 maltxenable(Mal *ml)
198 {
199 putdcr(Txcasr, getdcr(Txcasr) | IBIT(ml->n));
200 }
201
202 void
malrxreset(Mal * ml)203 malrxreset(Mal *ml)
204 {
205 putdcr(Rxcarr, IBIT(ml->n));
206 }
207
208 void
malrxinit(Mal * ml,Ring * r,ulong limit)209 malrxinit(Mal *ml, Ring *r, ulong limit)
210 {
211 putdcr(RXCTPR(ml->n), PADDR(r->rdr));
212 putdcr(RCBS(ml->n), limit);
213 }
214
215 void
malrxenable(Mal * ml)216 malrxenable(Mal *ml)
217 {
218 putdcr(Rxcasr, getdcr(Rxcasr) | IBIT(ml->n));
219 }
220
221 /*
222 * initialise receive and transmit buffer rings
223 * to use both Emacs, or two channels per emac, we'll need
224 * to allocate all rx descriptors at once, and all tx descriptors at once,
225 * in a region where all addresses have the same bits 0-12(!);
226 * see p 20-34. of the MAL chapter.
227 *
228 * the ring entries must be aligned on sizeof(BD) boundaries
229 * rings must be uncached, and buffers must align with cache lines since the cache doesn't snoop
230 *
231 * thus, we initialise it once for all, then hand it out as requested.
232 */
233 void
ioringreserve(int nrx,ulong nrb,int ntx,ulong ntb)234 ioringreserve(int nrx, ulong nrb, int ntx, ulong ntb)
235 {
236 ulong nb, nbd;
237
238 lock(&malmem);
239 if(malmem.base == nil){
240 nbd = nrx*nrb + ntx*ntb;
241 nb = mmumapsize(nbd*sizeof(BD));
242 /*
243 * the data sheet says in the description of buffer tables that they must be on a 4k boundary,
244 * but the pointer register descriptions say 8 bytes; it seems to be the latter.
245 */
246 malmem.base = mmucacheinhib(xspanalloc(nb, nb, 1<<19), nb);
247 malmem.limit = malmem.base + nbd;
248 malmem.avail = malmem.base;
249 if((PADDR(malmem.base)&~0x7FFFF) != (PADDR(malmem.base)&~0x7FFFF))
250 print("mal: trouble ahead?\n");
251 }
252 unlock(&malmem);
253 if(malmem.base == nil)
254 panic("ioringreserve");
255 }
256
257 BD*
bdalloc(ulong nd)258 bdalloc(ulong nd)
259 {
260 BD *b;
261
262 lock(&malmem);
263 b = malmem.avail;
264 if(b+nd > malmem.limit)
265 b = nil;
266 else
267 malmem.avail = b+nd;
268 unlock(&malmem);
269 return b;
270 }
271
272 int
ioringinit(Ring * r,int nrdre,int ntdre)273 ioringinit(Ring* r, int nrdre, int ntdre)
274 {
275 int i;
276
277 /* buffers must align with cache lines since the cache doesn't snoop */
278 r->nrdre = nrdre;
279 if(r->rdr == nil)
280 r->rdr = bdalloc(nrdre);
281 if(r->rxb == nil)
282 r->rxb = malloc(nrdre*sizeof(Block*));
283 if(r->rdr == nil || r->rxb == nil)
284 return -1;
285 for(i = 0; i < nrdre; i++){
286 r->rxb[i] = nil;
287 r->rdr[i].length = 0;
288 r->rdr[i].addr = 0;
289 r->rdr[i].status = BDEmpty|BDInt;
290 }
291 r->rdr[i-1].status |= BDWrap;
292 r->rdrx = 0;
293
294 r->ntdre = ntdre;
295 if(r->tdr == nil)
296 r->tdr = bdalloc(ntdre);
297 if(r->txb == nil)
298 r->txb = malloc(ntdre*sizeof(Block*));
299 if(r->tdr == nil || r->txb == nil)
300 return -1;
301 for(i = 0; i < ntdre; i++){
302 r->txb[i] = nil;
303 r->tdr[i].addr = 0;
304 r->tdr[i].length = 0;
305 r->tdr[i].status = 0;
306 }
307 r->tdr[i-1].status |= BDWrap;
308 r->tdrh = 0;
309 r->tdri = 0;
310 r->ntq = 0;
311 return 0;
312 }
313
314 void
dumpmal(void)315 dumpmal(void)
316 {
317 int i;
318
319 iprint("Cfg=%8.8lux\n", getdcr(Cfg));
320 iprint("Esr=%8.8lux\n", getdcr(Esr));
321 iprint("Ier=%8.8lux\n", getdcr(Ier));
322 iprint("Txcasr=%8.8lux\n", getdcr(Txcasr));
323 iprint("Txcarr=%8.8lux\n", getdcr(Txcarr));
324 iprint("Txeobisr=%8.8lux\n", getdcr(Txeobisr));
325 iprint("Txdeir=%8.8lux\n", getdcr(Txdeir));
326 iprint("Rxcasr=%8.8lux\n", getdcr(Rxcasr));
327 iprint("Rxcarr=%8.8lux\n", getdcr(Rxcarr));
328 iprint("Rxeobisr=%8.8lux\n", getdcr(Rxeobisr));
329 iprint("Rxdeir=%8.8lux\n", getdcr(Rxdeir));
330 for(i=0; i<Nrxchan; i++)
331 iprint("Rxctpr[%d]=%8.8lux Rcbs[%d]=%8.8lux\n", i, getdcr(RXCTPR(i)), i, getdcr(RCBS(i)));
332 for(i=0;i<Ntxchan; i++)
333 iprint("Txctpr[%d]=%8.8lux\n", i, getdcr(TXCTPR(i)));
334 }
335