xref: /inferno-os/os/cerf405/mal.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
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