📄 ether2114x.c
字号:
/* * Digital Semiconductor DECchip 2114x PCI Fast Ethernet LAN Controller. * To do: * thresholds; * ring sizing; * handle more error conditions; * tidy setup packet mess; * push initialisation back to attach; * full SROM decoding. */#include "all.h"#include "io.h"#include "mem.h"#include "../ip/ip.h"#include "etherif.h"#define DEBUG (0)#define debug if(DEBUG)printenum { Nrde = 64, Ntde = 64,};#define Rbsz ROUNDUP(sizeof(Enpkt)+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; Msgbuf* mb;} 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, Tulip3 = (0x0019<<16)|0x1011, Pnic = (0x0002<<16)|0x11AD, Pnic2 = (0xC115<<16)|0x11AD,};typedef struct Ctlr Ctlr;typedef struct Ctlr { int port; Pcidev* pcidev; Ctlr* next; int active; int id; /* (pcidev->did<<16)|pcidev->vid */ uchar srom[128]; 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; Lock lock; Des* rdr; /* receive descriptor ring */ int nrdr; /* size of rdr */ int rdrx; /* index into rdr */ Lock tlock; 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 */ int ntqmax; Msgbuf* setupmb; ulong of; /* receive statistics */ ulong ce; ulong cs; ulong tl; ulong rf; ulong de; ulong ru; ulong rps; ulong rwt; ulong uf; /* transmit statistics */ ulong ec; ulong lc; ulong nc; ulong lo; ulong to; ulong tps; ulong tu; ulong tjt; ulong unf;} 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; ilock(&ctlr->lock); if(!(ctlr->csr6 & Sr)){ ctlr->csr6 |= Sr; csr32w(ctlr, 6, ctlr->csr6); } iunlock(&ctlr->lock);}static voidtxstart(Ether* ether){ Ctlr *ctlr; Msgbuf *mb; Des *des; int control; ctlr = ether->ctlr; while(ctlr->ntq < (ctlr->ntdr-1)){ if(ctlr->setupmb){ mb = ctlr->setupmb; ctlr->setupmb = 0; control = Ic|Set|mb->count; } else{ mb = etheroq(ether); if(mb == nil) break; control = Ic|Lseg|Fseg|mb->count; } ctlr->tdr[PREV(ctlr->tdrh, ctlr->ntdr)].control &= ~Ic; des = &ctlr->tdr[ctlr->tdrh]; des->mb = mb; des->addr = PADDR(mb->data); des->control |= control; ctlr->ntq++; coherence(); des->status = Own; csr32w(ctlr, 1, 0); ctlr->tdrh = NEXT(ctlr->tdrh, ctlr->ntdr); } if(ctlr->ntq > ctlr->ntqmax) ctlr->ntqmax = ctlr->ntq;}static voidtransmit(Ether* ether){ Ctlr *ctlr; ctlr = ether->ctlr; ilock(&ctlr->tlock); txstart(ether); iunlock(&ctlr->tlock);}static voidinterrupt(Ureg*, void* arg){ Ctlr *ctlr; Ether *ether; int len, status; Des *des; Msgbuf *mb, *rmb; 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|Ti)); if(status & Ais){ if(status & Tps) ctlr->tps++; if(status & Tu) ctlr->tu++; if(status & Tjt) ctlr->tjt++; if(status & Ru) ctlr->ru++; if(status & Rps) ctlr->rps++; if(status & Rwt) ctlr->rwt++; status &= ~(Ais|Rwt|Rps|Ru|Tjt|Tu|Tps); } /* * Received packets. */ if(status & Ri){ des = &ctlr->rdr[ctlr->rdrx]; while(!(des->status & Own)){ 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 if(mb = mballoc(Rbsz, 0, Mbeth1)){ rmb = des->mb; rmb->count = ((des->status & Fl)>>16)-4; etheriq(ether, rmb); des->mb = mb; des->addr = PADDR(mb->data); } des->control &= Er; des->control |= Rbsz; coherence(); 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){ ctlr->unf++; ilock(&ctlr->lock); 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); iunlock(&ctlr->lock); csr32w(ctlr, 5, Tps); status &= ~(Unf|Tps); } ilock(&ctlr->tlock); 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++; } mbfree(des->mb); des->control &= Er; ctlr->ntq--; ctlr->tdri = NEXT(ctlr->tdri, ctlr->ntdr); } txstart(ether); iunlock(&ctlr->tlock); /* * Anything left not catered for? */ if(status) panic("#l%d: status %8.8uX\n", ether->ctlrno, status); }}static voidctlrinit(Ether* ether){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -