1.1new file mode 100644
1.2--- /dev/null
1.3+++ b/sys/src/9/bcm64/ethergenet.c
1.4@@ -0,0 +1,1075 @@
1.5+#include "u.h"
1.6+#include "../port/lib.h"
1.7+#include "mem.h"
1.8+#include "dat.h"
1.9+#include "fns.h"
1.10+#include "io.h"
1.11+#include "../port/netif.h"
1.12+#include "../port/etherif.h"
1.13+#include "../port/ethermii.h"
1.14+
1.15+enum
1.16+{
1.17+ Rbsz = 2048,
1.18+ Maxtu = 1536,
1.19+
1.20+ DmaOWN = 0x8000,
1.21+ DmaSOP = 0x2000,
1.22+ DmaEOP = 0x4000,
1.23+ DmaRxLg = 0x10,
1.24+ DmaRxNo = 0x08,
1.25+ DmaRxErr = 0x04,
1.26+ DmaRxCrc = 0x02,
1.27+ DmaRxOv = 0x01,
1.28+ DmaRxErrors = DmaRxLg|DmaRxNo|DmaRxErr|DmaRxCrc|DmaRxOv,
1.29+
1.30+ DmaTxQtag = 0x1F80,
1.31+ DmaTxUnderrun = 0x0200,
1.32+ DmaTxAppendCrc = 0x0040,
1.33+ DmaTxOwCrc = 0x0020,
1.34+ DmaTxDoCsum = 0x0010,
1.35+
1.36+ /* Ctlr->regs */
1.37+ SysRevision = 0x00/4,
1.38+ SysPortCtrl = 0x04/4,
1.39+ PortModeIntEphy = 0,
1.40+ PortModeIntGphy = 1,
1.41+ PortModeExtEphy = 2,
1.42+ PortModeExtGphy = 3,
1.43+ PortModeExtRvmii50 = 4,
1.44+ PortModeExtRvmii25 = 16 | 4,
1.45+ LedActSourceMac = 1 << 9,
1.46+
1.47+ SysRbufFlushCtrl = 0x08/4,
1.48+ SysTbufFlushCtrl = 0x0C/4,
1.49+
1.50+ ExtRgmiiOobCtrl = 0x8C/4,
1.51+ RgmiiLink = 1 << 4,
1.52+ OobDisable = 1 << 5,
1.53+ RgmiiModeEn = 1 << 6,
1.54+ IdModeDis = 1 << 16,
1.55+
1.56+ Intrl0 = 0x200/4,
1.57+ IrqScb = 1 << 0,
1.58+ IrqEphy = 1 << 1,
1.59+ IrqPhyDetR = 1 << 2,
1.60+ IrqPhyDetF = 1 << 3,
1.61+ IrqLinkUp = 1 << 4,
1.62+ IrqLinkDown = 1 << 5,
1.63+ IrqUmac = 1 << 6,
1.64+ IrqUmacTsv = 1 << 7,
1.65+ IrqTbufUnderrun = 1 << 8,
1.66+ IrqRbufOverflow = 1 << 9,
1.67+ IrqHfbSm = 1 << 10,
1.68+ IrqHfbMm = 1 << 11,
1.69+ IrqMpdR = 1 << 12,
1.70+ IrqRxDmaDone = 1 << 13,
1.71+ IrqRxDmaPDone = 1 << 14,
1.72+ IrqRxDmaBDone = 1 << 15,
1.73+ IrqTxDmaDone = 1 << 16,
1.74+ IrqTxDmaPDone = 1 << 17,
1.75+ IrqTxDmaBDone = 1 << 18,
1.76+ IrqMdioDone = 1 << 23,
1.77+ IrqMdioError = 1 << 24,
1.78+ Intrl1 = 0x240/4,
1.79+ /* Intrl0/1 + ... */
1.80+ IntrSts = 0x00/4,
1.81+ IntrSet = 0x04/4,
1.82+ IntrClr = 0x08/4,
1.83+ IntrMaskSts = 0x0C/4,
1.84+ IntrMaskSet = 0x10/4,
1.85+ IntrMaskClr = 0x14/4,
1.86+
1.87+ RbufCtrl = 0x300/4,
1.88+ Rbuf64En = 1 << 0,
1.89+ RbufAlign2B = 1 << 1,
1.90+ RbufBadDis = 1 << 2,
1.91+
1.92+ RbufChkCtrl = 0x314/4,
1.93+ RbufChkRxChkEn = 1 << 0,
1.94+ RbufChkSkipFcs = 1 << 4,
1.95+
1.96+ RbufOvflCnt = 0x394/4,
1.97+ RbufErrCnt = 0x398/4,
1.98+
1.99+ RbufEnergyCtrl = 0x39c/4,
1.100+ RbufEeeEn = 1 << 0,
1.101+ RbufPmEn = 1 << 1,
1.102+
1.103+ RbufTbufSizeCtrl= 0x3b4/4,
1.104+
1.105+ TbufCtrl = 0x600/4,
1.106+ TbufBpMc = 0x60C/4,
1.107+ TbufEnergyCtrl = 0x614/4,
1.108+
1.109+ UmacCmd = 0x808/4,
1.110+ CmdTxEn = 1 << 0,
1.111+ CmdRxEn = 1 << 1,
1.112+ CmdSpeed10 = 0 << 2,
1.113+ CmdSpeed100 = 1 << 2,
1.114+ CmdSpeed1000 = 2 << 2,
1.115+ CmdSpeedMask = 3 << 2,
1.116+ CmdProm = 1 << 4,
1.117+ CmdPadEn = 1 << 5,
1.118+ CmdCrcFwd = 1 << 6,
1.119+ CmdPauseFwd = 1 << 7,
1.120+ CmdRxPauseIgn = 1 << 8,
1.121+ CmdTxAddrIn = 1 << 9,
1.122+ CmdHdEn = 1 << 10,
1.123+ CmdSwReset = 1 << 13,
1.124+ CmdLclLoopEn = 1 << 15,
1.125+ CmdAutoConfig = 1 << 22,
1.126+ CmdCntlFrmEn = 1 << 23,
1.127+ CmdNoLenChk = 1 << 24,
1.128+ CmdRmtLoopEn = 1 << 25,
1.129+ CmdPrblEn = 1 << 27,
1.130+ CmdTxPauseIgn = 1 << 28,
1.131+ CmdTxRxEn = 1 << 29,
1.132+ CmdRuntFilterDis= 1 << 30,
1.133+
1.134+ UmacMac0 = 0x80C/4,
1.135+ UmacMac1 = 0x810/4,
1.136+ UmacMaxFrameLen = 0x814/4,
1.137+
1.138+ UmacEeeCtrl = 0x864/4,
1.139+ UmacEeeEn = 1<<3,
1.140+
1.141+ UmacEeeLpiTimer = 0x868/4,
1.142+ UmacEeeWakeTimer= 0x86C/4,
1.143+ UmacEeeRefCount = 0x870/4,
1.144+ EeeRefCountMask = 0xFFFF,
1.145+
1.146+ UmacTxFlush = 0xb34/4,
1.147+
1.148+ UmacMibCtrl = 0xd80/4,
1.149+ MibResetRx = 1 << 0,
1.150+ MibResetRunt = 1 << 1,
1.151+ MibResetTx = 1 << 2,
1.152+
1.153+ MdioCmd = 0xe14/4,
1.154+ MdioStartBusy = 1 << 29,
1.155+ MdioReadFail = 1 << 28,
1.156+ MdioRead = 2 << 26,
1.157+ MdioWrite = 1 << 26,
1.158+ MdioPhyShift = 21,
1.159+ MdioPhyMask = 0x1F,
1.160+ MdioAddrShift = 16,
1.161+ MdioAddrMask = 0x1F,
1.162+
1.163+ UmacMpdCtrl = 0xe20/4,
1.164+ MpdEn = 1 << 0,
1.165+ MpdPwEn = 1 << 27,
1.166+
1.167+ UmacMdfCtrl = 0xe50/4,
1.168+ UmacMdfAddr0 = 0xe54/4,
1.169+
1.170+ RdmaOffset = 0x2000/4,
1.171+ TdmaOffset = 0x4000/4,
1.172+ HfbOffset = 0x8000/4,
1.173+
1.174+ HfbCtlr = 0xFC00/4,
1.175+ HfbFltEnable = 0xFC04/4,
1.176+ HfbFltLen = 0xFC1C/4,
1.177+
1.178+ /* common Ring->regs */
1.179+ RdmaWP = 0x00/4,
1.180+ TdmaRP = 0x00/4,
1.181+ RxWP = 0x08/4,
1.182+ TxRP = 0x08/4,
1.183+ TxWP = 0x0C/4,
1.184+ RxRP = 0x0C/4,
1.185+ DmaRingBufSize = 0x10/4,
1.186+ DmaStart = 0x14/4,
1.187+ DmaEnd = 0x1C/4,
1.188+ DmaDoneThresh = 0x24/4,
1.189+ TdmaFlowPeriod = 0x28/4,
1.190+ RdmaXonXoffThresh=0x28/4,
1.191+ TdmaWP = 0x2C/4,
1.192+ RdmaRP = 0x2C/4,
1.193+
1.194+ /*
1.195+ * reg offsets only for RING16
1.196+ * ctlr->rx->regs / ctlr->tx->regs
1.197+ */
1.198+ RingCfg = 0x40/4,
1.199+ RxRingCfgMask = 0x10000,
1.200+ TxRingCfgMask = 0x1000F,
1.201+
1.202+ DmaCtrl = 0x44/4,
1.203+ DmaCtrlEn = 1 << 0,
1.204+ DmaStatus = 0x48/4,
1.205+ DmaStatusDis = 1 << 0,
1.206+ DmaScbBurstSize = 0x4C/4,
1.207+
1.208+ TdmaArbCtrl = 0x6C/4,
1.209+ TdmaPriority0 = 0x70/4,
1.210+ TdmaPriority1 = 0x74/4,
1.211+ TdmaPriority2 = 0x78/4,
1.212+
1.213+ RdmaTimeout0 = 0x6C/4,
1.214+ RdmaIndex2Ring0 = 0xB0/4,
1.215+};
1.216+
1.217+typedef struct Desc Desc;
1.218+typedef struct Ring Ring;
1.219+typedef struct Ctlr Ctlr;
1.220+
1.221+struct Desc
1.222+{
1.223+ u32int *d; /* hw descriptor */
1.224+ Block *b;
1.225+};
1.226+
1.227+struct Ring
1.228+{
1.229+ Rendez;
1.230+ u32int *regs;
1.231+ u32int *intregs;
1.232+ u32int intmask;
1.233+
1.234+ Desc *d;
1.235+
1.236+ u32int m;
1.237+ u32int cp;
1.238+ u32int rp;
1.239+ u32int wp;
1.240+
1.241+ int num;
1.242+};
1.243+
1.244+struct Ctlr
1.245+{
1.246+ Lock;
1.247+ u32int *regs;
1.248+
1.249+ Desc rd[256];
1.250+ Desc td[256];
1.251+
1.252+ Ring rx[1+0];
1.253+ Ring tx[1+0];
1.254+
1.255+ Rendez avail[1];
1.256+ Rendez link[1];
1.257+ struct {
1.258+ Mii;
1.259+ Rendez;
1.260+ } mii[1];
1.261+
1.262+ QLock;
1.263+ char attached;
1.264+};
1.265+
1.266+static Block *scratch;
1.267+
1.268+/*
1.269+this driver causes the ethernet controller to stall the gisb bus
1.270+which causes other devices to fail.
1.271+*/
1.272+#ifdef XXXDEBUG
1.273+
1.274+static u32int *lastgenetregaddr;
1.275+static uintptr lastgenetregpc;
1.276+static ulong lastgenetregtime;
1.277+static Ctlr *xxx;
1.278+
1.279+#define REG(x) *(logreg(&(x)))
1.280+
1.281+static u32int*
1.282+logreg(u32int *x)
1.283+{
1.284+ coherence();
1.285+ lastgenetregtime = MACHP(0)->ticks;
1.286+ lastgenetregpc = getcallerpc(&x);
1.287+ lastgenetregaddr = x;
1.288+ return x;
1.289+}
1.290+
1.291+static void
1.292+dumparb(void)
1.293+{
1.294+ static int once;
1.295+ static u32int *regs = (u32int*)(VIRTIO + 0x9800);
1.296+
1.297+ if(!once){
1.298+ once = 1;
1.299+ regs[0x00/4] |= 1;
1.300+ regs[0x40/4] = (regs[0x40/4] & ~0x1F) | 9 | 0x40000000;
1.301+ }
1.302+ iprint("arb %.8ux %.8ux %.8ux %.8ux; "
1.303+ "%.8ux %.8ux %.8ux %.8ux; "
1.304+ "%.8ux %.8ux %.8ux\n",
1.305+ regs[0x40/4], regs[0x44/4], regs[0x48/4], regs[0x4C/4],
1.306+ regs[0x50/4], regs[0x54/4], regs[0x58/4], regs[0x5C/4],
1.307+ regs[0x60/4], regs[0x64/4], regs[0x68/4]);
1.308+}
1.309+
1.310+void
1.311+genetclock(void)
1.312+{
1.313+ static int ctr;
1.314+
1.315+ if(xxx == nil)
1.316+ return;
1.317+
1.318+ if((++ctr & 0xFF) != 0)
1.319+ return;
1.320+ iprint("%d %#p @ %#p; "
1.321+ "rx=(%.2ux %.2ux [%.2ux]); "
1.322+ "tx=(%.2ux %.2ux %.2ux [%.2ux]); "
1.323+ "(%lud)\n",
1.324+ m->machno,
1.325+ lastgenetregaddr, lastgenetregpc,
1.326+ xxx->rx->rp, xxx->rx->wp, xxx->rx->wp - xxx->rx->rp,
1.327+ xxx->tx->cp, xxx->tx->rp, xxx->tx->wp, xxx->tx->wp - xxx->tx->rp,
1.328+ tk2ms(MACHP(0)->ticks-lastgenetregtime));
1.329+ dumparb();
1.330+}
1.331+
1.332+#else
1.333+
1.334+#define REG(x) (x)
1.335+
1.336+#endif
1.337+
1.338+static void
1.339+interrupt0(Ureg*, void *arg)
1.340+{
1.341+ Ether *edev = arg;
1.342+ Ctlr *ctlr = edev->ctlr;
1.343+ u32int sts;
1.344+
1.345+ sts = REG(ctlr->regs[Intrl0 + IntrSts]) & ~REG(ctlr->regs[Intrl0 + IntrMaskSts]);
1.346+ REG(ctlr->regs[Intrl0 + IntrClr]) = sts;
1.347+ REG(ctlr->regs[Intrl0 + IntrMaskSet]) = sts;
1.348+
1.349+ if(sts & ctlr->rx->intmask)
1.350+ wakeup(ctlr->rx);
1.351+ if(sts & ctlr->tx->intmask)
1.352+ wakeup(ctlr->tx);
1.353+
1.354+ if(sts & (IrqMdioDone|IrqMdioError))
1.355+ wakeup(ctlr->mii);
1.356+ if(sts & (IrqLinkUp|IrqLinkDown))
1.357+ wakeup(ctlr->link);
1.358+}
1.359+
1.360+static void
1.361+interrupt1(Ureg*, void *arg)
1.362+{
1.363+ Ether *edev = arg;
1.364+ Ctlr *ctlr = edev->ctlr;
1.365+ u32int sts;
1.366+ int i;
1.367+
1.368+ sts = REG(ctlr->regs[Intrl1 + IntrSts]) & ~REG(ctlr->regs[Intrl1 + IntrMaskSts]);
1.369+ REG(ctlr->regs[Intrl1 + IntrClr]) = sts;
1.370+ REG(ctlr->regs[Intrl1 + IntrMaskSet]) = sts;
1.371+
1.372+ for(i = 1; i < nelem(ctlr->rx); i++)
1.373+ if(sts & ctlr->rx[i].intmask)
1.374+ wakeup(&ctlr->rx[i]);
1.375+
1.376+ for(i = 1; i < nelem(ctlr->tx); i++)
1.377+ if(sts & ctlr->tx[i].intmask)
1.378+ wakeup(&ctlr->tx[i]);
1.379+}
1.380+
1.381+static void
1.382+setdma(Desc *d, void *v)
1.383+{
1.384+ u64int pa = PADDR(v);
1.385+ REG(d->d[1]) = pa;
1.386+ REG(d->d[2]) = pa >> 32;
1.387+}
1.388+
1.389+static void
1.390+replenish(Desc *d)
1.391+{
1.392+ d->b = allocb(Rbsz);
1.393+ dmaflush(1, d->b->rp, Rbsz);
1.394+ setdma(d, d->b->rp);
1.395+}
1.396+
1.397+static int
1.398+rxdone(void *arg)
1.399+{
1.400+ Ring *r = arg;
1.401+
1.402+ r->wp = REG(r->regs[RxWP]) & 0xFFFF;
1.403+ if(r->rp != r->wp)
1.404+ return 1;
1.405+ REG(r->intregs[IntrMaskClr]) = r->intmask;
1.406+ return 0;
1.407+}
1.408+
1.409+static void
1.410+recvproc(void *arg)
1.411+{
1.412+ Ether *edev = arg;
1.413+ Ctlr *ctlr = edev->ctlr;
1.414+ Desc *d;
1.415+ Block *b;
1.416+ u32int s;
1.417+
1.418+#ifdef XXXDEBUG
1.419+ procwired(up, 1);
1.420+ sched();
1.421+#endif
1.422+
1.423+ while(waserror())
1.424+ ;
1.425+
1.426+ for(;;){
1.427+ if(ctlr->rx->rp == ctlr->rx->wp){
1.428+ sleep(ctlr->rx, rxdone, ctlr->rx);
1.429+ continue;
1.430+ }
1.431+ d = &ctlr->rx->d[ctlr->rx->rp & ctlr->rx->m];
1.432+ b = d->b;
1.433+ dmaflush(0, b->rp, Rbsz);
1.434+ s = REG(d->d[0]);
1.435+ replenish(d);
1.436+ coherence();
1.437+ ctlr->rx->rp = (ctlr->rx->rp + 1) & 0xFFFF;
1.438+ REG(ctlr->rx->regs[RxRP]) = ctlr->rx->rp;
1.439+ if((s & (DmaSOP|DmaEOP|DmaRxErrors)) != (DmaSOP|DmaEOP)){
1.440+ freeb(b);
1.441+ continue;
1.442+ }
1.443+ b->wp += (s & 0x0FFF0000) >> 16;
1.444+ etheriq(edev, b);
1.445+ }
1.446+}
1.447+
1.448+static int
1.449+txavail(void *arg)
1.450+{
1.451+ Ring *r = arg;
1.452+
1.453+ return ((r->wp+1) & r->m) != (r->cp & r->m);
1.454+}
1.455+
1.456+static void
1.457+sendproc(void *arg)
1.458+{
1.459+ Ether *edev = arg;
1.460+ Ctlr *ctlr = edev->ctlr;
1.461+ Desc *d;
1.462+ Block *b;
1.463+
1.464+#ifdef XXXDEBUG
1.465+ procwired(up, 1);
1.466+ sched();
1.467+#endif
1.468+
1.469+ while(waserror())
1.470+ ;
1.471+
1.472+ for(;;){
1.473+ if(!txavail(ctlr->tx)){
1.474+ sleep(ctlr->avail, txavail, ctlr->tx);
1.475+ continue;
1.476+ }
1.477+ if((b = qbread(edev->oq, 100000)) == nil)
1.478+ break;
1.479+ d = &ctlr->tx->d[ctlr->tx->wp & ctlr->tx->m];
1.480+ assert(d->b == nil);
1.481+ d->b = b;
1.482+ dmaflush(1, b->rp, BLEN(b));
1.483+ setdma(d, b->rp);
1.484+ REG(d->d[0]) = BLEN(b)<<16 | DmaTxQtag | DmaSOP | DmaEOP | DmaTxAppendCrc;
1.485+ coherence();
1.486+ ctlr->tx->wp = (ctlr->tx->wp+1) & 0xFFFF;
1.487+ REG(ctlr->tx->regs[TxWP]) = ctlr->tx->wp;
1.488+ }
1.489+}
1.490+
1.491+static int
1.492+txdone(void *arg)
1.493+{
1.494+ Ring *r = arg;
1.495+
1.496+ if(r->cp != r->wp){
1.497+ r->rp = REG(r->regs[TxRP]) & 0xFFFF;
1.498+ if(r->cp != r->rp)
1.499+ return 1;
1.500+ }
1.501+ REG(r->intregs[IntrMaskClr]) = r->intmask;
1.502+ return 0;
1.503+}
1.504+
1.505+static void
1.506+freeproc(void *arg)
1.507+{
1.508+ Ether *edev = arg;
1.509+ Ctlr *ctlr = edev->ctlr;
1.510+ Desc *d;
1.511+
1.512+#ifdef XXXDEBUG
1.513+ procwired(up, 1);
1.514+ sched();
1.515+#endif
1.516+
1.517+ while(waserror())
1.518+ ;
1.519+
1.520+ for(;;){
1.521+ if(ctlr->tx->cp == ctlr->tx->rp){
1.522+ wakeup(ctlr->avail);
1.523+ sleep(ctlr->tx, txdone, ctlr->tx);
1.524+ continue;
1.525+ }
1.526+ d = &ctlr->tx->d[ctlr->tx->cp & ctlr->tx->m];
1.527+ assert(d->b != nil);
1.528+ freeb(d->b);
1.529+ d->b = nil;
1.530+ coherence();
1.531+ ctlr->tx->cp = (ctlr->tx->cp+1) & 0xFFFF;
1.532+ }
1.533+}
1.534+
1.535+static void
1.536+initring(Ring *ring, Desc *desc, int start, int size)
1.537+{
1.538+ ring->d = &desc[start];
1.539+ ring->m = size - 1;
1.540+ ring->cp = ring->rp = ring->wp = 0;
1.541+ REG(ring->regs[RxWP]) = 0;
1.542+ REG(ring->regs[RxRP]) = 0;
1.543+ REG(ring->regs[DmaStart]) = start*3;
1.544+ REG(ring->regs[DmaEnd]) = (start+size)*3 - 1;
1.545+ REG(ring->regs[RdmaWP]) = start*3;
1.546+ REG(ring->regs[RdmaRP]) = start*3;
1.547+ REG(ring->regs[DmaRingBufSize]) = (size << 16) | Rbsz;
1.548+ REG(ring->regs[DmaDoneThresh]) = 1;
1.549+}
1.550+
1.551+static void
1.552+introff(Ctlr *ctlr)
1.553+{
1.554+ REG(ctlr->regs[Intrl0 + IntrMaskSet]) = -1;
1.555+ REG(ctlr->regs[Intrl0 + IntrClr]) = -1;
1.556+ REG(ctlr->regs[Intrl1 + IntrMaskSet]) = -1;
1.557+ REG(ctlr->regs[Intrl1 + IntrClr]) = -1;
1.558+}
1.559+
1.560+static void
1.561+dmaoff(Ctlr *ctlr)
1.562+{
1.563+ REG(ctlr->rx->regs[DmaCtrl]) &= ~(RxRingCfgMask<<1 | DmaCtrlEn);
1.564+ REG(ctlr->tx->regs[DmaCtrl]) &= ~(TxRingCfgMask<<1 | DmaCtrlEn);
1.565+
1.566+ REG(ctlr->regs[UmacTxFlush]) = 1;
1.567+ microdelay(10);
1.568+ REG(ctlr->regs[UmacTxFlush]) = 0;
1.569+
1.570+ while((REG(ctlr->rx->regs[DmaStatus]) & DmaStatusDis) == 0)
1.571+ microdelay(10);
1.572+ while((REG(ctlr->tx->regs[DmaStatus]) & DmaStatusDis) == 0)
1.573+ microdelay(10);
1.574+}
1.575+
1.576+static void
1.577+dmaon(Ctlr *ctlr)
1.578+{
1.579+ REG(ctlr->rx->regs[DmaCtrl]) |= DmaCtrlEn;
1.580+ REG(ctlr->tx->regs[DmaCtrl]) |= DmaCtrlEn;
1.581+
1.582+ while(REG(ctlr->rx->regs[DmaStatus]) & DmaStatusDis)
1.583+ microdelay(10);
1.584+ while(REG(ctlr->tx->regs[DmaStatus]) & DmaStatusDis)
1.585+ microdelay(10);
1.586+}
1.587+
1.588+static void
1.589+allocbufs(Ctlr *ctlr)
1.590+{
1.591+ int i;
1.592+
1.593+ if(scratch == nil){
1.594+ scratch = allocb(Rbsz);
1.595+ memset(scratch->rp, 0xFF, Rbsz);
1.596+ dmaflush(1, scratch->rp, Rbsz);
1.597+ }
1.598+
1.599+ for(i = 0; i < nelem(ctlr->rd); i++){
1.600+ ctlr->rd[i].d = &ctlr->regs[RdmaOffset + i*3];
1.601+ replenish(&ctlr->rd[i]);
1.602+ }
1.603+
1.604+ for(i = 0; i < nelem(ctlr->td); i++){
1.605+ ctlr->td[i].d = &ctlr->regs[TdmaOffset + i*3];
1.606+ setdma(&ctlr->td[i], scratch->rp);
1.607+ REG(ctlr->td[i].d[0]) = DmaTxUnderrun;
1.608+ }
1.609+}
1.610+
1.611+static void
1.612+freebufs(Ctlr *ctlr)
1.613+{
1.614+ int i;
1.615+
1.616+ for(i = 0; i < nelem(ctlr->rd); i++){
1.617+ if(ctlr->rd[i].b != nil){
1.618+ freeb(ctlr->rd[i].b);
1.619+ ctlr->rd[i].b = nil;
1.620+ }
1.621+ }
1.622+ for(i = 0; i < nelem(ctlr->td); i++){
1.623+ if(ctlr->td[i].b != nil){
1.624+ freeb(ctlr->td[i].b);
1.625+ ctlr->td[i].b = nil;
1.626+ }
1.627+ }
1.628+}
1.629+
1.630+static void
1.631+initrings(Ctlr *ctlr)
1.632+{
1.633+ u32int rcfg, tcfg, dmapri[3];
1.634+ int i;
1.635+
1.636+ ctlr->rx->intregs = &ctlr->regs[Intrl0];
1.637+ ctlr->rx->intmask = IrqRxDmaDone;
1.638+ ctlr->rx->num = 16;
1.639+ rcfg = 1<<16;
1.640+ for(i = 1; i < nelem(ctlr->rx); i++){
1.641+ ctlr->rx[i].regs = &ctlr->regs[RdmaOffset + nelem(ctlr->rd)*3 + (i-1)*RingCfg];
1.642+ ctlr->rx[i].intregs = &ctlr->regs[Intrl1];
1.643+ ctlr->rx[i].intmask = 0x10000 << (i - 1);
1.644+ ctlr->rx[i].num = i - 1;
1.645+ rcfg |= 1<<(i-1);
1.646+ }
1.647+ assert(rcfg && (rcfg & ~RxRingCfgMask) == 0);
1.648+
1.649+ ctlr->tx->intregs = &ctlr->regs[Intrl0];
1.650+ ctlr->tx->intmask = IrqTxDmaDone;
1.651+ ctlr->tx->num = 16;
1.652+ tcfg = 1<<16;
1.653+ for(i = 1; i < nelem(ctlr->tx); i++){
1.654+ ctlr->tx[i].regs = &ctlr->regs[TdmaOffset + nelem(ctlr->td)*3 + (i-1)*RingCfg];
1.655+ ctlr->tx[i].intregs = &ctlr->regs[Intrl1];
1.656+ ctlr->tx[i].intmask = 1 << (i - 1);
1.657+ ctlr->tx[i].num = i - 1;
1.658+ tcfg |= 1<<(i-1);
1.659+ }
1.660+ assert(tcfg && (tcfg & ~TxRingCfgMask) == 0);
1.661+
1.662+ REG(ctlr->rx->regs[DmaScbBurstSize]) = 0x08;
1.663+ for(i = 1; i < nelem(ctlr->rx); i++)
1.664+ initring(&ctlr->rx[i], ctlr->rd, (i-1)*32, 32);
1.665+ initring(ctlr->rx, ctlr->rd, (i-1)*32, nelem(ctlr->rd) - (i-1)*32);
1.666+
1.667+ for(i = 0; i < nelem(ctlr->rx); i++){
1.668+ REG(ctlr->rx[i].regs[DmaDoneThresh]) = 1;
1.669+ REG(ctlr->rx[i].regs[RdmaXonXoffThresh]) = (5 << 16) | ((ctlr->rx[i].m+1) >> 4);
1.670+
1.671+ // set dma timeout to 50µs
1.672+ REG(ctlr->rx->regs[RdmaTimeout0 + ctlr->rx[i].num]) = ((50*1000 + 8191)/8192);
1.673+ }
1.674+
1.675+ REG(ctlr->tx->regs[DmaScbBurstSize]) = 0x08;
1.676+ for(i = 1; i < nelem(ctlr->tx); i++)
1.677+ initring(&ctlr->tx[i], ctlr->td, (i-1)*32, 32);
1.678+ initring(ctlr->tx, ctlr->td, (i-1)*32, nelem(ctlr->td) - (i-1)*32);
1.679+
1.680+ dmapri[0] = dmapri[1] = dmapri[2] = 0;
1.681+ for(i = 0; i < nelem(ctlr->tx); i++){
1.682+ REG(ctlr->tx[i].regs[DmaDoneThresh]) = 10;
1.683+ REG(ctlr->tx[i].regs[TdmaFlowPeriod]) = i ? 0 : Maxtu << 16;
1.684+ dmapri[ctlr->tx[i].num/6] |= i << ((ctlr->tx[i].num%6)*5);
1.685+ }
1.686+
1.687+ REG(ctlr->tx->regs[TdmaArbCtrl]) = 2;
1.688+ REG(ctlr->tx->regs[TdmaPriority0]) = dmapri[0];
1.689+ REG(ctlr->tx->regs[TdmaPriority1]) = dmapri[1];
1.690+ REG(ctlr->tx->regs[TdmaPriority2]) = dmapri[2];
1.691+
1.692+ REG(ctlr->rx->regs[RingCfg]) = rcfg;
1.693+ REG(ctlr->tx->regs[RingCfg]) = tcfg;
1.694+
1.695+ REG(ctlr->rx->regs[DmaCtrl]) |= rcfg<<1;
1.696+ REG(ctlr->tx->regs[DmaCtrl]) |= tcfg<<1;
1.697+}
1.698+
1.699+static void
1.700+umaccmd(Ctlr *ctlr, u32int set, u32int clr)
1.701+{
1.702+ ilock(ctlr);
1.703+ REG(ctlr->regs[UmacCmd]) = (REG(ctlr->regs[UmacCmd]) & ~clr) | set;
1.704+ iunlock(ctlr);
1.705+}
1.706+
1.707+static void
1.708+reset(Ctlr *ctlr)
1.709+{
1.710+ u32int r;
1.711+
1.712+ // reset umac
1.713+ r = REG(ctlr->regs[SysRbufFlushCtrl]);
1.714+ REG(ctlr->regs[SysRbufFlushCtrl]) = r | 2;
1.715+ microdelay(10);
1.716+ REG(ctlr->regs[SysRbufFlushCtrl]) = r & ~2;
1.717+ microdelay(10);
1.718+
1.719+ // umac reset
1.720+ REG(ctlr->regs[SysRbufFlushCtrl]) = 0;
1.721+ microdelay(10);
1.722+
1.723+ REG(ctlr->regs[UmacCmd]) = 0;
1.724+ REG(ctlr->regs[UmacCmd]) = CmdSwReset | CmdLclLoopEn;
1.725+ microdelay(2);
1.726+ REG(ctlr->regs[UmacCmd]) = 0;
1.727+}
1.728+
1.729+static void
1.730+setmac(Ctlr *ctlr, uchar *ea)
1.731+{
1.732+ REG(ctlr->regs[UmacMac0]) = ea[0]<<24 | ea[1]<<16 | ea[2]<<8 | ea[3];
1.733+ REG(ctlr->regs[UmacMac1]) = ea[4]<<8 | ea[5];
1.734+}
1.735+
1.736+static void
1.737+sethfb(Ctlr *ctlr)
1.738+{
1.739+ int i;
1.740+
1.741+ REG(ctlr->regs[HfbCtlr]) = 0;
1.742+ REG(ctlr->regs[HfbFltEnable]) = 0;
1.743+ REG(ctlr->regs[HfbFltEnable+1]) = 0;
1.744+
1.745+ for(i = 0; i < 8; i++)
1.746+ REG(ctlr->rx->regs[RdmaIndex2Ring0+i]) = 0;
1.747+
1.748+ for(i = 0; i < 48/4; i++)
1.749+ REG(ctlr->regs[HfbFltLen + i]) = 0;
1.750+
1.751+ for(i = 0; i < 48*128; i++)
1.752+ REG(ctlr->regs[HfbOffset + i]) = 0;
1.753+}
1.754+
1.755+static int
1.756+mdiodone(void *arg)
1.757+{
1.758+ Ctlr *ctlr = arg;
1.759+ REG(ctlr->regs[Intrl0 + IntrMaskClr]) = (IrqMdioDone|IrqMdioError);
1.760+ return (REG(ctlr->regs[MdioCmd]) & MdioStartBusy) == 0;
1.761+}
1.762+
1.763+static int
1.764+mdiowait(Ctlr *ctlr)
1.765+{
1.766+ REG(ctlr->regs[MdioCmd]) |= MdioStartBusy;
1.767+ while(REG(ctlr->regs[MdioCmd]) & MdioStartBusy)
1.768+ tsleep(ctlr->mii, mdiodone, ctlr, 10);
1.769+ return 0;
1.770+}
1.771+
1.772+static int
1.773+mdiow(Mii* mii, int phy, int addr, int data)
1.774+{
1.775+ Ctlr *ctlr = mii->ctlr;
1.776+
1.777+ if(phy > MdioPhyMask)
1.778+ return -1;
1.779+ addr &= MdioAddrMask;
1.780+ REG(ctlr->regs[MdioCmd]) = MdioWrite
1.781+ | (phy << MdioPhyShift) | (addr << MdioAddrShift) | (data & 0xFFFF);
1.782+ return mdiowait(ctlr);
1.783+}
1.784+
1.785+static int
1.786+mdior(Mii* mii, int phy, int addr)
1.787+{
1.788+ Ctlr *ctlr = mii->ctlr;
1.789+
1.790+ if(phy > MdioPhyMask)
1.791+ return -1;
1.792+ addr &= MdioAddrMask;
1.793+ REG(ctlr->regs[MdioCmd]) = MdioRead
1.794+ | (phy << MdioPhyShift) | (addr << MdioAddrShift);
1.795+ if(mdiowait(ctlr) < 0)
1.796+ return -1;
1.797+ if(REG(ctlr->regs[MdioCmd]) & MdioReadFail)
1.798+ return -1;
1.799+ return REG(ctlr->regs[MdioCmd]) & 0xFFFF;
1.800+}
1.801+
1.802+static int
1.803+bcmshdr(Mii *mii, int reg)
1.804+{
1.805+ miimiw(mii, 0x1C, (reg & 0x1F) << 10);
1.806+ return miimir(mii, 0x1C) & 0x3FF;
1.807+}
1.808+
1.809+static int
1.810+bcmshdw(Mii *mii, int reg, int dat)
1.811+{
1.812+ return miimiw(mii, 0x1C, 0x8000 | (reg & 0x1F) << 10 | (dat & 0x3FF));
1.813+}
1.814+
1.815+static int
1.816+linkevent(void *arg)
1.817+{
1.818+ Ctlr *ctlr = arg;
1.819+ REG(ctlr->regs[Intrl0 + IntrMaskClr]) = IrqLinkUp|IrqLinkDown;
1.820+ return 0;
1.821+}
1.822+
1.823+static void
1.824+linkproc(void *arg)
1.825+{
1.826+ Ether *edev = arg;
1.827+ Ctlr *ctlr = edev->ctlr;
1.828+ MiiPhy *phy;
1.829+ int link = -1;
1.830+
1.831+#ifdef XXXDEBUG
1.832+ procwired(up, 1);
1.833+ sched();
1.834+#endif
1.835+
1.836+ while(waserror())
1.837+ ;
1.838+
1.839+ for(;;){
1.840+ tsleep(ctlr->link, linkevent, ctlr, 1000);
1.841+ miistatus(ctlr->mii);
1.842+ phy = ctlr->mii->curphy;
1.843+ if(phy == nil || phy->link == link)
1.844+ continue;
1.845+ link = phy->link;
1.846+ if(link){
1.847+ u32int cmd = CmdRxEn|CmdTxEn;
1.848+ switch(phy->speed){
1.849+ case 1000: cmd |= CmdSpeed1000; break;
1.850+ case 100: cmd |= CmdSpeed100; break;
1.851+ case 10: cmd |= CmdSpeed10; break;
1.852+ }
1.853+ if(!phy->fd)
1.854+ cmd |= CmdHdEn;
1.855+ if(!phy->rfc)
1.856+ cmd |= CmdRxPauseIgn;
1.857+ if(!phy->tfc)
1.858+ cmd |= CmdTxPauseIgn;
1.859+
1.860+ REG(ctlr->regs[ExtRgmiiOobCtrl]) = (REG(ctlr->regs[ExtRgmiiOobCtrl]) & ~OobDisable) | RgmiiLink;
1.861+ umaccmd(ctlr, cmd, CmdSpeedMask|CmdHdEn|CmdRxPauseIgn|CmdTxPauseIgn);
1.862+
1.863+ edev->mbps = phy->speed;
1.864+ }
1.865+ edev->link = link;
1.866+ // print("#l%d: link %d speed %d\n", edev->ctlrno, edev->link, edev->mbps);
1.867+ }
1.868+}
1.869+
1.870+static void
1.871+setmdfaddr(Ctlr *ctlr, int i, uchar *ea)
1.872+{
1.873+ REG(ctlr->regs[UmacMdfAddr0 + i*2 + 0]) = ea[0] << 8 | ea[1];
1.874+ REG(ctlr->regs[UmacMdfAddr0 + i*2 + 1]) = ea[2] << 24 | ea[3] << 16 | ea[4] << 8 | ea[5];
1.875+}
1.876+
1.877+static void
1.878+rxmode(Ether *edev, int prom)
1.879+{
1.880+ Ctlr *ctlr = edev->ctlr;
1.881+ Netaddr *na;
1.882+ int i;
1.883+
1.884+ if(prom || edev->nmaddr > 16-2){
1.885+ REG(ctlr->regs[UmacMdfCtrl]) = 0;
1.886+ umaccmd(ctlr, CmdProm, 0);
1.887+ return;
1.888+ }
1.889+ setmdfaddr(ctlr, 0, edev->bcast);
1.890+ setmdfaddr(ctlr, 1, edev->ea);
1.891+ for(i = 2, na = edev->maddr; na != nil; na = na->next, i++)
1.892+ setmdfaddr(ctlr, i, na->addr);
1.893+ REG(ctlr->regs[UmacMdfCtrl]) = (-0x10000 >> i) & 0x1FFFF;
1.894+ umaccmd(ctlr, 0, CmdProm);
1.895+}
1.896+
1.897+static void
1.898+shutdown(Ether *edev)
1.899+{
1.900+ Ctlr *ctlr = edev->ctlr;
1.901+
1.902+ dmaoff(ctlr);
1.903+ introff(ctlr);
1.904+}
1.905+
1.906+static void
1.907+attach(Ether *edev)
1.908+{
1.909+ Ctlr *ctlr = edev->ctlr;
1.910+
1.911+ eqlock(ctlr);
1.912+ if(ctlr->attached){
1.913+ qunlock(ctlr);
1.914+ return;
1.915+ }
1.916+ if(waserror()){
1.917+ print("#l%d: %s\n", edev->ctlrno, up->errstr);
1.918+ shutdown(edev);
1.919+ freebufs(ctlr);
1.920+ qunlock(ctlr);
1.921+ nexterror();
1.922+ }
1.923+
1.924+ // statistics
1.925+ REG(ctlr->regs[UmacMibCtrl]) = MibResetRx | MibResetTx | MibResetRunt;
1.926+ REG(ctlr->regs[UmacMibCtrl]) = 0;
1.927+
1.928+ // wol
1.929+ REG(ctlr->regs[UmacMpdCtrl]) &= ~(MpdPwEn|MpdEn);
1.930+
1.931+ // power
1.932+ REG(ctlr->regs[UmacEeeCtrl]) &= ~UmacEeeEn;
1.933+ REG(ctlr->regs[RbufEnergyCtrl]) &= ~(RbufEeeEn|RbufPmEn);
1.934+ REG(ctlr->regs[TbufEnergyCtrl]) &= ~(RbufEeeEn|RbufPmEn);
1.935+ REG(ctlr->regs[TbufBpMc]) = 0;
1.936+
1.937+ REG(ctlr->regs[UmacMaxFrameLen]) = Maxtu;
1.938+
1.939+ REG(ctlr->regs[RbufTbufSizeCtrl]) = 1;
1.940+
1.941+ REG(ctlr->regs[TbufCtrl]) &= ~(Rbuf64En);
1.942+ REG(ctlr->regs[RbufCtrl]) &= ~(Rbuf64En|RbufAlign2B);
1.943+ REG(ctlr->regs[RbufChkCtrl]) &= ~(RbufChkRxChkEn|RbufChkSkipFcs);
1.944+
1.945+ allocbufs(ctlr);
1.946+ initrings(ctlr);
1.947+ dmaon(ctlr);
1.948+
1.949+ setmac(ctlr, edev->ea);
1.950+ sethfb(ctlr);
1.951+ rxmode(edev, 0);
1.952+
1.953+ REG(ctlr->regs[SysPortCtrl]) = PortModeExtGphy;
1.954+ REG(ctlr->regs[ExtRgmiiOobCtrl]) |= RgmiiModeEn | IdModeDis;
1.955+
1.956+ ctlr->mii->ctlr = ctlr;
1.957+ ctlr->mii->mir = mdior;
1.958+ ctlr->mii->miw = mdiow;
1.959+ mii(ctlr->mii, ~0);
1.960+
1.961+ if(ctlr->mii->curphy == nil)
1.962+ error("no phy");
1.963+
1.964+ print("#l%d: phy%d id %.8ux oui %x\n",
1.965+ edev->ctlrno, ctlr->mii->curphy->phyno,
1.966+ ctlr->mii->curphy->id, ctlr->mii->curphy->oui);
1.967+
1.968+ miireset(ctlr->mii);
1.969+
1.970+ switch(ctlr->mii->curphy->id){
1.971+ case 0x600d84a2: /* BCM54312PE */
1.972+ /* mask interrupts */
1.973+ miimiw(ctlr->mii, 0x10, miimir(ctlr->mii, 0x10) | 0x1000);
1.974+
1.975+ /* SCR3: clear DLLAPD_DIS */
1.976+ bcmshdw(ctlr->mii, 0x05, bcmshdr(ctlr->mii, 0x05) &~0x0002);
1.977+ /* APD: set APD_EN */
1.978+ bcmshdw(ctlr->mii, 0x0a, bcmshdr(ctlr->mii, 0x0a) | 0x0020);
1.979+
1.980+ /* blinkenlights */
1.981+ bcmshdw(ctlr->mii, 0x09, bcmshdr(ctlr->mii, 0x09) | 0x0010);
1.982+ bcmshdw(ctlr->mii, 0x0d, 3<<0 | 0<<4);
1.983+ break;
1.984+ }
1.985+
1.986+ /* don't advertise EEE */
1.987+ miimmdw(ctlr->mii, 7, 60, 0);
1.988+
1.989+ miiane(ctlr->mii, ~0, ~0, ~0);
1.990+
1.991+#ifdef XXXDEBUG
1.992+ xxx = ctlr;
1.993+#endif
1.994+
1.995+ ctlr->attached = 1;
1.996+
1.997+ kproc("genet-recv", recvproc, edev);
1.998+ kproc("genet-send", sendproc, edev);
1.999+ kproc("genet-free", freeproc, edev);
1.1000+ kproc("genet-link", linkproc, edev);
1.1001+
1.1002+ qunlock(ctlr);
1.1003+ poperror();
1.1004+}
1.1005+
1.1006+static void
1.1007+prom(void *arg, int on)
1.1008+{
1.1009+ Ether *edev = arg;
1.1010+ rxmode(edev, on);
1.1011+}
1.1012+
1.1013+static void
1.1014+multi(void *arg, uchar*, int)
1.1015+{
1.1016+ Ether *edev = arg;
1.1017+ rxmode(edev, edev->prom > 0);
1.1018+}
1.1019+
1.1020+static long
1.1021+ctl(Ether *edev, void *data, long len)
1.1022+{
1.1023+ Ctlr *ctlr = edev->ctlr;
1.1024+ char *s = data;
1.1025+
1.1026+ if(len >= 4 && strncmp(s, "tron", 4) == 0){
1.1027+ umaccmd(ctlr, CmdTxEn, 0);
1.1028+ } else if(len >= 5 && strncmp(s, "troff", 5) == 0){
1.1029+ umaccmd(ctlr, 0, CmdTxEn);
1.1030+ } else if(len >= 3 && strncmp(s, "ron", 3) == 0){
1.1031+ umaccmd(ctlr, CmdRxEn, 0);
1.1032+ } else if(len >= 4 && strncmp(s, "roff", 4) == 0){
1.1033+ umaccmd(ctlr, 0, CmdRxEn);
1.1034+ }
1.1035+
1.1036+ return len;
1.1037+}
1.1038+
1.1039+static int
1.1040+pnp(Ether *edev)
1.1041+{
1.1042+ static Ctlr ctlr[1];
1.1043+
1.1044+ if(ctlr->regs != nil)
1.1045+ return -1;
1.1046+
1.1047+ ctlr->regs = (u32int*)(VIRTIO1 + 0x580000);
1.1048+ ctlr->rx->regs = &ctlr->regs[RdmaOffset + nelem(ctlr->rd)*3 + 16*RingCfg];
1.1049+ ctlr->tx->regs = &ctlr->regs[TdmaOffset + nelem(ctlr->td)*3 + 16*RingCfg];
1.1050+
1.1051+ edev->port = (uintptr)ctlr->regs;
1.1052+ edev->irq = IRQether;
1.1053+ edev->ctlr = ctlr;
1.1054+ edev->attach = attach;
1.1055+ edev->shutdown = shutdown;
1.1056+ edev->promiscuous = prom;
1.1057+ edev->multicast = multi;
1.1058+ edev->ctl = ctl;
1.1059+ edev->arg = edev;
1.1060+ edev->mbps = 1000;
1.1061+ edev->maxmtu = Maxtu;
1.1062+
1.1063+ parseether(edev->ea, getethermac());
1.1064+
1.1065+ reset(ctlr);
1.1066+ dmaoff(ctlr);
1.1067+ introff(ctlr);
1.1068+
1.1069+ intrenable(edev->irq+0, interrupt0, edev, BUSUNKNOWN, edev->name);
1.1070+ intrenable(edev->irq+1, interrupt1, edev, BUSUNKNOWN, edev->name);
1.1071+
1.1072+ return 0;
1.1073+}
1.1074+
1.1075+void
1.1076+ethergenetlink(void)
1.1077+{
1.1078+ addethercard("genet", pnp);
1.1079+}