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;
265 this driver causes the ethernet controller to stall the gisb bus
266 which causes other devices to fail.
270 static u32int *lastgenetregaddr;
271 static uintptr lastgenetregpc;
272 static ulong lastgenetregtime;
275 #define REG(x) *(logreg(&(x)))
281 lastgenetregtime = MACHP(0)->ticks;
282 lastgenetregpc = getcallerpc(&x);
283 lastgenetregaddr = x;
291 static u32int *regs = (u32int*)(VIRTIO + 0x9800);
296 regs[0x40/4] = (regs[0x40/4] & ~0x1F) | 9 | 0x40000000;
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]);
314 if((++ctr & 0xFF) != 0)
316 iprint("%d %#p @ %#p; "
317 "rx=(%.2ux %.2ux [%.2ux]); "
318 "tx=(%.2ux %.2ux %.2ux [%.2ux]); "
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));
335 interrupt0(Ureg*, void *arg)
338 Ctlr *ctlr = edev->ctlr;
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;
345 if(sts & ctlr->rx->intmask)
347 if(sts & ctlr->tx->intmask)
350 if(sts & (IrqMdioDone|IrqMdioError))
352 if(sts & (IrqLinkUp|IrqLinkDown))
357 interrupt1(Ureg*, void *arg)
360 Ctlr *ctlr = edev->ctlr;
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;
368 for(i = 1; i < nelem(ctlr->rx); i++)
369 if(sts & ctlr->rx[i].intmask)
370 wakeup(&ctlr->rx[i]);
372 for(i = 1; i < nelem(ctlr->tx); i++)
373 if(sts & ctlr->tx[i].intmask)
374 wakeup(&ctlr->tx[i]);
378 setdma(Desc *d, void *v)
380 u64int pa = PADDR(v);
382 REG(d->d[2]) = pa >> 32;
389 dmaflush(1, d->b->rp, Rbsz);
398 r->wp = REG(r->regs[RxWP]) & 0xFFFF;
401 REG(r->intregs[IntrMaskClr]) = r->intmask;
409 Ctlr *ctlr = edev->ctlr;
423 if(ctlr->rx->rp == ctlr->rx->wp){
424 sleep(ctlr->rx, rxdone, ctlr->rx);
427 d = &ctlr->rx->d[ctlr->rx->rp & ctlr->rx->m];
429 dmaflush(0, b->rp, Rbsz);
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)){
439 b->wp += (s & 0x0FFF0000) >> 16;
449 return ((r->wp+1) & r->m) != (r->cp & r->m);
456 Ctlr *ctlr = edev->ctlr;
469 if(!txavail(ctlr->tx)){
470 sleep(ctlr->avail, txavail, ctlr->tx);
473 if((b = qbread(edev->oq, 100000)) == nil)
475 d = &ctlr->tx->d[ctlr->tx->wp & ctlr->tx->m];
478 dmaflush(1, b->rp, BLEN(b));
480 REG(d->d[0]) = BLEN(b)<<16 | DmaTxQtag | DmaSOP | DmaEOP | DmaTxAppendCrc;
482 ctlr->tx->wp = (ctlr->tx->wp+1) & 0xFFFF;
483 REG(ctlr->tx->regs[TxWP]) = ctlr->tx->wp;
493 r->rp = REG(r->regs[TxRP]) & 0xFFFF;
497 REG(r->intregs[IntrMaskClr]) = r->intmask;
505 Ctlr *ctlr = edev->ctlr;
517 if(ctlr->tx->cp == ctlr->tx->rp){
519 sleep(ctlr->tx, txdone, ctlr->tx);
522 d = &ctlr->tx->d[ctlr->tx->cp & ctlr->tx->m];
527 ctlr->tx->cp = (ctlr->tx->cp+1) & 0xFFFF;
532 initring(Ring *ring, Desc *desc, int start, int size)
534 ring->d = &desc[start];
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;
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;
559 REG(ctlr->rx->regs[DmaCtrl]) &= ~(RxRingCfgMask<<1 | DmaCtrlEn);
560 REG(ctlr->tx->regs[DmaCtrl]) &= ~(TxRingCfgMask<<1 | DmaCtrlEn);
562 REG(ctlr->regs[UmacTxFlush]) = 1;
564 REG(ctlr->regs[UmacTxFlush]) = 0;
566 while((REG(ctlr->rx->regs[DmaStatus]) & DmaStatusDis) == 0)
568 while((REG(ctlr->tx->regs[DmaStatus]) & DmaStatusDis) == 0)
575 REG(ctlr->rx->regs[DmaCtrl]) |= DmaCtrlEn;
576 REG(ctlr->tx->regs[DmaCtrl]) |= DmaCtrlEn;
578 while(REG(ctlr->rx->regs[DmaStatus]) & DmaStatusDis)
580 while(REG(ctlr->tx->regs[DmaStatus]) & DmaStatusDis)
585 allocbufs(Ctlr *ctlr)
590 scratch = allocb(Rbsz);
591 memset(scratch->rp, 0xFF, Rbsz);
592 dmaflush(1, scratch->rp, Rbsz);
595 for(i = 0; i < nelem(ctlr->rd); i++){
596 ctlr->rd[i].d = &ctlr->regs[RdmaOffset + i*3];
597 replenish(&ctlr->rd[i]);
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;
612 for(i = 0; i < nelem(ctlr->rd); i++){
613 if(ctlr->rd[i].b != nil){
614 freeb(ctlr->rd[i].b);
618 for(i = 0; i < nelem(ctlr->td); i++){
619 if(ctlr->td[i].b != nil){
620 freeb(ctlr->td[i].b);
627 initrings(Ctlr *ctlr)
629 u32int rcfg, tcfg, dmapri[3];
632 ctlr->rx->intregs = &ctlr->regs[Intrl0];
633 ctlr->rx->intmask = IrqRxDmaDone;
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;
643 assert(rcfg && (rcfg & ~RxRingCfgMask) == 0);
645 ctlr->tx->intregs = &ctlr->regs[Intrl0];
646 ctlr->tx->intmask = IrqTxDmaDone;
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;
656 assert(tcfg && (tcfg & ~TxRingCfgMask) == 0);
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);
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);
667 // set dma timeout to 50µs
668 REG(ctlr->rx->regs[RdmaTimeout0 + ctlr->rx[i].num]) = ((50*1000 + 8191)/8192);
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);
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);
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];
688 REG(ctlr->rx->regs[RingCfg]) = rcfg;
689 REG(ctlr->tx->regs[RingCfg]) = tcfg;
691 REG(ctlr->rx->regs[DmaCtrl]) |= rcfg<<1;
692 REG(ctlr->tx->regs[DmaCtrl]) |= tcfg<<1;
696 umaccmd(Ctlr *ctlr, u32int set, u32int clr)
699 REG(ctlr->regs[UmacCmd]) = (REG(ctlr->regs[UmacCmd]) & ~clr) | set;
709 r = REG(ctlr->regs[SysRbufFlushCtrl]);
710 REG(ctlr->regs[SysRbufFlushCtrl]) = r | 2;
712 REG(ctlr->regs[SysRbufFlushCtrl]) = r & ~2;
716 REG(ctlr->regs[SysRbufFlushCtrl]) = 0;
719 REG(ctlr->regs[UmacCmd]) = 0;
720 REG(ctlr->regs[UmacCmd]) = CmdSwReset | CmdLclLoopEn;
722 REG(ctlr->regs[UmacCmd]) = 0;
726 setmac(Ctlr *ctlr, uchar *ea)
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];
737 REG(ctlr->regs[HfbCtlr]) = 0;
738 REG(ctlr->regs[HfbFltEnable]) = 0;
739 REG(ctlr->regs[HfbFltEnable+1]) = 0;
741 for(i = 0; i < 8; i++)
742 REG(ctlr->rx->regs[RdmaIndex2Ring0+i]) = 0;
744 for(i = 0; i < 48/4; i++)
745 REG(ctlr->regs[HfbFltLen + i]) = 0;
747 for(i = 0; i < 48*128; i++)
748 REG(ctlr->regs[HfbOffset + i]) = 0;
755 REG(ctlr->regs[Intrl0 + IntrMaskClr]) = (IrqMdioDone|IrqMdioError);
756 return (REG(ctlr->regs[MdioCmd]) & MdioStartBusy) == 0;
762 REG(ctlr->regs[MdioCmd]) |= MdioStartBusy;
763 while(REG(ctlr->regs[MdioCmd]) & MdioStartBusy)
764 tsleep(ctlr->mii, mdiodone, ctlr, 10);
769 mdiow(Mii* mii, int phy, int addr, int data)
771 Ctlr *ctlr = mii->ctlr;
773 if(phy > MdioPhyMask)
775 addr &= MdioAddrMask;
776 REG(ctlr->regs[MdioCmd]) = MdioWrite
777 | (phy << MdioPhyShift) | (addr << MdioAddrShift) | (data & 0xFFFF);
778 return mdiowait(ctlr);
782 mdior(Mii* mii, int phy, int addr)
784 Ctlr *ctlr = mii->ctlr;
786 if(phy > MdioPhyMask)
788 addr &= MdioAddrMask;
789 REG(ctlr->regs[MdioCmd]) = MdioRead
790 | (phy << MdioPhyShift) | (addr << MdioAddrShift);
791 if(mdiowait(ctlr) < 0)
793 if(REG(ctlr->regs[MdioCmd]) & MdioReadFail)
795 return REG(ctlr->regs[MdioCmd]) & 0xFFFF;
799 bcmshdr(Mii *mii, int reg)
801 miimiw(mii, 0x1C, (reg & 0x1F) << 10);
802 return miimir(mii, 0x1C) & 0x3FF;
806 bcmshdw(Mii *mii, int reg, int dat)
808 return miimiw(mii, 0x1C, 0x8000 | (reg & 0x1F) << 10 | (dat & 0x3FF));
815 REG(ctlr->regs[Intrl0 + IntrMaskClr]) = IrqLinkUp|IrqLinkDown;
823 Ctlr *ctlr = edev->ctlr;
836 tsleep(ctlr->link, linkevent, ctlr, 1000);
837 miistatus(ctlr->mii);
838 phy = ctlr->mii->curphy;
839 if(phy == nil || phy->link == link)
843 u32int cmd = CmdRxEn|CmdTxEn;
845 case 1000: cmd |= CmdSpeed1000; break;
846 case 100: cmd |= CmdSpeed100; break;
847 case 10: cmd |= CmdSpeed10; break;
852 cmd |= CmdRxPauseIgn;
854 cmd |= CmdTxPauseIgn;
856 REG(ctlr->regs[ExtRgmiiOobCtrl]) = (REG(ctlr->regs[ExtRgmiiOobCtrl]) & ~OobDisable) | RgmiiLink;
857 umaccmd(ctlr, cmd, CmdSpeedMask|CmdHdEn|CmdRxPauseIgn|CmdTxPauseIgn);
859 edev->mbps = phy->speed;
862 // print("#l%d: link %d speed %d\n", edev->ctlrno, edev->link, edev->mbps);
867 setmdfaddr(Ctlr *ctlr, int i, uchar *ea)
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];
874 rxmode(Ether *edev, int prom)
876 Ctlr *ctlr = edev->ctlr;
880 if(prom || edev->nmaddr > 16-2){
881 REG(ctlr->regs[UmacMdfCtrl]) = 0;
882 umaccmd(ctlr, CmdProm, 0);
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);
894 shutdown(Ether *edev)
896 Ctlr *ctlr = edev->ctlr;
905 Ctlr *ctlr = edev->ctlr;
913 print("#l%d: %s\n", edev->ctlrno, up->errstr);
921 REG(ctlr->regs[UmacMibCtrl]) = MibResetRx | MibResetTx | MibResetRunt;
922 REG(ctlr->regs[UmacMibCtrl]) = 0;
925 REG(ctlr->regs[UmacMpdCtrl]) &= ~(MpdPwEn|MpdEn);
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;
933 REG(ctlr->regs[UmacMaxFrameLen]) = Maxtu;
935 REG(ctlr->regs[RbufTbufSizeCtrl]) = 1;
937 REG(ctlr->regs[TbufCtrl]) &= ~(Rbuf64En);
938 REG(ctlr->regs[RbufCtrl]) &= ~(Rbuf64En|RbufAlign2B);
939 REG(ctlr->regs[RbufChkCtrl]) &= ~(RbufChkRxChkEn|RbufChkSkipFcs);
945 setmac(ctlr, edev->ea);
949 REG(ctlr->regs[SysPortCtrl]) = PortModeExtGphy;
950 REG(ctlr->regs[ExtRgmiiOobCtrl]) |= RgmiiModeEn | IdModeDis;
952 ctlr->mii->ctlr = ctlr;
953 ctlr->mii->mir = mdior;
954 ctlr->mii->miw = mdiow;
957 if(ctlr->mii->curphy == nil)
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);
966 switch(ctlr->mii->curphy->id){
967 case 0x600d84a2: /* BCM54312PE */
968 /* mask interrupts */
969 miimiw(ctlr->mii, 0x10, miimir(ctlr->mii, 0x10) | 0x1000);
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);
977 bcmshdw(ctlr->mii, 0x09, bcmshdr(ctlr->mii, 0x09) | 0x0010);
978 bcmshdw(ctlr->mii, 0x0d, 3<<0 | 0<<4);
982 /* don't advertise EEE */
983 miimmdw(ctlr->mii, 7, 60, 0);
985 miiane(ctlr->mii, ~0, AnaAP|AnaP, ~0);
993 kproc("genet-recv", recvproc, edev);
994 kproc("genet-send", sendproc, edev);
995 kproc("genet-free", freeproc, edev);
996 kproc("genet-link", linkproc, edev);
1003 prom(void *arg, int on)
1010 multi(void *arg, uchar*, int)
1013 rxmode(edev, edev->prom > 0);
1017 ctl(Ether *edev, void *data, long len)
1019 Ctlr *ctlr = edev->ctlr;
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);
1038 static Ctlr ctlr[1];
1040 if(ctlr->regs != nil)
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];
1047 edev->port = (uintptr)ctlr->regs;
1048 edev->irq = IRQether;
1050 edev->attach = attach;
1051 edev->shutdown = shutdown;
1052 edev->promiscuous = prom;
1053 edev->multicast = multi;
1057 edev->maxmtu = Maxtu;
1059 parseether(edev->ea, getethermac());
1065 intrenable(edev->irq+0, interrupt0, edev, BUSUNKNOWN, edev->name);
1066 intrenable(edev->irq+1, interrupt1, edev, BUSUNKNOWN, edev->name);
1072 ethergenetlink(void)
1074 addethercard("genet", pnp);