xref: /plan9-contrib/sys/src/9/bcm/ethergenet.c (revision 5c47fe09a0cc86dfb02c0ea4a2b6aec7eda2361f)
1 /*
2  * Broadcom 2711 native gigabit ethernet
3  *
4  *	from 9front
5  */
6 
7 #include "u.h"
8 #include "../port/lib.h"
9 #include "mem.h"
10 #include "dat.h"
11 #include "fns.h"
12 #include "io.h"
13 #include "../port/netif.h"
14 #include "etherif.h"
15 #include "ethermii.h"
16 
17 #define	MIIDBG	if(0)print
18 
19 enum
20 {
21 	Rbsz		= 10240,
22 	Maxtu		= 9014,
23 
24 	DmaOWN		= 0x8000,
25 	DmaSOP		= 0x2000,
26 	DmaEOP		= 0x4000,
27 	DmaRxLg		= 0x10,
28 	DmaRxNo		= 0x08,
29 	DmaRxErr	= 0x04,
30 	DmaRxCrc	= 0x02,
31 	DmaRxOv		= 0x01,
32 	DmaRxErrors	= DmaRxLg|DmaRxNo|DmaRxErr|DmaRxCrc|DmaRxOv,
33 
34 	DmaTxQtag	= 0x1F80,
35 	DmaTxUnderrun	= 0x0200,
36 	DmaTxAppendCrc	= 0x0040,
37 	DmaTxOwCrc	= 0x0020,
38 	DmaTxDoCsum	= 0x0010,
39 
40 	/* Ctlr->regs */
41 	SysRevision	= 0x00/4,
42 	SysPortCtrl	= 0x04/4,
43 		PortModeIntEphy	= 0,
44 		PortModeIntGphy = 1,
45 		PortModeExtEphy = 2,
46 		PortModeExtGphy = 3,
47 		PortModeExtRvmii50 = 4,
48 		PortModeExtRvmii25 = 16 | 4,
49 		LedActSourceMac = 1 << 9,
50 
51 	SysRbufFlushCtrl	= 0x08/4,
52 	SysTbufFlushCtrl	= 0x0C/4,
53 
54 	ExtRgmiiOobCtrl	= 0x8C/4,
55 		RgmiiLink	= 1 << 4,
56 		OobDisable	= 1 << 5,
57 		RgmiiModeEn	= 1 << 6,
58 		IdModeDis	= 1 << 16,
59 
60 	Intrl0		= 0x200/4,
61 		IrqScb		= 1 << 0,
62 		IrqEphy		= 1 << 1,
63 		IrqPhyDetR	= 1 << 2,
64 		IrqPhyDetF	= 1 << 3,
65 		IrqLinkUp	= 1 << 4,
66 		IrqLinkDown	= 1 << 5,
67 		IrqUmac		= 1 << 6,
68 		IrqUmacTsv	= 1 << 7,
69 		IrqTbufUnderrun	= 1 << 8,
70 		IrqRbufOverflow	= 1 << 9,
71 		IrqHfbSm	= 1 << 10,
72 		IrqHfbMm	= 1 << 11,
73 		IrqMpdR		= 1 << 12,
74 		IrqRxDmaDone	= 1 << 13,
75 		IrqRxDmaPDone	= 1 << 14,
76 		IrqRxDmaBDone	= 1 << 15,
77 		IrqTxDmaDone	= 1 << 16,
78 		IrqTxDmaPDone	= 1 << 17,
79 		IrqTxDmaBDone	= 1 << 18,
80 		IrqMdioDone	= 1 << 23,
81 		IrqMdioError	= 1 << 24,
82 	Intrl1		= 0x240/4,
83 		/* Intrl0/1 + ... */
84 		IntrSts		= 0x00/4,
85 		IntrSet		= 0x04/4,
86 		IntrClr		= 0x08/4,
87 		IntrMaskSts	= 0x0C/4,
88 		IntrMaskSet	= 0x10/4,
89 		IntrMaskClr	= 0x14/4,
90 
91 	RbufCtrl	= 0x300/4,
92 		Rbuf64En	= 1 << 0,
93 		RbufAlign2B	= 1 << 1,
94 		RbufBadDis	= 1 << 2,
95 
96 	RbufChkCtrl	= 0x314/4,
97 		RbufChkRxChkEn	= 1 << 0,
98 		RbufChkSkipFcs	= 1 << 4,
99 
100 	RbufOvflCnt	= 0x394/4,
101 	RbufErrCnt	= 0x398/4,
102 
103 	RbufEnergyCtrl	= 0x39c/4,
104 		RbufEeeEn	= 1 << 0,
105 		RbufPmEn	= 1 << 1,
106 
107 	RbufTbufSizeCtrl= 0x3b4/4,
108 
109 	TbufCtrl	= 0x600/4,
110 	TbufBpMc	= 0x60C/4,
111 	TbufEnergyCtrl	= 0x614/4,
112 
113 	UmacCmd		= 0x808/4,
114 		CmdTxEn		= 1 << 0,
115 		CmdRxEn		= 1 << 1,
116 		CmdSpeed10	= 0 << 2,
117 		CmdSpeed100	= 1 << 2,
118 		CmdSpeed1000	= 2 << 2,
119 		CmdSpeedMask	= 3 << 2,
120 		CmdProm		= 1 << 4,
121 		CmdPadEn	= 1 << 5,
122 		CmdCrcFwd	= 1 << 6,
123 		CmdPauseFwd	= 1 << 7,
124 		CmdRxPauseIgn	= 1 << 8,
125 		CmdTxAddrIn	= 1 << 9,
126 		CmdHdEn		= 1 << 10,
127 		CmdSwReset	= 1 << 13,
128 		CmdLclLoopEn	= 1 << 15,
129 		CmdAutoConfig	= 1 << 22,
130 		CmdCntlFrmEn	= 1 << 23,
131 		CmdNoLenChk	= 1 << 24,
132 		CmdRmtLoopEn	= 1 << 25,
133 		CmdPrblEn	= 1 << 27,
134 		CmdTxPauseIgn	= 1 << 28,
135 		CmdTxRxEn	= 1 << 29,
136 		CmdRuntFilterDis= 1 << 30,
137 
138 	UmacMac0	= 0x80C/4,
139 	UmacMac1	= 0x810/4,
140 	UmacMaxFrameLen	= 0x814/4,
141 
142 	UmacEeeCtrl	= 0x864/4,
143 		UmacEeeEn	= 1<<3,
144 
145 	UmacEeeLpiTimer	= 0x868/4,
146 	UmacEeeWakeTimer= 0x86C/4,
147 	UmacEeeRefCount	= 0x870/4,
148 		EeeRefCountMask = 0xFFFF,
149 
150 	UmacTxFlush	= 0xb34/4,
151 
152 	UmacMibCtrl	= 0xd80/4,
153 		MibResetRx	= 1 << 0,
154 		MibResetRunt	= 1 << 1,
155 		MibResetTx	= 1 << 2,
156 
157 	MdioCmd		= 0xe14/4,
158 		MdioStartBusy	= 1 << 29,
159 		MdioReadFail	= 1 << 28,
160 		MdioRead	= 2 << 26,
161 		MdioWrite	= 1 << 26,
162 		MdioPhyShift	= 21,
163 		MdioPhyMask	= 0x1F,
164 		MdioAddrShift	= 16,
165 		MdioAddrMask	= 0x1F,
166 
167 	UmacMpdCtrl	= 0xe20/4,
168 		MpdEn	= 1 << 0,
169 		MpdPwEn	= 1 << 27,
170 
171 	UmacMdfCtrl	= 0xe50/4,
172 	UmacMdfAddr0	= 0xe54/4,
173 
174 	RdmaOffset	= 0x2000/4,
175 	TdmaOffset	= 0x4000/4,
176 	HfbOffset	= 0x8000/4,
177 
178 	HfbCtlr		= 0xFC00/4,
179 	HfbFltEnable	= 0xFC04/4,
180 	HfbFltLen	= 0xFC1C/4,
181 
182 	/* common Ring->regs */
183 	RdmaWP		= 0x00/4,
184 	TdmaRP		= 0x00/4,
185 	RxWP		= 0x08/4,
186 	TxRP		= 0x08/4,
187 	TxWP		= 0x0C/4,
188 	RxRP		= 0x0C/4,
189 	DmaRingBufSize	= 0x10/4,
190 	DmaStart	= 0x14/4,
191 	DmaEnd		= 0x1C/4,
192 	DmaDoneThresh	= 0x24/4,
193 	TdmaFlowPeriod	= 0x28/4,
194 	RdmaXonXoffThresh=0x28/4,
195 	TdmaWP		= 0x2C/4,
196 	RdmaRP		= 0x2C/4,
197 
198 	/*
199 	 * reg offsets only for RING16
200 	 * ctlr->rx->regs / ctlr->tx->regs
201 	 */
202 	RingCfg		= 0x40/4,
203 		RxRingCfgMask	= 0x10000,
204 		TxRingCfgMask	= 0x1000F,
205 
206 	DmaCtrl		= 0x44/4,
207 		DmaCtrlEn	= 1 << 0,
208 	DmaStatus	= 0x48/4,
209 		DmaStatusDis	= 1 << 0,
210 	DmaScbBurstSize	= 0x4C/4,
211 
212 	TdmaArbCtrl	= 0x6C/4,
213 	TdmaPriority0	= 0x70/4,
214 	TdmaPriority1	= 0x74/4,
215 	TdmaPriority2	= 0x78/4,
216 
217 	RdmaTimeout0	= 0x6C/4,
218 	RdmaIndex2Ring0	= 0xB0/4,
219 };
220 
221 typedef struct Desc Desc;
222 typedef struct Ring Ring;
223 typedef struct Ctlr Ctlr;
224 
225 struct Desc
226 {
227 	u32int	*d;	/* hw descriptor */
228 	Block	*b;
229 };
230 
231 struct Ring
232 {
233 	Rendez;
234 	u32int	*regs;
235 	u32int	*intregs;
236 	u32int	intmask;
237 
238 	Desc	*d;
239 
240 	u32int	m;
241 	u32int	cp;
242 	u32int	rp;
243 	u32int	wp;
244 
245 	int	num;
246 };
247 
248 struct Ctlr
249 {
250 	Lock;
251 	u32int	*regs;
252 
253 	Desc	rd[256];
254 	Desc	td[256];
255 
256 	Ring	rx[1+0];
257 	Ring	tx[1+0];
258 
259 	Rendez	avail[1];
260 	Rendez	link[1];
261 	struct {
262 		Mii;
263 		Rendez;
264 	}	mii[1];
265 
266 	QLock;
267 	char	attached;
268 };
269 
270 static Block *scratch;
271 
272 #define	REG(x)	(x)
273 
274 static void
interrupt0(Ureg *,void * arg)275 interrupt0(Ureg*, void *arg)
276 {
277 	Ether *edev = arg;
278 	Ctlr *ctlr = edev->ctlr;
279 	u32int sts;
280 
281 	sts = REG(ctlr->regs[Intrl0 + IntrSts]) & ~REG(ctlr->regs[Intrl0 + IntrMaskSts]);
282 	REG(ctlr->regs[Intrl0 + IntrClr]) = sts;
283 	REG(ctlr->regs[Intrl0 + IntrMaskSet]) = sts;
284 
285 	if(sts & ctlr->rx->intmask)
286 		wakeup(ctlr->rx);
287 	if(sts & ctlr->tx->intmask)
288 		wakeup(ctlr->tx);
289 
290 	if(sts & (IrqMdioDone|IrqMdioError))
291 		wakeup(ctlr->mii);
292 	if(sts & (IrqLinkUp|IrqLinkDown))
293 		wakeup(ctlr->link);
294 }
295 
296 static void
interrupt1(Ureg *,void * arg)297 interrupt1(Ureg*, void *arg)
298 {
299 	Ether *edev = arg;
300 	Ctlr *ctlr = edev->ctlr;
301 	u32int sts;
302 	int i;
303 
304 	sts = REG(ctlr->regs[Intrl1 + IntrSts]) & ~REG(ctlr->regs[Intrl1 + IntrMaskSts]);
305 	REG(ctlr->regs[Intrl1 + IntrClr]) = sts;
306 	REG(ctlr->regs[Intrl1 + IntrMaskSet]) = sts;
307 
308 	for(i = 1; i < nelem(ctlr->rx); i++)
309 		if(sts & ctlr->rx[i].intmask)
310 			wakeup(&ctlr->rx[i]);
311 
312 	for(i = 1; i < nelem(ctlr->tx); i++)
313 		if(sts & ctlr->tx[i].intmask)
314 			wakeup(&ctlr->tx[i]);
315 }
316 
317 static void
setdma(Desc * d,void * v)318 setdma(Desc *d, void *v)
319 {
320 	u64int pa = PADDR(v);
321 	REG(d->d[1]) = pa;
322 	REG(d->d[2]) = pa >> 32;
323 }
324 
325 static void
replenish(Desc * d)326 replenish(Desc *d)
327 {
328 	d->b = allocb(Rbsz);
329 	cachedwbse(d->b->rp, Rbsz);
330 	setdma(d, d->b->rp);
331 }
332 
333 static int
rxdone(void * arg)334 rxdone(void *arg)
335 {
336 	Ring *r = arg;
337 
338 	r->wp = REG(r->regs[RxWP]) & 0xFFFF;
339 	if(r->rp != r->wp)
340 		return 1;
341 	REG(r->intregs[IntrMaskClr]) = r->intmask;
342 	return 0;
343 }
344 
345 static void
recvproc(void * arg)346 recvproc(void *arg)
347 {
348 	Ether *edev = arg;
349 	Ctlr *ctlr = edev->ctlr;
350 	Desc *d;
351 	Block *b;
352 	u32int s;
353 
354 	while(waserror())
355 		;
356 
357 	for(;;){
358 		if(ctlr->rx->rp == ctlr->rx->wp){
359 			sleep(ctlr->rx, rxdone, ctlr->rx);
360 			continue;
361 		}
362 		d = &ctlr->rx->d[ctlr->rx->rp & ctlr->rx->m];
363 		b = d->b;
364 		cachedinvse(b->rp, Rbsz);
365 		s = REG(d->d[0]);
366 		replenish(d);
367 		coherence();
368 		ctlr->rx->rp = (ctlr->rx->rp + 1) & 0xFFFF;
369 		REG(ctlr->rx->regs[RxRP]) = ctlr->rx->rp;
370 		if((s & (DmaSOP|DmaEOP|DmaRxErrors)) != (DmaSOP|DmaEOP)){
371 			freeb(b);
372 			continue;
373 		}
374 		b->wp += (s & 0x7FFF0000) >> 16;
375 		etheriq(edev, b, 1);
376 	}
377 }
378 
379 static int
txavail(void * arg)380 txavail(void *arg)
381 {
382 	Ring *r = arg;
383 
384 	return ((r->wp+1) & r->m) != (r->cp & r->m);
385 }
386 
387 static void
sendproc(void * arg)388 sendproc(void *arg)
389 {
390 	Ether *edev = arg;
391 	Ctlr *ctlr = edev->ctlr;
392 	Desc *d;
393 	Block *b;
394 
395 	while(waserror())
396 		;
397 
398 	for(;;){
399 		if(!txavail(ctlr->tx)){
400 			sleep(ctlr->avail, txavail, ctlr->tx);
401 			continue;
402 		}
403 		if((b = qbread(edev->oq, 100000)) == nil)
404 			break;
405 		d = &ctlr->tx->d[ctlr->tx->wp & ctlr->tx->m];
406 		assert(d->b == nil);
407 		d->b = b;
408 		cachedwbse(b->rp, BLEN(b));
409 		setdma(d, b->rp);
410 		REG(d->d[0]) = BLEN(b)<<16 | DmaTxQtag | DmaSOP | DmaEOP | DmaTxAppendCrc;
411 		coherence();
412 		ctlr->tx->wp = (ctlr->tx->wp+1) & 0xFFFF;
413 		REG(ctlr->tx->regs[TxWP]) = ctlr->tx->wp;
414 	}
415 }
416 
417 static int
txdone(void * arg)418 txdone(void *arg)
419 {
420 	Ring *r = arg;
421 
422 	if(r->cp != r->wp){
423 		r->rp = REG(r->regs[TxRP]) & 0xFFFF;
424 		if(r->cp != r->rp)
425 			return 1;
426 	}
427 	REG(r->intregs[IntrMaskClr]) = r->intmask;
428 	return 0;
429 }
430 
431 static void
freeproc(void * arg)432 freeproc(void *arg)
433 {
434 	Ether *edev = arg;
435 	Ctlr *ctlr = edev->ctlr;
436 	Desc *d;
437 
438 	while(waserror())
439 		;
440 
441 	for(;;){
442 		if(ctlr->tx->cp == ctlr->tx->rp){
443 			wakeup(ctlr->avail);
444 			sleep(ctlr->tx, txdone, ctlr->tx);
445 			continue;
446 		}
447 		d = &ctlr->tx->d[ctlr->tx->cp & ctlr->tx->m];
448 		assert(d->b != nil);
449 		freeb(d->b);
450 		d->b = nil;
451 		coherence();
452 		ctlr->tx->cp = (ctlr->tx->cp+1) & 0xFFFF;
453 	}
454 }
455 
456 static void
initring(Ring * ring,Desc * desc,int start,int size)457 initring(Ring *ring, Desc *desc, int start, int size)
458 {
459 	ring->d = &desc[start];
460 	ring->m = size - 1;
461 	ring->cp = ring->rp = ring->wp = 0;
462 	REG(ring->regs[RxWP]) = 0;
463 	REG(ring->regs[RxRP]) = 0;
464 	REG(ring->regs[DmaStart]) = start*3;
465 	REG(ring->regs[DmaEnd]) = (start+size)*3 - 1;
466 	REG(ring->regs[RdmaWP]) = start*3;
467 	REG(ring->regs[RdmaRP]) = start*3;
468 	REG(ring->regs[DmaRingBufSize]) = (size << 16) | Rbsz;
469 	REG(ring->regs[DmaDoneThresh]) = 1;
470 }
471 
472 static void
introff(Ctlr * ctlr)473 introff(Ctlr *ctlr)
474 {
475 	REG(ctlr->regs[Intrl0 + IntrMaskSet]) = -1;
476 	REG(ctlr->regs[Intrl0 + IntrClr]) = -1;
477 	REG(ctlr->regs[Intrl1 + IntrMaskSet]) = -1;
478 	REG(ctlr->regs[Intrl1 + IntrClr]) = -1;
479 }
480 
481 static void
dmaoff(Ctlr * ctlr)482 dmaoff(Ctlr *ctlr)
483 {
484 	REG(ctlr->rx->regs[DmaCtrl]) &= ~(RxRingCfgMask<<1 | DmaCtrlEn);
485 	REG(ctlr->tx->regs[DmaCtrl]) &= ~(TxRingCfgMask<<1 | DmaCtrlEn);
486 
487 	REG(ctlr->regs[UmacTxFlush]) = 1;
488 	microdelay(10);
489 	REG(ctlr->regs[UmacTxFlush]) = 0;
490 
491 	while((REG(ctlr->rx->regs[DmaStatus]) & DmaStatusDis) == 0)
492 		microdelay(10);
493 	while((REG(ctlr->tx->regs[DmaStatus]) & DmaStatusDis) == 0)
494 		microdelay(10);
495 }
496 
497 static void
dmaon(Ctlr * ctlr)498 dmaon(Ctlr *ctlr)
499 {
500 	REG(ctlr->rx->regs[DmaCtrl]) |= DmaCtrlEn;
501 	REG(ctlr->tx->regs[DmaCtrl]) |= DmaCtrlEn;
502 
503 	while(REG(ctlr->rx->regs[DmaStatus]) & DmaStatusDis)
504 		microdelay(10);
505 	while(REG(ctlr->tx->regs[DmaStatus]) & DmaStatusDis)
506 		microdelay(10);
507 }
508 
509 static void
allocbufs(Ctlr * ctlr)510 allocbufs(Ctlr *ctlr)
511 {
512 	int i;
513 
514 	if(scratch == nil){
515 		scratch = allocb(Rbsz);
516 		memset(scratch->rp, 0xFF, Rbsz);
517 		cachedwbse(scratch->rp, Rbsz);
518 	}
519 
520 	for(i = 0; i < nelem(ctlr->rd); i++){
521 		ctlr->rd[i].d = &ctlr->regs[RdmaOffset + i*3];
522 		replenish(&ctlr->rd[i]);
523 	}
524 
525 	for(i = 0; i < nelem(ctlr->td); i++){
526 		ctlr->td[i].d = &ctlr->regs[TdmaOffset + i*3];
527 		setdma(&ctlr->td[i], scratch->rp);
528 		REG(ctlr->td[i].d[0]) = DmaTxUnderrun;
529 	}
530 }
531 
532 static void
freebufs(Ctlr * ctlr)533 freebufs(Ctlr *ctlr)
534 {
535 	int i;
536 
537 	for(i = 0; i < nelem(ctlr->rd); i++){
538 		if(ctlr->rd[i].b != nil){
539 			freeb(ctlr->rd[i].b);
540 			ctlr->rd[i].b = nil;
541 		}
542 	}
543 	for(i = 0; i < nelem(ctlr->td); i++){
544 		if(ctlr->td[i].b != nil){
545 			freeb(ctlr->td[i].b);
546 			ctlr->td[i].b = nil;
547 		}
548 	}
549 }
550 
551 static void
initrings(Ctlr * ctlr)552 initrings(Ctlr *ctlr)
553 {
554 	u32int rcfg, tcfg, dmapri[3];
555 	int i;
556 
557 	ctlr->rx->intregs = &ctlr->regs[Intrl0];
558 	ctlr->rx->intmask = IrqRxDmaDone;
559 	ctlr->rx->num = 16;
560 	rcfg = 1<<16;
561 	for(i = 1; i < nelem(ctlr->rx); i++){
562 		ctlr->rx[i].regs = &ctlr->regs[RdmaOffset + nelem(ctlr->rd)*3 + (i-1)*RingCfg];
563 		ctlr->rx[i].intregs = &ctlr->regs[Intrl1];
564 		ctlr->rx[i].intmask = 0x10000 << (i - 1);
565 		ctlr->rx[i].num = i - 1;
566 		rcfg |= 1<<(i-1);
567 	}
568 	assert(rcfg && (rcfg & ~RxRingCfgMask) == 0);
569 
570 	ctlr->tx->intregs = &ctlr->regs[Intrl0];
571 	ctlr->tx->intmask = IrqTxDmaDone;
572 	ctlr->tx->num = 16;
573 	tcfg = 1<<16;
574 	for(i = 1; i < nelem(ctlr->tx); i++){
575 		ctlr->tx[i].regs = &ctlr->regs[TdmaOffset + nelem(ctlr->td)*3 + (i-1)*RingCfg];
576 		ctlr->tx[i].intregs = &ctlr->regs[Intrl1];
577 		ctlr->tx[i].intmask = 1 << (i - 1);
578 		ctlr->tx[i].num = i - 1;
579 		tcfg |= 1<<(i-1);
580 	}
581 	assert(tcfg && (tcfg & ~TxRingCfgMask) == 0);
582 
583 	REG(ctlr->rx->regs[DmaScbBurstSize]) = 0x08;
584 	for(i = 1; i < nelem(ctlr->rx); i++)
585 		initring(&ctlr->rx[i], ctlr->rd, (i-1)*32, 32);
586 	initring(ctlr->rx, ctlr->rd, (i-1)*32, nelem(ctlr->rd) - (i-1)*32);
587 
588 	for(i = 0; i < nelem(ctlr->rx); i++){
589 		REG(ctlr->rx[i].regs[DmaDoneThresh]) = 1;
590 		REG(ctlr->rx[i].regs[RdmaXonXoffThresh]) = (5 << 16) | ((ctlr->rx[i].m+1) >> 4);
591 
592 		// set dma timeout to 50µs
593 		REG(ctlr->rx->regs[RdmaTimeout0 + ctlr->rx[i].num]) = ((50*1000 + 8191)/8192);
594 	}
595 
596 	REG(ctlr->tx->regs[DmaScbBurstSize]) = 0x08;
597 	for(i = 1; i < nelem(ctlr->tx); i++)
598 		initring(&ctlr->tx[i], ctlr->td, (i-1)*32, 32);
599 	initring(ctlr->tx, ctlr->td, (i-1)*32, nelem(ctlr->td) - (i-1)*32);
600 
601 	dmapri[0] = dmapri[1] = dmapri[2] = 0;
602 	for(i = 0; i < nelem(ctlr->tx); i++){
603 		REG(ctlr->tx[i].regs[DmaDoneThresh]) = 10;
604 		REG(ctlr->tx[i].regs[TdmaFlowPeriod]) = i ? 0 : Maxtu << 16;
605 		dmapri[ctlr->tx[i].num/6] |= i << ((ctlr->tx[i].num%6)*5);
606 	}
607 
608 	REG(ctlr->tx->regs[TdmaArbCtrl]) = 2;
609 	REG(ctlr->tx->regs[TdmaPriority0]) = dmapri[0];
610 	REG(ctlr->tx->regs[TdmaPriority1]) = dmapri[1];
611 	REG(ctlr->tx->regs[TdmaPriority2]) = dmapri[2];
612 
613 	REG(ctlr->rx->regs[RingCfg]) = rcfg;
614 	REG(ctlr->tx->regs[RingCfg]) = tcfg;
615 
616 	REG(ctlr->rx->regs[DmaCtrl]) |= rcfg<<1;
617 	REG(ctlr->tx->regs[DmaCtrl]) |= tcfg<<1;
618 }
619 
620 static void
umaccmd(Ctlr * ctlr,u32int set,u32int clr)621 umaccmd(Ctlr *ctlr, u32int set, u32int clr)
622 {
623 	ilock(ctlr);
624 	REG(ctlr->regs[UmacCmd]) = (REG(ctlr->regs[UmacCmd]) & ~clr) | set;
625 	iunlock(ctlr);
626 }
627 
628 static void
reset(Ctlr * ctlr)629 reset(Ctlr *ctlr)
630 {
631 	u32int r;
632 
633 	// reset umac
634 	r = REG(ctlr->regs[SysRbufFlushCtrl]);
635 	REG(ctlr->regs[SysRbufFlushCtrl]) = r | 2;
636 	microdelay(10);
637 	REG(ctlr->regs[SysRbufFlushCtrl]) = r & ~2;
638 	microdelay(10);
639 
640 	// umac reset
641 	REG(ctlr->regs[SysRbufFlushCtrl]) = 0;
642 	microdelay(10);
643 
644 	REG(ctlr->regs[UmacCmd]) = 0;
645 	REG(ctlr->regs[UmacCmd]) = CmdSwReset | CmdLclLoopEn;
646 	microdelay(2);
647 	REG(ctlr->regs[UmacCmd]) = 0;
648 }
649 
650 static void
setmac(Ctlr * ctlr,uchar * ea)651 setmac(Ctlr *ctlr, uchar *ea)
652 {
653 	REG(ctlr->regs[UmacMac0]) = ea[0]<<24 | ea[1]<<16 | ea[2]<<8 | ea[3];
654 	REG(ctlr->regs[UmacMac1]) = ea[4]<<8 | ea[5];
655 }
656 
657 static void
sethfb(Ctlr * ctlr)658 sethfb(Ctlr *ctlr)
659 {
660 	int i;
661 
662 	REG(ctlr->regs[HfbCtlr]) = 0;
663 	REG(ctlr->regs[HfbFltEnable]) = 0;
664 	REG(ctlr->regs[HfbFltEnable+1]) = 0;
665 
666 	for(i = 0; i < 8; i++)
667 		REG(ctlr->rx->regs[RdmaIndex2Ring0+i]) = 0;
668 
669 	for(i = 0; i < 48/4; i++)
670 		REG(ctlr->regs[HfbFltLen + i]) = 0;
671 
672 	for(i = 0; i < 48*128; i++)
673 		REG(ctlr->regs[HfbOffset + i]) = 0;
674 }
675 
676 static int
mdiodone(void * arg)677 mdiodone(void *arg)
678 {
679 	Ctlr *ctlr = arg;
680 	REG(ctlr->regs[Intrl0 + IntrMaskClr]) = (IrqMdioDone|IrqMdioError);
681 	return (REG(ctlr->regs[MdioCmd]) & MdioStartBusy) == 0;
682 }
683 
684 static int
mdiowait(Ctlr * ctlr)685 mdiowait(Ctlr *ctlr)
686 {
687 	REG(ctlr->regs[MdioCmd]) |= MdioStartBusy;
688 	while(REG(ctlr->regs[MdioCmd]) & MdioStartBusy)
689 		tsleep(ctlr->mii, mdiodone, ctlr, 10);
690 	return 0;
691 }
692 
693 static int
mdiow(Mii * mii,int phy,int addr,int data)694 mdiow(Mii* mii, int phy, int addr, int data)
695 {
696 	Ctlr *ctlr = mii->ctlr;
697 
698 	if(phy > MdioPhyMask)
699 		return -1;
700 	addr &= MdioAddrMask;
701 	REG(ctlr->regs[MdioCmd]) = MdioWrite
702 		| (phy << MdioPhyShift) | (addr << MdioAddrShift) | (data & 0xFFFF);
703 	return mdiowait(ctlr);
704 }
705 
706 static int
mdior(Mii * mii,int phy,int addr)707 mdior(Mii* mii, int phy, int addr)
708 {
709 	Ctlr *ctlr = mii->ctlr;
710 
711 	if(phy > MdioPhyMask)
712 		return -1;
713 	addr &= MdioAddrMask;
714 	REG(ctlr->regs[MdioCmd]) = MdioRead
715 		| (phy << MdioPhyShift) | (addr << MdioAddrShift);
716 	if(mdiowait(ctlr) < 0)
717 		return -1;
718 	if(REG(ctlr->regs[MdioCmd]) & MdioReadFail)
719 		return -1;
720 	return REG(ctlr->regs[MdioCmd]) & 0xFFFF;
721 }
722 
723 static int
bcmshdr(Mii * mii,int reg)724 bcmshdr(Mii *mii, int reg)
725 {
726 	miimiw(mii, 0x1C, (reg & 0x1F) << 10);
727 	return miimir(mii, 0x1C) & 0x3FF;
728 }
729 
730 static int
bcmshdw(Mii * mii,int reg,int dat)731 bcmshdw(Mii *mii, int reg, int dat)
732 {
733 	return miimiw(mii, 0x1C, 0x8000 | (reg & 0x1F) << 10 | (dat & 0x3FF));
734 }
735 
736 static int
linkevent(void * arg)737 linkevent(void *arg)
738 {
739 	Ctlr *ctlr = arg;
740 	REG(ctlr->regs[Intrl0 + IntrMaskClr]) = IrqLinkUp|IrqLinkDown;
741 	return 0;
742 }
743 
744 static void
linkproc(void * arg)745 linkproc(void *arg)
746 {
747 	Ether *edev = arg;
748 	Ctlr *ctlr = edev->ctlr;
749 	MiiPhy *phy;
750 	int link = -1;
751 
752 	while(waserror())
753 		;
754 
755 	for(;;){
756 		tsleep(ctlr->link, linkevent, ctlr, 1000);
757 		miistatus(ctlr->mii);
758 		phy = ctlr->mii->curphy;
759 		if(phy == nil || phy->link == link)
760 			continue;
761 		link = phy->link;
762 		if(link){
763 			u32int cmd = CmdRxEn|CmdTxEn;
764 			switch(phy->speed){
765 			case 1000:	cmd |= CmdSpeed1000; break;
766 			case 100:	cmd |= CmdSpeed100; break;
767 			case 10:	cmd |= CmdSpeed10; break;
768 			}
769 			if(!phy->fd)
770 				cmd |= CmdHdEn;
771 			if(!phy->rfc)
772 				cmd |= CmdRxPauseIgn;
773 			if(!phy->tfc)
774 				cmd |= CmdTxPauseIgn;
775 
776 			REG(ctlr->regs[ExtRgmiiOobCtrl]) = (REG(ctlr->regs[ExtRgmiiOobCtrl]) & ~OobDisable) | RgmiiLink;
777 			umaccmd(ctlr, cmd, CmdSpeedMask|CmdHdEn|CmdRxPauseIgn|CmdTxPauseIgn);
778 
779 			edev->mbps = phy->speed;
780 		}
781 		edev->link = link;
782 		// print("#l%d: link %d speed %d\n", edev->ctlrno, edev->link, edev->mbps);
783 	}
784 }
785 
786 static void
setmdfaddr(Ctlr * ctlr,int i,uchar * ea)787 setmdfaddr(Ctlr *ctlr, int i, uchar *ea)
788 {
789 	REG(ctlr->regs[UmacMdfAddr0 + i*2 + 0]) = ea[0] << 8  | ea[1];
790 	REG(ctlr->regs[UmacMdfAddr0 + i*2 + 1]) = ea[2] << 24 | ea[3] << 16 | ea[4] << 8 | ea[5];
791 }
792 
793 static void
rxmode(Ether * edev,int prom)794 rxmode(Ether *edev, int prom)
795 {
796 	Ctlr *ctlr = edev->ctlr;
797 	Netaddr *na;
798 	int i;
799 
800 	if(prom || edev->nmaddr > 16-2){
801 		REG(ctlr->regs[UmacMdfCtrl]) = 0;
802 		umaccmd(ctlr, CmdProm, 0);
803 		return;
804 	}
805 	setmdfaddr(ctlr, 0, edev->bcast);
806 	setmdfaddr(ctlr, 1, edev->ea);
807 	for(i = 2, na = edev->maddr; na != nil; na = na->next, i++)
808 		setmdfaddr(ctlr, i, na->addr);
809 	REG(ctlr->regs[UmacMdfCtrl]) = (-0x10000 >> i) & 0x1FFFF;
810 	umaccmd(ctlr, 0, CmdProm);
811 }
812 
813 static void
shutdown(Ether * edev)814 shutdown(Ether *edev)
815 {
816 	Ctlr *ctlr = edev->ctlr;
817 
818 	dmaoff(ctlr);
819 	introff(ctlr);
820 }
821 
822 static void
attach(Ether * edev)823 attach(Ether *edev)
824 {
825 	Ctlr *ctlr = edev->ctlr;
826 
827 	qlock(ctlr);
828 	if(ctlr->attached){
829 		qunlock(ctlr);
830 		return;
831 	}
832 	if(waserror()){
833 		print("#l%d: %s\n", edev->ctlrno, up->errstr);
834 		shutdown(edev);
835 		freebufs(ctlr);
836 		qunlock(ctlr);
837 		nexterror();
838 	}
839 
840 	// statistics
841 	REG(ctlr->regs[UmacMibCtrl]) = MibResetRx | MibResetTx | MibResetRunt;
842 	REG(ctlr->regs[UmacMibCtrl]) = 0;
843 
844 	// wol
845 	REG(ctlr->regs[UmacMpdCtrl]) &= ~(MpdPwEn|MpdEn);
846 
847 	// power
848 	REG(ctlr->regs[UmacEeeCtrl]) &= ~UmacEeeEn;
849 	REG(ctlr->regs[RbufEnergyCtrl]) &= ~(RbufEeeEn|RbufPmEn);
850 	REG(ctlr->regs[TbufEnergyCtrl]) &= ~(RbufEeeEn|RbufPmEn);
851 	REG(ctlr->regs[TbufBpMc]) = 0;
852 
853 	REG(ctlr->regs[UmacMaxFrameLen]) = Maxtu;
854 
855 	REG(ctlr->regs[RbufTbufSizeCtrl]) = 1;
856 
857 	REG(ctlr->regs[TbufCtrl]) &= ~(Rbuf64En);
858 	REG(ctlr->regs[RbufCtrl]) &= ~(Rbuf64En|RbufAlign2B);
859 	REG(ctlr->regs[RbufChkCtrl]) &= ~(RbufChkRxChkEn|RbufChkSkipFcs);
860 
861 	allocbufs(ctlr);
862 	initrings(ctlr);
863 	dmaon(ctlr);
864 
865 	setmac(ctlr, edev->ea);
866 	sethfb(ctlr);
867 	rxmode(edev, 0);
868 
869 	REG(ctlr->regs[SysPortCtrl]) = PortModeExtGphy;
870 	REG(ctlr->regs[ExtRgmiiOobCtrl]) |= RgmiiModeEn | IdModeDis;
871 
872 	ctlr->mii->ctlr = ctlr;
873 	ctlr->mii->mir = mdior;
874 	ctlr->mii->miw = mdiow;
875 	mii(ctlr->mii, ~0);
876 
877 	if(ctlr->mii->curphy == nil)
878 		error("no phy");
879 
880 	MIIDBG("#l%d: phy%d id %.8ux oui %x\n",
881 		edev->ctlrno, ctlr->mii->curphy->phyno,
882 		ctlr->mii->curphy->id, ctlr->mii->curphy->oui);
883 
884 	miireset(ctlr->mii);
885 
886 	switch(ctlr->mii->curphy->id){
887 	case 0x600d84a2:	/* BCM54312PE */
888 		/* mask interrupts */
889 		miimiw(ctlr->mii, 0x10, miimir(ctlr->mii, 0x10) | 0x1000);
890 
891 		/* SCR3: clear DLLAPD_DIS */
892 		bcmshdw(ctlr->mii, 0x05, bcmshdr(ctlr->mii, 0x05) &~0x0002);
893 		/* APD: set APD_EN */
894 		bcmshdw(ctlr->mii, 0x0a, bcmshdr(ctlr->mii, 0x0a) | 0x0020);
895 
896 		/* blinkenlights */
897 		bcmshdw(ctlr->mii, 0x09, bcmshdr(ctlr->mii, 0x09) | 0x0010);
898 		bcmshdw(ctlr->mii, 0x0d, 3<<0 | 0<<4);
899 		break;
900 	}
901 
902 	/* don't advertise EEE */
903 	miimmdw(ctlr->mii, 7, 60, 0);
904 
905 	miiane(ctlr->mii, ~0, AnaAP|AnaP, ~0);
906 
907 	ctlr->attached = 1;
908 
909 	kproc("genet-recv", recvproc, edev);
910 	kproc("genet-send", sendproc, edev);
911 	kproc("genet-free", freeproc, edev);
912 	kproc("genet-link", linkproc, edev);
913 
914 	qunlock(ctlr);
915 	poperror();
916 }
917 
918 static void
prom(void * arg,int on)919 prom(void *arg, int on)
920 {
921 	Ether *edev = arg;
922 	rxmode(edev, on);
923 }
924 
925 static void
multi(void * arg,uchar *,int)926 multi(void *arg, uchar*, int)
927 {
928 	Ether *edev = arg;
929 	rxmode(edev, edev->prom > 0);
930 }
931 
932 static int
pnp(Ether * edev)933 pnp(Ether *edev)
934 {
935 	static Ctlr ctlr[1];
936 
937 	if(ctlr->regs != nil)
938 		return -1;
939 
940 	ctlr->regs = (u32int*)(VIRTIO + 0x580000);
941 	ctlr->rx->regs = &ctlr->regs[RdmaOffset + nelem(ctlr->rd)*3 + 16*RingCfg];
942 	ctlr->tx->regs = &ctlr->regs[TdmaOffset + nelem(ctlr->td)*3 + 16*RingCfg];
943 
944 	edev->port = (uintptr)ctlr->regs;
945 	edev->irq = IRQether;
946 	edev->ctlr = ctlr;
947 	edev->attach = attach;
948 	edev->shutdown = shutdown;
949 	edev->promiscuous = prom;
950 	edev->multicast = multi;
951 	edev->arg = edev;
952 	edev->mbps = 1000;
953 	edev->maxmtu = Maxtu;
954 
955 	parseether(edev->ea, getethermac());
956 
957 	reset(ctlr);
958 	dmaoff(ctlr);
959 	introff(ctlr);
960 
961 	intrenable(edev->irq+0, interrupt0, edev, BUSUNKNOWN, edev->name);
962 	intrenable(edev->irq+1, interrupt1, edev, BUSUNKNOWN, edev->name);
963 
964 	return 0;
965 }
966 
967 void
ethergenetlink(void)968 ethergenetlink(void)
969 {
970 	addethercard("genet", pnp);
971 }
972