📄 ether2114x.c
字号:
/* * Digital Semiconductor DECchip 21140 PCI Fast Ethernet LAN Controller * as found on the Digital Fast EtherWORKS PCI 10/100 adapter (DE-500-X). * To do: * thresholds; * ring sizing; * handle more error conditions; * all the rest of it... */#include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "etherif.h"#define DEBUG (0)#define debug if(DEBUG)printenum { Nrde = 32, Ntde = 4,};#define Rbsz ROUNDUP(sizeof(Etherpkt)+4, 4)enum { /* CRS0 - Bus Mode */ Swr = 0x00000001, /* Software Reset */ Bar = 0x00000002, /* Bus Arbitration */ Dsl = 0x0000007C, /* Descriptor Skip Length (field) */ Ble = 0x00000080, /* Big/Little Endian */ Pbl = 0x00003F00, /* Programmable Burst Length (field) */ Cal = 0x0000C000, /* Cache Alignment (field) */ Cal8 = 0x00004000, /* 8 longword boundary alignment */ Cal16 = 0x00008000, /* 16 longword boundary alignment */ Cal32 = 0x0000C000, /* 32 longword boundary alignment */ Tap = 0x000E0000, /* Transmit Automatic Polling (field) */ Dbo = 0x00100000, /* Descriptor Byte Ordering Mode */ Rml = 0x00200000, /* Read Multiple */}; enum { /* CSR[57] - Status and Interrupt Enable */ Ti = 0x00000001, /* Transmit Interrupt */ Tps = 0x00000002, /* Transmit Process Stopped */ Tu = 0x00000004, /* Transmit buffer Unavailable */ Tjt = 0x00000008, /* Transmit Jabber Timeout */ Unf = 0x00000020, /* transmit UNderFlow */ Ri = 0x00000040, /* Receive Interrupt */ Ru = 0x00000080, /* Receive buffer Unavailable */ Rps = 0x00000100, /* Receive Process Stopped */ Rwt = 0x00000200, /* Receive Watchdog Timeout */ Eti = 0x00000400, /* Early Transmit Interrupt */ Gte = 0x00000800, /* General purpose Timer Expired */ Fbe = 0x00002000, /* Fatal Bit Error */ Ais = 0x00008000, /* Abnormal Interrupt Summary */ Nis = 0x00010000, /* Normal Interrupt Summary */ Rs = 0x000E0000, /* Receive process State (field) */ Ts = 0x00700000, /* Transmit process State (field) */ Eb = 0x03800000, /* Error bits */};enum { /* CSR6 - Operating Mode */ Hp = 0x00000001, /* Hash/Perfect receive filtering mode */ Sr = 0x00000002, /* Start/stop Receive */ Ho = 0x00000004, /* Hash-Only filtering mode */ Pb = 0x00000008, /* Pass Bad frames */ If = 0x00000010, /* Inverse Filtering */ Sb = 0x00000020, /* Start/stop Backoff counter */ Pr = 0x00000040, /* Promiscuous Mode */ Pm = 0x00000080, /* Pass all Multicast */ Fd = 0x00000200, /* Full Duplex mode */ Om = 0x00000C00, /* Operating Mode (field) */ Fc = 0x00001000, /* Force Collision */ St = 0x00002000, /* Start/stop Transmission Command */ Tr = 0x0000C000, /* ThReshold control bits (field) */ Tr128 = 0x00000000, Tr256 = 0x00004000, Tr512 = 0x00008000, Tr1024 = 0x0000C000, Ca = 0x00020000, /* CApture effect enable */ Ps = 0x00040000, /* Port Select */ Hbd = 0x00080000, /* HeartBeat Disable */ Imm = 0x00100000, /* IMMediate mode */ Sf = 0x00200000, /* Store and Forward */ Ttm = 0x00400000, /* Transmit Threshold Mode */ Pcs = 0x00800000, /* PCS function */ Scr = 0x01000000, /* SCRambler mode */ Mbo = 0x02000000, /* Must Be One */ Ra = 0x40000000, /* Receive All */ Sc = 0x80000000, /* Special Capture effect enable */ TrMODE = Tr512, /* default transmission threshold */};enum { /* CSR9 - ROM and MII Management */ Scs = 0x00000001, /* serial ROM chip select */ Sclk = 0x00000002, /* serial ROM clock */ Sdi = 0x00000004, /* serial ROM data in */ Sdo = 0x00000008, /* serial ROM data out */ Ss = 0x00000800, /* serial ROM select */ Wr = 0x00002000, /* write */ Rd = 0x00004000, /* read */ Mdc = 0x00010000, /* MII management clock */ Mdo = 0x00020000, /* MII management write data */ Mii = 0x00040000, /* MII management operation mode (W) */ Mdi = 0x00080000, /* MII management data in */};enum { /* CSR12 - General-Purpose Port */ Gpc = 0x00000100, /* General Purpose Control */};typedef struct Des { int status; int control; ulong addr; void* bp;} Des;enum { /* status */ Of = 0x00000001, /* Rx: OverFlow */ Ce = 0x00000002, /* Rx: CRC Error */ Db = 0x00000004, /* Rx: Dribbling Bit */ Re = 0x00000008, /* Rx: Report on MII Error */ Rw = 0x00000010, /* Rx: Receive Watchdog */ Ft = 0x00000020, /* Rx: Frame Type */ Cs = 0x00000040, /* Rx: Collision Seen */ Tl = 0x00000080, /* Rx: Frame too Long */ Ls = 0x00000100, /* Rx: Last deScriptor */ Fs = 0x00000200, /* Rx: First deScriptor */ Mf = 0x00000400, /* Rx: Multicast Frame */ Rf = 0x00000800, /* Rx: Runt Frame */ Dt = 0x00003000, /* Rx: Data Type (field) */ De = 0x00004000, /* Rx: Descriptor Error */ Fl = 0x3FFF0000, /* Rx: Frame Length (field) */ Ff = 0x40000000, /* Rx: Filtering Fail */ Def = 0x00000001, /* Tx: DEFerred */ Uf = 0x00000002, /* Tx: UnderFlow error */ Lf = 0x00000004, /* Tx: Link Fail report */ Cc = 0x00000078, /* Tx: Collision Count (field) */ Hf = 0x00000080, /* Tx: Heartbeat Fail */ Ec = 0x00000100, /* Tx: Excessive Collisions */ Lc = 0x00000200, /* Tx: Late Collision */ Nc = 0x00000400, /* Tx: No Carrier */ Lo = 0x00000800, /* Tx: LOss of carrier */ To = 0x00004000, /* Tx: Transmission jabber timeOut */ Es = 0x00008000, /* [RT]x: Error Summary */ Own = 0x80000000, /* [RT]x: OWN bit */};enum { /* control */ Bs1 = 0x000007FF, /* [RT]x: Buffer 1 Size */ Bs2 = 0x003FF800, /* [RT]x: Buffer 2 Size */ Ch = 0x01000000, /* [RT]x: second address CHained */ Er = 0x02000000, /* [RT]x: End of Ring */ Ft0 = 0x00400000, /* Tx: Filtering Type 0 */ Dpd = 0x00800000, /* Tx: Disabled PaDding */ Ac = 0x04000000, /* Tx: Add CRC disable */ Set = 0x08000000, /* Tx: SETup packet */ Ft1 = 0x10000000, /* Tx: Filtering Type 1 */ Fseg = 0x20000000, /* Tx: First SEGment */ Lseg = 0x40000000, /* Tx: Last SEGment */ Ic = 0x80000000, /* Tx: Interrupt on Completion */};enum { /* PHY registers */ Bmcr = 0, /* Basic Mode Control */ Bmsr = 1, /* Basic Mode Status */ Phyidr1 = 2, /* PHY Identifier #1 */ Phyidr2 = 3, /* PHY Identifier #2 */ Anar = 4, /* Auto-Negotiation Advertisment */ Anlpar = 5, /* Auto-Negotiation Link Partner Ability */ Aner = 6, /* Auto-Negotiation Expansion */};enum { /* Variants */ Tulip0 = (0x0009<<16)|0x1011, Tulip1 = (0x0014<<16)|0x1011, Tulip3 = (0x0019<<16)|0x1011, Pnic = (0x0002<<16)|0x11AD, Pnic2 = (0xC115<<16)|0x11AD, CentaurP = (0x0985<<16)|0x1317, CentaurPcb = (0x1985<<16)|0x1317,};typedef struct Ctlr Ctlr;typedef struct Ctlr { int port; Pcidev* pcidev; Ctlr* next; int active; int id; /* (pcidev->did<<16)|pcidev->vid */ uchar *srom; int sromsz; uchar* sromea; /* MAC address */ uchar* leaf; int sct; /* selected connection type */ int k; /* info block count */ uchar* infoblock[16]; int sctk; /* sct block index */ int curk; /* current block index */ uchar* type5block; int phy[32]; /* logical to physical map */ int phyreset; /* reset bitmap */ int curphyad; int fdx; int ttm; uchar fd; /* option */ int medium; /* option */ int csr6; /* CSR6 - operating mode */ int mask; /* CSR[57] - interrupt mask */ int mbps; Des* rdr; /* receive descriptor ring */ int nrdr; /* size of rdr */ int rdrx; /* index into rdr */ Des* tdr; /* transmit descriptor ring */ int ntdr; /* size of tdr */ int tdrh; /* host index into tdr */ int tdri; /* interface index into tdr */ int ntq; /* descriptors active */ Block* setupbp; ulong of; /* receive statistics */ ulong ce; ulong cs; ulong tl; ulong rf; ulong de; ulong uf; /* transmit statistics */ ulong ec; ulong lc; ulong nc; ulong lo; ulong to;} Ctlr;static Ctlr* ctlrhead;static Ctlr* ctlrtail;#define csr32r(c, r) (inl((c)->port+((r)*8)))#define csr32w(c, r, l) (outl((c)->port+((r)*8), (ulong)(l)))static voidattach(Ether* ether){ Ctlr *ctlr; ctlr = ether->ctlr; if(!(ctlr->csr6 & Sr)){ ctlr->csr6 |= Sr; csr32w(ctlr, 6, ctlr->csr6); }}static voidtransmit(Ether* ether){ Ctlr *ctlr; Block *bp; Des *des; int control; RingBuf *tb; ctlr = ether->ctlr; while(ctlr->ntq < (ctlr->ntdr-1)){ if(ctlr->setupbp){ bp = ctlr->setupbp; ctlr->setupbp = 0; control = Ic|Set|BLEN(bp); } else{ if(ether->ntb == 0) break; tb = ðer->tb[ether->ti]; if(tb->owner != Interface) break; bp = allocb(tb->len); memmove(bp->wp, tb->pkt, tb->len); memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); bp->wp += tb->len; tb->owner = Host; ether->ti = NEXT(ether->ti, ether->ntb); control = Ic|Lseg|Fseg|BLEN(bp); } ctlr->tdr[PREV(ctlr->tdrh, ctlr->ntdr)].control &= ~Ic; des = &ctlr->tdr[ctlr->tdrh]; des->bp = bp; des->addr = PADDR(bp->rp); des->control |= control; ctlr->ntq++; //coherence(); des->status = Own; csr32w(ctlr, 1, 0); ctlr->tdrh = NEXT(ctlr->tdrh, ctlr->ntdr); }}static voidinterrupt(Ureg*, void* arg){ Ctlr *ctlr; Ether *ether; int len, status; Des *des; RingBuf *ring; ether = arg; ctlr = ether->ctlr; while((status = csr32r(ctlr, 5)) & (Nis|Ais)){ /* * Acknowledge the interrupts and mask-out * the ones that are implicitly handled. */ csr32w(ctlr, 5, status); status &= (ctlr->mask & ~(Nis|Ais|Ti)); /* * Received packets. */ if(status & Ri){ des = &ctlr->rdr[ctlr->rdrx]; while((des->status & Own) == 0){ len = ((des->status & Fl)>>16)-4; if(des->status & Es){ if(des->status & Of) ctlr->of++; if(des->status & Ce) ctlr->ce++; if(des->status & Cs) ctlr->cs++; if(des->status & Tl) ctlr->tl++; if(des->status & Rf) ctlr->rf++; if(des->status & De) ctlr->de++; } else{ ring = ðer->rb[ether->ri]; if(ring->owner == Interface){ ring->owner = Host; ring->len = len; memmove(ring->pkt, des->bp, len); ether->ri = NEXT(ether->ri, ether->nrb); } } des->control &= Er; des->control |= Rbsz; des->status = Own; ctlr->rdrx = NEXT(ctlr->rdrx, ctlr->nrdr); des = &ctlr->rdr[ctlr->rdrx]; } status &= ~Ri; } /* * Check the transmit side: * check for Transmit Underflow and Adjust * the threshold upwards; * free any transmitted buffers and try to * top-up the ring. */ if(status & Unf){ csr32w(ctlr, 6, ctlr->csr6 & ~St); switch(ctlr->csr6 & Tr){ case Tr128: len = Tr256; break; case Tr256: len = Tr512; break; case Tr512: len = Tr1024; break; default: case Tr1024: len = Sf; break; } ctlr->csr6 = (ctlr->csr6 & ~Tr)|len; csr32w(ctlr, 6, ctlr->csr6); csr32w(ctlr, 5, Tps); status &= ~(Unf|Tps); } while(ctlr->ntq){ des = &ctlr->tdr[ctlr->tdri]; if(des->status & Own) break; if(des->status & Es){ if(des->status & Uf) ctlr->uf++; if(des->status & Ec) ctlr->ec++; if(des->status & Lc) ctlr->lc++; if(des->status & Nc) ctlr->nc++; if(des->status & Lo) ctlr->lo++; if(des->status & To) ctlr->to++; } freeb(des->bp); des->control &= Er; ctlr->ntq--; ctlr->tdri = NEXT(ctlr->tdri, ctlr->ntdr); } transmit(ether); /* * Anything left not catered for? */ if(status) panic("#l%d: status %8.8uX\n", ether->ctlrno, status); }}static voidctlrinit(Ether* ether){ Ctlr *ctlr; Des *des; Block *bp; int i; uchar bi[Eaddrlen*2]; ctlr = ether->ctlr; /* * Allocate and initialise the receive ring; * allocate and initialise the transmit ring; * unmask interrupts and start the transmit side; * create and post a setup packet to initialise * the physical ethernet address. */ ctlr->rdr = malloc(ctlr->nrdr*sizeof(Des)); for(des = ctlr->rdr; des < &ctlr->rdr[ctlr->nrdr]; des++){ des->bp = malloc(Rbsz); des->status = Own; des->control = Rbsz; des->addr = PADDR(des->bp); } ctlr->rdr[ctlr->nrdr-1].control |= Er; ctlr->rdrx = 0; csr32w(ctlr, 3, PADDR(ctlr->rdr)); ctlr->tdr = ialloc(ctlr->ntdr*sizeof(Des), 32); ctlr->tdr[ctlr->ntdr-1].control |= Er; ctlr->tdrh = 0; ctlr->tdri = 0; csr32w(ctlr, 4, PADDR(ctlr->tdr)); /* * Clear any bits in the Status Register (CSR5) as * the PNIC has a different reset value from a true 2114x. */ ctlr->mask = Nis|Ais|Fbe|Rwt|Rps|Ru|Ri|Unf|Tjt|Tps|Ti; csr32w(ctlr, 5, ctlr->mask); csr32w(ctlr, 7, ctlr->mask); ctlr->csr6 |= St; csr32w(ctlr, 6, ctlr->csr6); for(i = 0; i < Eaddrlen/2; i++){ bi[i*4] = ether->ea[i*2]; bi[i*4+1] = ether->ea[i*2+1]; bi[i*4+2] = ether->ea[i*2+1]; bi[i*4+3] = ether->ea[i*2]; } bp = allocb(Eaddrlen*2*16); memset(bp->rp, 0xFF, sizeof(bi)); for(i = sizeof(bi); i < sizeof(bi)*16; i += sizeof(bi)) memmove(bp->rp+i, bi, sizeof(bi)); bp->wp += sizeof(bi)*16; ctlr->setupbp = bp; transmit(ether);}static voidcsr9w(Ctlr* ctlr, int data){ csr32w(ctlr, 9, data); microdelay(1);}static intmiimdi(Ctlr* ctlr, int n){ int data, i; /* * Read n bits from the MII Management Register. */ data = 0; for(i = n-1; i >= 0; i--){ if(csr32r(ctlr, 9) & Mdi) data |= (1<<i); csr9w(ctlr, Mii|Mdc); csr9w(ctlr, Mii); } csr9w(ctlr, 0); return data;}static voidmiimdo(Ctlr* ctlr, int bits, int n){ int i, mdo; /* * Write n bits to the MII Management Register. */ for(i = n-1; i >= 0; i--){ if(bits & (1<<i)) mdo = Mdo; else mdo = 0; csr9w(ctlr, mdo); csr9w(ctlr, mdo|Mdc); csr9w(ctlr, mdo); }}static intmiir(Ctlr* ctlr, int phyad, int regad){ int data, i; if(ctlr->id == Pnic){ i = 1000; csr32w(ctlr, 20, 0x60020000|(phyad<<23)|(regad<<18)); do{ microdelay(1); data = csr32r(ctlr, 20);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -