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