?? 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 1#define debug if(DEBUG)printenum { Nrde = 4, Ntde = 1,};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 = Sf, /* 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 */ Mdi = 0x00080000, /* MII management data in */};enum { /* CSR12 - General-Purpose Port */ Gpc = 0x00000100, /* General Purpose Control */ De500xFSYM = 0x00000001, /* output, force 100Mb mode */ De500xHD = 0x00000008, /* output, half-duplex mode */ De500xNoSYM = 0x00000040, /* input, 100Mb mode unavailable */ De500xNoTBT = 0x00000080, /* input, 10Mb mode unavailable */};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 */};typedef struct Ctlr Ctlr;typedef struct Ctlr { int port; Pcidev* pcidev; Ctlr* next; int active; 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; 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 */ 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 uchar setup[Eaddrlen*2*16];static voidattach(Ether* ether){ Ctlr *ctlr; ctlr = ether->ctlr; if((ctlr->csr6 & Sr) == 0){ ctlr->csr6 |= Sr; csr32w(ctlr, 6, ctlr->csr6); }}static voidtransmit(Ether* ether){ Ctlr *ctlr; Des *des; RingBuf *tb; ctlr = ether->ctlr; des = &ctlr->tdr[ctlr->tdri]; tb = ðer->tb[ether->ti]; if((des->status & Own) == 0 && tb->owner == Interface){ ctlr->tdr[PREV(ctlr->tdri, ctlr->ntdr)].control &= ~Ic; des->addr = PADDR(tb->pkt); des->bp = tb->pkt; des->control |= Ic|Lseg|Fseg|tb->len; des->status = Own; csr32w(ctlr, 1, 0); }}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 |= ROUNDUP(sizeof(Etherpkt)+4, 4); 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); } des = &ctlr->tdr[ctlr->tdri]; while((des->status & Own) == 0 && des->bp){ 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++; } ring = ðer->tb[ether->ti]; ring->owner = Host; /* */ if((uchar*)des->bp != setup) ether->ti = NEXT(ether->ti, ether->ntb); des->control &= Er; des->bp = 0; ctlr->tdri = NEXT(ctlr->tdri, ctlr->ntdr); des = &ctlr->tdr[ctlr->tdri]; } 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; 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(sizeof(Etherpkt)+4); des->status = Own; des->control = ROUNDUP(sizeof(Etherpkt)+4, 4); des->addr = PADDR(des->bp); } ctlr->rdr[ctlr->nrdr-1].control |= Er; ctlr->rdrx = 0; csr32w(ctlr, 3, PADDR(ctlr->rdr)); ctlr->tdr = malloc(ctlr->ntdr*sizeof(Des)); ctlr->tdr[ctlr->ntdr-1].control |= Er; ctlr->tdrh = 0; ctlr->tdri = 0; csr32w(ctlr, 4, PADDR(ctlr->tdr)); ctlr->mask = Nis|Ais|Fbe|Rwt|Rps|Ru|Ri|Unf|Tjt|Tps|Ti; 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]; } memset(setup, 0xFF, sizeof(bi)); for(i = sizeof(bi); i < sizeof(bi)*16; i += sizeof(bi)) memmove(setup+i, bi, sizeof(bi)); des = &ctlr->tdr[ctlr->tdrh]; des->bp = setup; des->addr = PADDR(setup); des->control |= Ic|Set|sizeof(setup); des->status = Own; ctlr->tdrh = NEXT(ctlr->tdrh, ctlr->ntdr); csr32w(ctlr, 1, 0);}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; /* * Preamble; * ST+OP+PHYAD+REGAD; * TA + 16 data bits. */ miimdo(ctlr, 0xFFFFFFFF, 32); miimdo(ctlr, 0x1800|(phyad<<5)|regad, 14); data = miimdi(ctlr, 18); if(data & 0x10000) return -1; return data & 0xFFFF;}static voidmiiw(Ctlr* ctlr, int phyad, int regad, int data){ /* * Preamble; * ST+OP+PHYAD+REGAD+TA + 16 data bits; * Z. */ miimdo(ctlr, 0xFFFFFFFF, 32); data &= 0xFFFF; data |= (0x05<<(5+5+2+16))|(phyad<<(5+2+16))|(regad<<(2+16))|(0x02<<16); miimdo(ctlr, data, 32); csr9w(ctlr, Mdc); csr9w(ctlr, 0);}static intsromr(Ctlr* ctlr, int r){ int i, op, data; /* * This sequence for reading a 16-bit register 'r' * in the EEPROM is taken straight from Section * 7.4 of the 21140 Hardware Reference Manual. */ csr9w(ctlr, Rd|Ss); csr9w(ctlr, Rd|Ss|Scs); csr9w(ctlr, Rd|Ss|Sclk|Scs); csr9w(ctlr, Rd|Ss); op = 0x06; for(i = 3-1; i >= 0; i--){ data = Rd|Ss|(((op>>i) & 0x01)<<2)|Scs; csr9w(ctlr, data); csr9w(ctlr, data|Sclk); csr9w(ctlr, data); } for(i = 6-1; i >= 0; i--){ data = Rd|Ss|(((r>>i) & 0x01)<<2)|Scs; csr9w(ctlr, data); csr9w(ctlr, data|Sclk); csr9w(ctlr, data); } data = 0; for(i = 16-1; i >= 0; i--){ csr9w(ctlr, Rd|Ss|Sclk|Scs); if(csr32r(ctlr, 9) & Sdo) data |= (1<<i); csr9w(ctlr, Rd|Ss|Scs); } csr9w(ctlr, 0); return data & 0xFFFF;}static voidsoftreset(Ctlr* ctlr){ /* * Soft-reset the controller and initialise bus mode. * Delay should be >= 50 PCI cycles (2×S @ 25MHz). */ csr32w(ctlr, 0, Swr); microdelay(10); csr32w(ctlr, 0, Rml|Cal16); delay(1);}static inttype5block(Ctlr* ctlr, uchar* block){ int csr15, i, len; /* * Reset or GPR sequence. Reset should be once only, * before the GPR sequence. * Note 'block' is not a pointer to the block head but * a pointer to the data in the block starting at the * reset length value so type5block can be used for the * sequences contained in type 1 and type 3 blocks. * The SROM docs state the 21140 type 5 block is the * same as that for the 21143, but the two controllers * use different registers and sequence-element lengths * so the 21140 code here is a guess for a real type 5 * sequence. */ len = *block++; if(ctlr->pcidev->did == 0x0009){ for(i = 0; i < len; i++){ csr32w(ctlr, 12, *block); block++; } return len; } for(i = 0; i < len; i++){ csr15 = *block++<<16; csr15 |= *block++<<24; csr32w(ctlr, 15, csr15); debug("%8.8uX ", csr15); } return 2*len;}static inttypephylink(Ctlr* ctlr, uchar*){ int an, bmcr, bmsr, csr6, x;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -