2 #include "../port/lib.h"
7 #include "../port/netif.h"
8 #include "../port/etherif.h"
9 #include "../port/ethermii.h"
24 DmaRxErrors = DmaRxLg|DmaRxNo|DmaRxErr|DmaRxCrc|DmaRxOv,
27 DmaTxUnderrun = 0x0200,
28 DmaTxAppendCrc = 0x0040,
39 PortModeExtRvmii50 = 4,
40 PortModeExtRvmii25 = 16 | 4,
41 LedActSourceMac = 1 << 9,
43 SysRbufFlushCtrl = 0x08/4,
44 SysTbufFlushCtrl = 0x0C/4,
46 ExtRgmiiOobCtrl = 0x8C/4,
61 IrqTbufUnderrun = 1 << 8,
62 IrqRbufOverflow = 1 << 9,
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,
88 RbufChkCtrl = 0x314/4,
89 RbufChkRxChkEn = 1 << 0,
90 RbufChkSkipFcs = 1 << 4,
92 RbufOvflCnt = 0x394/4,
95 RbufEnergyCtrl = 0x39c/4,
99 RbufTbufSizeCtrl= 0x3b4/4,
103 TbufEnergyCtrl = 0x614/4,
109 CmdSpeed100 = 1 << 2,
110 CmdSpeed1000 = 2 << 2,
111 CmdSpeedMask = 3 << 2,
115 CmdPauseFwd = 1 << 7,
116 CmdRxPauseIgn = 1 << 8,
117 CmdTxAddrIn = 1 << 9,
119 CmdSwReset = 1 << 13,
120 CmdLclLoopEn = 1 << 15,
121 CmdAutoConfig = 1 << 22,
122 CmdCntlFrmEn = 1 << 23,
123 CmdNoLenChk = 1 << 24,
124 CmdRmtLoopEn = 1 << 25,
126 CmdTxPauseIgn = 1 << 28,
128 CmdRuntFilterDis= 1 << 30,
132 UmacMaxFrameLen = 0x814/4,
134 UmacEeeCtrl = 0x864/4,
137 UmacEeeLpiTimer = 0x868/4,
138 UmacEeeWakeTimer= 0x86C/4,
139 UmacEeeRefCount = 0x870/4,
140 EeeRefCountMask = 0xFFFF,
142 UmacTxFlush = 0xb34/4,
144 UmacMibCtrl = 0xd80/4,
146 MibResetRunt = 1 << 1,
150 MdioStartBusy = 1 << 29,
151 MdioReadFail = 1 << 28,
159 UmacMpdCtrl = 0xe20/4,
163 UmacMdfCtrl = 0xe50/4,
164 UmacMdfAddr0 = 0xe54/4,
166 RdmaOffset = 0x2000/4,
167 TdmaOffset = 0x4000/4,
168 HfbOffset = 0x8000/4,
171 HfbFltEnable = 0xFC04/4,
172 HfbFltLen = 0xFC1C/4,
174 /* common Ring->regs */
181 DmaRingBufSize = 0x10/4,
184 DmaDoneThresh = 0x24/4,
185 TdmaFlowPeriod = 0x28/4,
186 RdmaXonXoffThresh=0x28/4,
191 * reg offsets only for RING16
192 * ctlr->rx->regs / ctlr->tx->regs
195 RxRingCfgMask = 0x10000,
196 TxRingCfgMask = 0x1000F,
201 DmaStatusDis = 1 << 0,
202 DmaScbBurstSize = 0x4C/4,
204 TdmaArbCtrl = 0x6C/4,
205 TdmaPriority0 = 0x70/4,
206 TdmaPriority1 = 0x74/4,
207 TdmaPriority2 = 0x78/4,
209 RdmaTimeout0 = 0x6C/4,
210 RdmaIndex2Ring0 = 0xB0/4,
213 typedef struct Desc Desc;
214 typedef struct Ring Ring;
215 typedef struct Ctlr Ctlr;
219 u32int *d; /* hw descriptor */
262 static Block *scratch;
267 interrupt0(Ureg*, void *arg)
270 Ctlr *ctlr = edev->ctlr;
273 sts = REG(ctlr->regs[Intrl0 + IntrSts]) & ~REG(ctlr->regs[Intrl0 + IntrMaskSts]);
274 REG(ctlr->regs[Intrl0 + IntrClr]) = sts;
275 REG(ctlr->regs[Intrl0 + IntrMaskSet]) = sts;
277 if(sts & ctlr->rx->intmask)
279 if(sts & ctlr->tx->intmask)
282 if(sts & (IrqMdioDone|IrqMdioError))
284 if(sts & (IrqLinkUp|IrqLinkDown))
289 interrupt1(Ureg*, void *arg)
292 Ctlr *ctlr = edev->ctlr;
296 sts = REG(ctlr->regs[Intrl1 + IntrSts]) & ~REG(ctlr->regs[Intrl1 + IntrMaskSts]);
297 REG(ctlr->regs[Intrl1 + IntrClr]) = sts;
298 REG(ctlr->regs[Intrl1 + IntrMaskSet]) = sts;
300 for(i = 1; i < nelem(ctlr->rx); i++)
301 if(sts & ctlr->rx[i].intmask)
302 wakeup(&ctlr->rx[i]);
304 for(i = 1; i < nelem(ctlr->tx); i++)
305 if(sts & ctlr->tx[i].intmask)
306 wakeup(&ctlr->tx[i]);
310 setdma(Desc *d, void *v)
312 u64int pa = PADDR(v);
314 REG(d->d[2]) = pa >> 32;
321 dmaflush(1, d->b->rp, Rbsz);
330 r->wp = REG(r->regs[RxWP]) & 0xFFFF;
333 REG(r->intregs[IntrMaskClr]) = r->intmask;
341 Ctlr *ctlr = edev->ctlr;
350 if(ctlr->rx->rp == ctlr->rx->wp){
351 sleep(ctlr->rx, rxdone, ctlr->rx);
354 d = &ctlr->rx->d[ctlr->rx->rp & ctlr->rx->m];
356 dmaflush(0, b->rp, Rbsz);
360 ctlr->rx->rp = (ctlr->rx->rp + 1) & 0xFFFF;
361 REG(ctlr->rx->regs[RxRP]) = ctlr->rx->rp;
362 if((s & (DmaSOP|DmaEOP|DmaRxErrors)) != (DmaSOP|DmaEOP)){
366 b->wp += (s & 0x0FFF0000) >> 16;
376 return ((r->wp+1) & r->m) != (r->cp & r->m);
383 Ctlr *ctlr = edev->ctlr;
391 if(!txavail(ctlr->tx)){
392 sleep(ctlr->avail, txavail, ctlr->tx);
395 if((b = qbread(edev->oq, 100000)) == nil)
397 d = &ctlr->tx->d[ctlr->tx->wp & ctlr->tx->m];
400 dmaflush(1, b->rp, BLEN(b));
402 REG(d->d[0]) = BLEN(b)<<16 | DmaTxQtag | DmaSOP | DmaEOP | DmaTxAppendCrc;
404 ctlr->tx->wp = (ctlr->tx->wp+1) & 0xFFFF;
405 REG(ctlr->tx->regs[TxWP]) = ctlr->tx->wp;
415 r->rp = REG(r->regs[TxRP]) & 0xFFFF;
419 REG(r->intregs[IntrMaskClr]) = r->intmask;
427 Ctlr *ctlr = edev->ctlr;
434 if(ctlr->tx->cp == ctlr->tx->rp){
436 sleep(ctlr->tx, txdone, ctlr->tx);
439 d = &ctlr->tx->d[ctlr->tx->cp & ctlr->tx->m];
444 ctlr->tx->cp = (ctlr->tx->cp+1) & 0xFFFF;
449 initring(Ring *ring, Desc *desc, int start, int size)
451 ring->d = &desc[start];
453 ring->cp = ring->rp = ring->wp = 0;
454 REG(ring->regs[RxWP]) = 0;
455 REG(ring->regs[RxRP]) = 0;
456 REG(ring->regs[DmaStart]) = start*3;
457 REG(ring->regs[DmaEnd]) = (start+size)*3 - 1;
458 REG(ring->regs[RdmaWP]) = start*3;
459 REG(ring->regs[RdmaRP]) = start*3;
460 REG(ring->regs[DmaRingBufSize]) = (size << 16) | Rbsz;
461 REG(ring->regs[DmaDoneThresh]) = 1;
467 REG(ctlr->regs[Intrl0 + IntrMaskSet]) = -1;
468 REG(ctlr->regs[Intrl0 + IntrClr]) = -1;
469 REG(ctlr->regs[Intrl1 + IntrMaskSet]) = -1;
470 REG(ctlr->regs[Intrl1 + IntrClr]) = -1;
476 REG(ctlr->rx->regs[DmaCtrl]) &= ~(RxRingCfgMask<<1 | DmaCtrlEn);
477 REG(ctlr->tx->regs[DmaCtrl]) &= ~(TxRingCfgMask<<1 | DmaCtrlEn);
479 REG(ctlr->regs[UmacTxFlush]) = 1;
481 REG(ctlr->regs[UmacTxFlush]) = 0;
483 while((REG(ctlr->rx->regs[DmaStatus]) & DmaStatusDis) == 0)
485 while((REG(ctlr->tx->regs[DmaStatus]) & DmaStatusDis) == 0)
492 REG(ctlr->rx->regs[DmaCtrl]) |= DmaCtrlEn;
493 REG(ctlr->tx->regs[DmaCtrl]) |= DmaCtrlEn;
495 while(REG(ctlr->rx->regs[DmaStatus]) & DmaStatusDis)
497 while(REG(ctlr->tx->regs[DmaStatus]) & DmaStatusDis)
502 allocbufs(Ctlr *ctlr)
507 scratch = allocb(Rbsz);
508 memset(scratch->rp, 0xFF, Rbsz);
509 dmaflush(1, scratch->rp, Rbsz);
512 for(i = 0; i < nelem(ctlr->rd); i++){
513 ctlr->rd[i].d = &ctlr->regs[RdmaOffset + i*3];
514 replenish(&ctlr->rd[i]);
517 for(i = 0; i < nelem(ctlr->td); i++){
518 ctlr->td[i].d = &ctlr->regs[TdmaOffset + i*3];
519 setdma(&ctlr->td[i], scratch->rp);
520 REG(ctlr->td[i].d[0]) = DmaTxUnderrun;
529 for(i = 0; i < nelem(ctlr->rd); i++){
530 if(ctlr->rd[i].b != nil){
531 freeb(ctlr->rd[i].b);
535 for(i = 0; i < nelem(ctlr->td); i++){
536 if(ctlr->td[i].b != nil){
537 freeb(ctlr->td[i].b);
544 initrings(Ctlr *ctlr)
546 u32int rcfg, tcfg, dmapri[3];
549 ctlr->rx->intregs = &ctlr->regs[Intrl0];
550 ctlr->rx->intmask = IrqRxDmaDone;
553 for(i = 1; i < nelem(ctlr->rx); i++){
554 ctlr->rx[i].regs = &ctlr->regs[RdmaOffset + nelem(ctlr->rd)*3 + (i-1)*RingCfg];
555 ctlr->rx[i].intregs = &ctlr->regs[Intrl1];
556 ctlr->rx[i].intmask = 0x10000 << (i - 1);
557 ctlr->rx[i].num = i - 1;
560 assert(rcfg && (rcfg & ~RxRingCfgMask) == 0);
562 ctlr->tx->intregs = &ctlr->regs[Intrl0];
563 ctlr->tx->intmask = IrqTxDmaDone;
566 for(i = 1; i < nelem(ctlr->tx); i++){
567 ctlr->tx[i].regs = &ctlr->regs[TdmaOffset + nelem(ctlr->td)*3 + (i-1)*RingCfg];
568 ctlr->tx[i].intregs = &ctlr->regs[Intrl1];
569 ctlr->tx[i].intmask = 1 << (i - 1);
570 ctlr->tx[i].num = i - 1;
573 assert(tcfg && (tcfg & ~TxRingCfgMask) == 0);
575 REG(ctlr->rx->regs[DmaScbBurstSize]) = 0x08;
576 for(i = 1; i < nelem(ctlr->rx); i++)
577 initring(&ctlr->rx[i], ctlr->rd, (i-1)*32, 32);
578 initring(ctlr->rx, ctlr->rd, (i-1)*32, nelem(ctlr->rd) - (i-1)*32);
580 for(i = 0; i < nelem(ctlr->rx); i++){
581 REG(ctlr->rx[i].regs[DmaDoneThresh]) = 1;
582 REG(ctlr->rx[i].regs[RdmaXonXoffThresh]) = (5 << 16) | ((ctlr->rx[i].m+1) >> 4);
584 // set dma timeout to 50µs
585 REG(ctlr->rx->regs[RdmaTimeout0 + ctlr->rx[i].num]) = ((50*1000 + 8191)/8192);
588 REG(ctlr->tx->regs[DmaScbBurstSize]) = 0x08;
589 for(i = 1; i < nelem(ctlr->tx); i++)
590 initring(&ctlr->tx[i], ctlr->td, (i-1)*32, 32);
591 initring(ctlr->tx, ctlr->td, (i-1)*32, nelem(ctlr->td) - (i-1)*32);
593 dmapri[0] = dmapri[1] = dmapri[2] = 0;
594 for(i = 0; i < nelem(ctlr->tx); i++){
595 REG(ctlr->tx[i].regs[DmaDoneThresh]) = 10;
596 REG(ctlr->tx[i].regs[TdmaFlowPeriod]) = i ? 0 : Maxtu << 16;
597 dmapri[ctlr->tx[i].num/6] |= i << ((ctlr->tx[i].num%6)*5);
600 REG(ctlr->tx->regs[TdmaArbCtrl]) = 2;
601 REG(ctlr->tx->regs[TdmaPriority0]) = dmapri[0];
602 REG(ctlr->tx->regs[TdmaPriority1]) = dmapri[1];
603 REG(ctlr->tx->regs[TdmaPriority2]) = dmapri[2];
605 REG(ctlr->rx->regs[RingCfg]) = rcfg;
606 REG(ctlr->tx->regs[RingCfg]) = tcfg;
608 REG(ctlr->rx->regs[DmaCtrl]) |= rcfg<<1;
609 REG(ctlr->tx->regs[DmaCtrl]) |= tcfg<<1;
613 umaccmd(Ctlr *ctlr, u32int set, u32int clr)
616 REG(ctlr->regs[UmacCmd]) = (REG(ctlr->regs[UmacCmd]) & ~clr) | set;
626 r = REG(ctlr->regs[SysRbufFlushCtrl]);
627 REG(ctlr->regs[SysRbufFlushCtrl]) = r | 2;
629 REG(ctlr->regs[SysRbufFlushCtrl]) = r & ~2;
633 REG(ctlr->regs[SysRbufFlushCtrl]) = 0;
636 REG(ctlr->regs[UmacCmd]) = 0;
637 REG(ctlr->regs[UmacCmd]) = CmdSwReset | CmdLclLoopEn;
639 REG(ctlr->regs[UmacCmd]) = 0;
643 setmac(Ctlr *ctlr, uchar *ea)
645 REG(ctlr->regs[UmacMac0]) = ea[0]<<24 | ea[1]<<16 | ea[2]<<8 | ea[3];
646 REG(ctlr->regs[UmacMac1]) = ea[4]<<8 | ea[5];
654 REG(ctlr->regs[HfbCtlr]) = 0;
655 REG(ctlr->regs[HfbFltEnable]) = 0;
656 REG(ctlr->regs[HfbFltEnable+1]) = 0;
658 for(i = 0; i < 8; i++)
659 REG(ctlr->rx->regs[RdmaIndex2Ring0+i]) = 0;
661 for(i = 0; i < 48/4; i++)
662 REG(ctlr->regs[HfbFltLen + i]) = 0;
664 for(i = 0; i < 48*128; i++)
665 REG(ctlr->regs[HfbOffset + i]) = 0;
672 REG(ctlr->regs[Intrl0 + IntrMaskClr]) = (IrqMdioDone|IrqMdioError);
673 return (REG(ctlr->regs[MdioCmd]) & MdioStartBusy) == 0;
679 REG(ctlr->regs[MdioCmd]) |= MdioStartBusy;
680 while(REG(ctlr->regs[MdioCmd]) & MdioStartBusy)
681 tsleep(ctlr->mii, mdiodone, ctlr, 10);
686 mdiow(Mii* mii, int phy, int addr, int data)
688 Ctlr *ctlr = mii->ctlr;
690 if(phy > MdioPhyMask)
692 addr &= MdioAddrMask;
693 REG(ctlr->regs[MdioCmd]) = MdioWrite
694 | (phy << MdioPhyShift) | (addr << MdioAddrShift) | (data & 0xFFFF);
695 return mdiowait(ctlr);
699 mdior(Mii* mii, int phy, int addr)
701 Ctlr *ctlr = mii->ctlr;
703 if(phy > MdioPhyMask)
705 addr &= MdioAddrMask;
706 REG(ctlr->regs[MdioCmd]) = MdioRead
707 | (phy << MdioPhyShift) | (addr << MdioAddrShift);
708 if(mdiowait(ctlr) < 0)
710 if(REG(ctlr->regs[MdioCmd]) & MdioReadFail)
712 return REG(ctlr->regs[MdioCmd]) & 0xFFFF;
716 bcmshdr(Mii *mii, int reg)
718 miimiw(mii, 0x1C, (reg & 0x1F) << 10);
719 return miimir(mii, 0x1C) & 0x3FF;
723 bcmshdw(Mii *mii, int reg, int dat)
725 return miimiw(mii, 0x1C, 0x8000 | (reg & 0x1F) << 10 | (dat & 0x3FF));
732 REG(ctlr->regs[Intrl0 + IntrMaskClr]) = IrqLinkUp|IrqLinkDown;
740 Ctlr *ctlr = edev->ctlr;
748 tsleep(ctlr->link, linkevent, ctlr, 1000);
749 miistatus(ctlr->mii);
750 phy = ctlr->mii->curphy;
751 if(phy == nil || phy->link == link)
755 u32int cmd = CmdRxEn|CmdTxEn;
757 case 1000: cmd |= CmdSpeed1000; break;
758 case 100: cmd |= CmdSpeed100; break;
759 case 10: cmd |= CmdSpeed10; break;
764 cmd |= CmdRxPauseIgn;
766 cmd |= CmdTxPauseIgn;
768 REG(ctlr->regs[ExtRgmiiOobCtrl]) = (REG(ctlr->regs[ExtRgmiiOobCtrl]) & ~OobDisable) | RgmiiLink;
769 umaccmd(ctlr, cmd, CmdSpeedMask|CmdHdEn|CmdRxPauseIgn|CmdTxPauseIgn);
771 edev->mbps = phy->speed;
774 // print("#l%d: link %d speed %d\n", edev->ctlrno, edev->link, edev->mbps);
779 setmdfaddr(Ctlr *ctlr, int i, uchar *ea)
781 REG(ctlr->regs[UmacMdfAddr0 + i*2 + 0]) = ea[0] << 8 | ea[1];
782 REG(ctlr->regs[UmacMdfAddr0 + i*2 + 1]) = ea[2] << 24 | ea[3] << 16 | ea[4] << 8 | ea[5];
786 rxmode(Ether *edev, int prom)
788 Ctlr *ctlr = edev->ctlr;
792 if(prom || edev->nmaddr > 16-2){
793 REG(ctlr->regs[UmacMdfCtrl]) = 0;
794 umaccmd(ctlr, CmdProm, 0);
797 setmdfaddr(ctlr, 0, edev->bcast);
798 setmdfaddr(ctlr, 1, edev->ea);
799 for(i = 2, na = edev->maddr; na != nil; na = na->next, i++)
800 setmdfaddr(ctlr, i, na->addr);
801 REG(ctlr->regs[UmacMdfCtrl]) = (-0x10000 >> i) & 0x1FFFF;
802 umaccmd(ctlr, 0, CmdProm);
806 shutdown(Ether *edev)
808 Ctlr *ctlr = edev->ctlr;
817 Ctlr *ctlr = edev->ctlr;
825 print("#l%d: %s\n", edev->ctlrno, up->errstr);
833 REG(ctlr->regs[UmacMibCtrl]) = MibResetRx | MibResetTx | MibResetRunt;
834 REG(ctlr->regs[UmacMibCtrl]) = 0;
837 REG(ctlr->regs[UmacMpdCtrl]) &= ~(MpdPwEn|MpdEn);
840 REG(ctlr->regs[UmacEeeCtrl]) &= ~UmacEeeEn;
841 REG(ctlr->regs[RbufEnergyCtrl]) &= ~(RbufEeeEn|RbufPmEn);
842 REG(ctlr->regs[TbufEnergyCtrl]) &= ~(RbufEeeEn|RbufPmEn);
843 REG(ctlr->regs[TbufBpMc]) = 0;
845 REG(ctlr->regs[UmacMaxFrameLen]) = Maxtu;
847 REG(ctlr->regs[RbufTbufSizeCtrl]) = 1;
849 REG(ctlr->regs[TbufCtrl]) &= ~(Rbuf64En);
850 REG(ctlr->regs[RbufCtrl]) &= ~(Rbuf64En|RbufAlign2B);
851 REG(ctlr->regs[RbufChkCtrl]) &= ~(RbufChkRxChkEn|RbufChkSkipFcs);
857 setmac(ctlr, edev->ea);
861 REG(ctlr->regs[SysPortCtrl]) = PortModeExtGphy;
862 REG(ctlr->regs[ExtRgmiiOobCtrl]) |= RgmiiModeEn | IdModeDis;
864 ctlr->mii->ctlr = ctlr;
865 ctlr->mii->mir = mdior;
866 ctlr->mii->miw = mdiow;
869 if(ctlr->mii->curphy == nil)
872 print("#l%d: phy%d id %.8ux oui %x\n",
873 edev->ctlrno, ctlr->mii->curphy->phyno,
874 ctlr->mii->curphy->id, ctlr->mii->curphy->oui);
878 switch(ctlr->mii->curphy->id){
879 case 0x600d84a2: /* BCM54312PE */
880 /* mask interrupts */
881 miimiw(ctlr->mii, 0x10, miimir(ctlr->mii, 0x10) | 0x1000);
883 /* SCR3: clear DLLAPD_DIS */
884 bcmshdw(ctlr->mii, 0x05, bcmshdr(ctlr->mii, 0x05) &~0x0002);
885 /* APD: set APD_EN */
886 bcmshdw(ctlr->mii, 0x0a, bcmshdr(ctlr->mii, 0x0a) | 0x0020);
889 bcmshdw(ctlr->mii, 0x09, bcmshdr(ctlr->mii, 0x09) | 0x0010);
890 bcmshdw(ctlr->mii, 0x0d, 3<<0 | 0<<4);
894 /* don't advertise EEE */
895 miimmdw(ctlr->mii, 7, 60, 0);
897 miiane(ctlr->mii, ~0, AnaAP|AnaP, ~0);
901 kproc("genet-recv", recvproc, edev);
902 kproc("genet-send", sendproc, edev);
903 kproc("genet-free", freeproc, edev);
904 kproc("genet-link", linkproc, edev);
911 prom(void *arg, int on)
918 multi(void *arg, uchar*, int)
921 rxmode(edev, edev->prom > 0);
929 if(ctlr->regs != nil)
932 ctlr->regs = (u32int*)(VIRTIO1 + 0x580000);
933 ctlr->rx->regs = &ctlr->regs[RdmaOffset + nelem(ctlr->rd)*3 + 16*RingCfg];
934 ctlr->tx->regs = &ctlr->regs[TdmaOffset + nelem(ctlr->td)*3 + 16*RingCfg];
936 edev->port = (uintptr)ctlr->regs;
937 edev->irq = IRQether;
939 edev->attach = attach;
940 edev->shutdown = shutdown;
941 edev->promiscuous = prom;
942 edev->multicast = multi;
945 edev->maxmtu = Maxtu;
947 parseether(edev->ea, getethermac());
953 intrenable(edev->irq+0, interrupt0, edev, BUSUNKNOWN, edev->name);
954 intrenable(edev->irq+1, interrupt1, edev, BUSUNKNOWN, edev->name);
962 addethercard("genet", pnp);