📄 etherrhine.c
字号:
/* Via Rhine driver, written for VT6102. Uses the ethermii to control PHY. Currently always copies on both, tx and rx. rx side could be copy-free, and tx-side might be made (almost) copy-free by using (possibly) two descriptors (if it allows arbitrary tx lengths, which it should..): first for alignment and second for rest of the frame. Rx-part should be worth doing.*/#include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"typedef struct QLock { int r; } QLock;#define qlock(i) while(0)#define qunlock(i) while(0)#define iprint print#include "etherif.h"#include "ethermii.h"typedef struct Desc Desc;typedef struct Ctlr Ctlr;enum { Ntxd = 4, Nrxd = 4, Nwait = 50, Ntxstats = 9, Nrxstats = 8, BIGSTR = 8192,};struct Desc { ulong stat; ulong size; ulong addr; ulong next; char *buf; ulong pad[3];};struct Ctlr { Pcidev *pci; int attached; int txused; int txhead; int txtail; int rxtail; ulong port; Mii mii; ulong txstats[Ntxstats]; ulong rxstats[Nrxstats]; Desc *txd; /* wants to be aligned on 16-byte boundary */ Desc *rxd; QLock attachlck; Lock tlock;};#define ior8(c, r) (inb((c)->port+(r)))#define ior16(c, r) (ins((c)->port+(r)))#define ior32(c, r) (inl((c)->port+(r)))#define iow8(c, r, b) (outb((c)->port+(r), (int)(b)))#define iow16(c, r, w) (outs((c)->port+(r), (ushort)(w)))#define iow32(c, r, l) (outl((c)->port+(r), (ulong)(l)))enum Regs { Eaddr = 0x0, Rcr = 0x6, Tcr = 0x7, Cr = 0x8, Isr = 0xc, Imr = 0xe, McastAddr = 0x10, RxdAddr = 0x18, TxdAddr = 0x1C, Bcr = 0x6e, RhineMiiPhy = 0x6C, RhineMiiSr = 0x6D, RhineMiiCr = 0x70, RhineMiiAddr = 0x71, RhineMiiData = 0x72, Eecsr = 0x74, ConfigB = 0x79, ConfigD = 0x7B, MiscCr = 0x80, HwSticky = 0x83, MiscIsr = 0x84, MiscImr = 0x86, WolCrSet = 0xA0, WolCfgSet = 0xA1, WolCgSet = 0xA3, WolCrClr = 0xA4, PwrCfgClr = 0xA5, WolCgClr = 0xA7,};enum Rcrbits { RxErrX = 1<<0, RxSmall = 1<<1, RxMcast = 1<<2, RxBcast = 1<<3, RxProm = 1<<4, RxFifo64 = 0<<5, RxFifo32 = 1<<5, RxFifo128 = 2<<5, RxFifo256 = 3<<5, RxFifo512 = 4<<5, RxFifo768 = 5<<5, RxFifo1024 = 6<<5, RxFifoStoreForward = 7<<5,};enum Tcrbits { TxLoopback0 = 1<<1, TxLoopback1 = 1<<2, TxBackoff = 1<<3, TxFifo128 = 0<<5, TxFifo256 = 1<<5, TxFifo512 = 2<<5, TxFifo1024 = 3<<5, TxFifoStoreForward = 7<<5,};enum Crbits { Init = 1<<0, Start = 1<<1, Stop = 1<<2, RxOn = 1<<3, TxOn = 1<<4, Tdmd = 1<<5, Rdmd = 1<<6, EarlyRx = 1<<8, Reserved0 = 1<<9, FullDuplex = 1<<10, NoAutoPoll = 1<<11, Reserved1 = 1<<12, Tdmd1 = 1<<13, Rdmd1 = 1<<14, Reset = 1<<15,};enum Isrbits { RxOk = 1<<0, TxOk = 1<<1, RxErr = 1<<2, TxErr = 1<<3, TxBufUdf = 1<<4, RxBufLinkErr = 1<<5, BusErr = 1<<6, CrcOvf = 1<<7, EarlyRxInt = 1<<8, TxFifoUdf = 1<<9, RxFifoOvf = 1<<10, TxPktRace = 1<<11, NoRxbuf = 1<<12, TxCollision = 1<<13, PortCh = 1<<14, GPInt = 1<<15};enum Bcrbits { Dma32 = 0<<0, Dma64 = 1<<0, Dma128 = 2<<0, Dma256 = 3<<0, Dma512 = 4<<0, Dma1024 = 5<<0, DmaStoreForward = 7<<0, DupRxFifo0 = 1<<3, DupRxFifo1 = 1<<4, DupRxFifo2 = 1<<5, ExtraLed = 1<<6, MediumSelect = 1<<7, PollTimer0 = 1<<8, PollTimer1 = 1<<9, PollTimer2 = 1<<10, DupTxFifo0 = 1<<11, DupTxFifo1 = 1<<12, DupTxFifo2 = 1<<13,};enum Eecsrbits { EeAutoLoad = 1<<5,};enum MiscCrbits { Timer0Enable= 1<<0, Timer0Suspend = 1<<1, HalfDuplexFlowControl = 1<<2, FullDuplexFlowControl = 1<<3, Timer1Enable = 1<<8, ForceSoftReset = 1<<14,};enum HwStickybits { StickyDS0 = 1<<0, StickyDS1 = 1<<1, WOLEna = 1<<2, WOLStat = 1<<3,};enum WolCgbits { PmeOvr = 1<<7,};enum Descbits { OwnNic = 1<<31, /* stat */ TxAbort = 1<<8, /* stat */ TxError = 1<<15, /* stat */ RxChainbuf = 1<<10, /* stat */ RxChainStart = 1<<9, /* stat */ RxChainEnd = 1<<8, /* stat */ Chainbuf = 1<<15, /* size rx & tx*/ TxDisableCrc = 1<<16, /* size */ TxChainStart = 1<<21, /* size */ TxChainEnd = 1<<22, /* size */ TxInt = 1<<23, /* size */};enum ConfigDbits { BackoffOptional = 1<<0, BackoffAMD = 1<<1, BackoffDEC = 1<<2, BackoffRandom = 1<<3, PmccTestMode = 1<<4, PciReadlineCap = 1<<5, DiagMode = 1<<6, MmioEnable = 1<<7,};enum ConfigBbits { LatencyTimer = 1<<0, WriteWaitState = 1<<1, ReadWaitState = 1<<2, RxArbit = 1<<3, TxArbit = 1<<4, NoMemReadline = 1<<5, NoParity = 1<<6, NoTxQueuing = 1<<7,};enum RhineMiiCrbits { Mdc = 1<<0, Mdi = 1<<1, Mdo = 1<<2, Mdout = 1<<3, Mdpm = 1<<4, Wcmd = 1<<5, Rcmd = 1<<6, Mauto = 1<<7,};enum RhineMiiSrbits { Speed10M = 1<<0, LinkFail = 1<<1, PhyError = 1<<3, DefaultPhy = 1<<4, ResetPhy = 1<<7,};enum RhineMiiAddrbits { Mdone = 1<<5, Msrcen = 1<<6, Midle = 1<<7,};static char *txstatnames[Ntxstats] = { "aborts (excess collisions)", "out of window collisions", "carrier sense losses", "fifo underflows", "invalid descriptor format or underflows", "system errors", "reserved", "transmit errors", "collisions",};static char *rxstatnames[Nrxstats] = { "receiver errors", "crc errors", "frame alignment errors", "fifo overflows", "long packets", "run packets", "system errors", "buffer underflows",};static voidattach(Ether *edev){ Ctlr *ctlr; Desc *txd, *rxd, *td, *rd; Mii *mi; MiiPhy *phy; int i, s; ctlr = edev->ctlr; qlock(&ctlr->attachlck); if (ctlr->attached == 0) { txd = ctlr->txd; rxd = ctlr->rxd; for (i = 0; i < Ntxd; ++i) { td = &txd[i]; td->next = PCIWADDR(&txd[(i+1) % Ntxd]); td->buf = xspanalloc(sizeof(Etherpkt)+4, 4, 0); td->addr = PCIWADDR(td->buf); td->size = 0; coherence(); td->stat = 0; } for (i = 0; i < Nrxd; ++i) { rd = &rxd[i]; rd->next = PCIWADDR(&rxd[(i+1) % Nrxd]); rd->buf = xspanalloc(sizeof(Etherpkt)+4, 4, 0); rd->addr = PCIWADDR(rd->buf); rd->size = sizeof(Etherpkt)+4; coherence(); rd->stat = OwnNic; } ctlr->txhead = ctlr->txtail = ctlr->rxtail = 0; mi = &ctlr->mii; miistatus(mi); phy = mi->curphy; s = splhi(); iow32(ctlr, TxdAddr, PCIWADDR(&txd[0])); iow32(ctlr, RxdAddr, PCIWADDR(&rxd[0])); iow16(ctlr, Cr, (phy->fd ? FullDuplex : 0) | NoAutoPoll | TxOn | RxOn | Start | Rdmd); iow16(ctlr, Isr, 0xFFFF); iow16(ctlr, Imr, 0xFFFF); iow8(ctlr, MiscIsr, 0xFF); iow8(ctlr, MiscImr, ~(3<<5)); splx(s); } ctlr->attached++; qunlock(&ctlr->attachlck);}static voidtxstart(Ether *edev){ Ctlr *ctlr; Desc *txd, *td; int i, txused, n; RingBuf *tb; ctlr = edev->ctlr; txd = ctlr->txd; i = ctlr->txhead; txused = ctlr->txused; n = 0; while (txused < Ntxd) { tb = &edev->tb[edev->ti]; if(tb->owner != Interface) break; td = &txd[i]; memmove(td->buf, tb->pkt, tb->len); td->size = tb->len | TxChainStart | TxChainEnd | TxInt; /* could reduce number of ints here */ coherence(); td->stat = OwnNic; i = (i + 1) % Ntxd; txused++; n++; tb->owner = Host; edev->ti = NEXT(edev->ti, edev->ntb); } if (n) iow16(ctlr, Cr, ior16(ctlr, Cr) | Tdmd); ctlr->txhead = i; ctlr->txused = txused;}static voidtransmit(Ether *edev){ Ctlr *ctlr; ctlr = edev->ctlr; ilock(&ctlr->tlock); txstart(edev); iunlock(&ctlr->tlock);}static voidtxcomplete(Ether *edev){ Ctlr *ctlr; Desc *txd, *td; int i, txused, j; ulong stat; ctlr = edev->ctlr; txd = ctlr->txd; txused = ctlr->txused; i = ctlr->txtail; while (txused > 0) { td = &txd[i]; stat = td->stat; if (stat & OwnNic) break; ctlr->txstats[Ntxstats-1] += stat & 0xF; for (j = 0; j < Ntxstats-1; ++j) if (stat & (1<<(j+8))) ctlr->txstats[j]++; i = (i + 1) % Ntxd; txused--; } ctlr->txused = txused; ctlr->txtail = i; if (txused <= Ntxd/2) txstart(edev);}static voidinterrupt(Ureg *, void *arg){ Ether *edev; Ctlr *ctlr; RingBuf *rb; ushort isr, misr; ulong stat; Desc *rxd, *rd; int i, n, j, size; edev = (Ether*)arg; ctlr = edev->ctlr; iow16(ctlr, Imr, 0); isr = ior16(ctlr, Isr); iow16(ctlr, Isr, 0xFFFF); misr = ior16(ctlr, MiscIsr) & ~(3<<5); /* don't care about used defined ints */ if (isr & RxOk) { rxd = ctlr->rxd; i = ctlr->rxtail; n = 0; while ((rxd[i].stat & OwnNic) == 0) { rd = &rxd[i]; stat = rd->stat; for (j = 0; j < Nrxstats; ++j) if (stat & (1<<j)) ctlr->rxstats[j]++; if (stat & 0xFF) iprint("rx: %lux\n", stat & 0xFF); size = ((rd->stat>>16) & 2047) - 4; rb = &edev->rb[edev->ri]; if(rb->owner == Interface){ rb->owner = Host; rb->len = size; memmove(rb->pkt, rd->buf, size); edev->ri = NEXT(edev->ri, edev->nrb); } rd->size = sizeof(Etherpkt)+4; coherence(); rd->stat = OwnNic; i = (i + 1) % Nrxd; n++; } if (n) iow16(ctlr, Cr, ior16(ctlr, Cr) | Rdmd); ctlr->rxtail = i; isr &= ~RxOk; } if (isr & TxOk) { txcomplete(edev); isr &= ~TxOk; } if (isr | misr) iprint("etherrhine: unhandled irq(s). isr:%x misr:%x\n", isr, misr); iow16(ctlr, Imr, 0xFFFF);}static voidpromiscuous(void *arg, int enable){ Ether *edev; Ctlr *ctlr; edev = arg; ctlr = edev->ctlr; ilock(&ctlr->tlock); iow8(ctlr, Rcr, ior8(ctlr, Rcr) | (enable ? RxProm : RxBcast)); iunlock(&ctlr->tlock);}static intmiiread(Mii *mii, int phy, int reg){ Ctlr *ctlr; int n; ctlr = mii->ctlr; n = Nwait; while (n-- && ior8(ctlr, RhineMiiCr) & (Rcmd | Wcmd)) microdelay(1); if (n == Nwait) iprint("etherrhine: miiread: timeout\n"); iow8(ctlr, RhineMiiCr, 0); iow8(ctlr, RhineMiiPhy, phy); iow8(ctlr, RhineMiiAddr, reg); iow8(ctlr, RhineMiiCr, Rcmd); n = Nwait; while (n-- && ior8(ctlr, RhineMiiCr) & Rcmd) microdelay(1); if (n == Nwait) iprint("etherrhine: miiread: timeout\n"); n = ior16(ctlr, RhineMiiData); return n;}static intmiiwrite(Mii *mii, int phy, int reg, int data){ int n; Ctlr *ctlr; ctlr = mii->ctlr; n = Nwait; while (n-- && ior8(ctlr, RhineMiiCr) & (Rcmd | Wcmd)) microdelay(1); if (n == Nwait) iprint("etherrhine: miiwrite: timeout\n"); iow8(ctlr, RhineMiiCr, 0); iow8(ctlr, RhineMiiPhy, phy); iow8(ctlr, RhineMiiAddr, reg); iow16(ctlr, RhineMiiData, data); iow8(ctlr, RhineMiiCr, Wcmd); n = Nwait; while (n-- && ior8(ctlr, RhineMiiCr) & Wcmd) microdelay(1); if (n == Nwait) iprint("etherrhine: miiwrite: timeout\n"); return 0;}static voidreset(Ctlr* ctlr){ int i; iow16(ctlr, Cr, ior16(ctlr, Cr) | Stop); iow16(ctlr, Cr, ior16(ctlr, Cr) | Reset); for (i = 0; i < Nwait; ++i) { if ((ior16(ctlr, Cr) & Reset) == 0) return; delay(5); } iprint("etherrhine: reset timeout\n");}static voiddetach(Ether* edev){ reset(edev->ctlr);}static voidinit(Ether *edev){ Ctlr *ctlr; int i; ctlr = edev->ctlr; ilock(&ctlr->tlock); pcisetbme(ctlr->pci); reset(ctlr); iow8(ctlr, Eecsr, ior8(ctlr, Eecsr) | EeAutoLoad); for (i = 0; i < Nwait; ++i) { if ((ior8(ctlr, Eecsr) & EeAutoLoad) == 0) break; delay(5); } if (i == Nwait) iprint("etherrhine: eeprom autoload timeout\n"); for (i = 0; i < Eaddrlen; ++i) edev->ea[i] = ior8(ctlr, Eaddr + i); ctlr->mii.mir = miiread; ctlr->mii.miw = miiwrite; ctlr->mii.ctlr = ctlr; if(mii(&ctlr->mii, ~0) == 0 || ctlr->mii.curphy == nil){ iprint("etherrhine: init mii failure\n"); return; } for (i = 0; i < NMiiPhy; ++i) if (ctlr->mii.phy[i]) if (ctlr->mii.phy[i]->oui != 0xFFFFF) ctlr->mii.curphy = ctlr->mii.phy[i]; miistatus(&ctlr->mii); iow16(ctlr, Imr, 0); iow16(ctlr, Cr, ior16(ctlr, Cr) | Stop); iunlock(&ctlr->tlock);}static Pcidev *rhinematch(ulong){ static int nrhines = 0; int nfound = 0; Pcidev *p = nil; while (p = pcimatch(p, 0x1106, 0)) if (p->did == 0x3065) if (++nfound > nrhines) { nrhines++; break; } return p;}intrhinepnp(Ether *edev){ Pcidev *p; Ctlr *ctlr; ulong port; p = rhinematch(edev->port); if (p == nil) return -1; port = p->mem[0].bar & ~1; if ((ctlr = malloc(sizeof(Ctlr))) == nil) { print("etherrhine: couldn't allocate memory for ctlr\n"); return -1; } memset(ctlr, 0, sizeof(Ctlr)); ctlr->txd = xspanalloc(sizeof(Desc) * Ntxd, 16, 0); ctlr->rxd = xspanalloc(sizeof(Desc) * Nrxd, 16, 0); ctlr->pci = p; ctlr->port = port; edev->ctlr = ctlr; edev->port = ctlr->port; edev->irq = p->intl; edev->tbdf = p->tbdf; init(edev); edev->attach = attach; edev->transmit = transmit; edev->interrupt = interrupt; edev->detach = detach; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -