## diffname pc/ether2114x.c 1999/0312 ## diff -e /dev/null /n/emeliedump/1999/0312/sys/src/brazil/pc/ether2114x.c 0a /* * 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 "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #include "../port/netif.h" #include "etherif.h" #define DEBUG 0 #define debug if(DEBUG)print enum { Nrde = 64, Ntde = 64, }; 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; Block* 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; 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; Block* setupbp; 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 void promiscuous(void* arg, int on) { Ctlr *ctlr; ctlr = ((Ether*)arg)->ctlr; ilock(&ctlr->lock); if(on) ctlr->csr6 |= Pr; else ctlr->csr6 &= ~Pr; csr32w(ctlr, 6, ctlr->csr6); iunlock(&ctlr->lock); } static void attach(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 long ifstat(Ether* ether, void* a, long n, ulong offset) { Ctlr *ctlr; char *buf, *p; int i, l, len; ctlr = ether->ctlr; ether->crcs = ctlr->ce; ether->frames = ctlr->rf+ctlr->cs; ether->buffs = ctlr->de+ctlr->tl; ether->overflows = ctlr->of; if(n == 0) return 0; p = malloc(READSTR); l = snprint(p, READSTR, "Overflow: %lud\n", ctlr->of); l += snprint(p+l, READSTR-l, "Ru: %lud\n", ctlr->ru); l += snprint(p+l, READSTR-l, "Rps: %lud\n", ctlr->rps); l += snprint(p+l, READSTR-l, "Rwt: %lud\n", ctlr->rwt); l += snprint(p+l, READSTR-l, "Tps: %lud\n", ctlr->tps); l += snprint(p+l, READSTR-l, "Tu: %lud\n", ctlr->tu); l += snprint(p+l, READSTR-l, "Tjt: %lud\n", ctlr->tjt); l += snprint(p+l, READSTR-l, "Unf: %lud\n", ctlr->unf); l += snprint(p+l, READSTR-l, "CRC Error: %lud\n", ctlr->ce); l += snprint(p+l, READSTR-l, "Collision Seen: %lud\n", ctlr->cs); l += snprint(p+l, READSTR-l, "Frame Too Long: %lud\n", ctlr->tl); l += snprint(p+l, READSTR-l, "Runt Frame: %lud\n", ctlr->rf); l += snprint(p+l, READSTR-l, "Descriptor Error: %lud\n", ctlr->de); l += snprint(p+l, READSTR-l, "Underflow Error: %lud\n", ctlr->uf); l += snprint(p+l, READSTR-l, "Excessive Collisions: %lud\n", ctlr->ec); l += snprint(p+l, READSTR-l, "Late Collision: %lud\n", ctlr->lc); l += snprint(p+l, READSTR-l, "No Carrier: %lud\n", ctlr->nc); l += snprint(p+l, READSTR-l, "Loss of Carrier: %lud\n", ctlr->lo); l += snprint(p+l, READSTR-l, "Transmit Jabber Timeout: %lud\n", ctlr->to); l += snprint(p+l, READSTR-l, "csr6: %luX %uX\n", csr32r(ctlr, 6), ctlr->csr6); snprint(p+l, READSTR-l, "ntqmax: %d\n", ctlr->ntqmax); ctlr->ntqmax = 0; buf = a; len = readstr(offset, buf, n, p); if(offset > l) offset -= l; else offset = 0; buf += len; n -= len; l = snprint(p, READSTR, "srom:"); for(i = 0; i < sizeof(ctlr->srom); i++){ if(i && ((i & 0x0F) == 0)) l += snprint(p+l, READSTR-l, "\n "); l += snprint(p+l, READSTR-l, " %2.2uX", ctlr->srom[i]); } snprint(p+l, READSTR-l, "\n"); len += readstr(offset, buf, n, p); free(p); return len; } static void txstart(Ether* ether) { Ctlr *ctlr; Block *bp; Des *des; int control; ctlr = ether->ctlr; while(ctlr->ntq < (ctlr->ntdr-1)){ if(ctlr->setupbp){ bp = ctlr->setupbp; ctlr->setupbp = 0; control = Ic|Set|BLEN(bp); } else{ bp = qget(ether->oq); if(bp == nil) break; 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); } if(ctlr->ntq > ctlr->ntqmax) ctlr->ntqmax = ctlr->ntq; } static void transmit(Ether* ether) { Ctlr *ctlr; ctlr = ether->ctlr; ilock(&ctlr->tlock); txstart(ether); iunlock(&ctlr->tlock); } static void interrupt(Ureg*, void* arg) { Ctlr *ctlr; Ether *ether; int len, status; Des *des; Block *bp; 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(bp = iallocb(sizeof(Etherpkt)+4)){ len = ((des->status & Fl)>>16)-4; des->bp->wp = des->bp->rp+len; etheriq(ether, des->bp, 1); des->bp = bp; des->addr = PADDR(bp->rp); } des->control &= Er; des->control |= ROUNDUP(sizeof(Etherpkt)+4, 4); 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++; ether->oerrs++; } freeb(des->bp); 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 void ctlrinit(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 = allocb(ROUNDUP(sizeof(Etherpkt)+4, 4)); des->status = Own; des->control = ROUNDUP(sizeof(Etherpkt)+4, 4); des->addr = PADDR(des->bp->rp); } ctlr->rdr[ctlr->nrdr-1].control |= Er; ctlr->rdrx = 0; csr32w(ctlr, 3, PADDR(ctlr->rdr)); ctlr->tdr = xspanalloc(ctlr->ntdr*sizeof(Des), 8*sizeof(ulong), 0); 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]; } 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; ether->oq = qopen(256*1024, 1, 0, 0); transmit(ether); } static void csr9w(Ctlr* ctlr, int data) { csr32w(ctlr, 9, data); microdelay(1); } static int miimdi(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<= 0; i--){ if(bits & (1<= 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<= 50 PCI cycles (2×S @ 25MHz). */ csr32w(ctlr, 0, Swr); microdelay(10); csr32w(ctlr, 0, Rml|Cal16); delay(1); } static int type5block(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 int typephylink(Ctlr* ctlr, uchar*) { int an, bmcr, bmsr, csr6, x; /* * Fail if * auto-negotiataion enabled but not complete; * no valid link established. */ bmcr = miir(ctlr, ctlr->curphyad, Bmcr); miir(ctlr, ctlr->curphyad, Bmsr); bmsr = miir(ctlr, ctlr->curphyad, Bmsr); debug("bmcr 0x%2.2uX bmsr 0x%2.2uX\n", bmcr, bmsr); if(((bmcr & 0x1000) && !(bmsr & 0x0020)) || !(bmsr & 0x0004)) return 0; if(bmcr & 0x1000){ an = miir(ctlr, ctlr->curphyad, Anar); an &= miir(ctlr, ctlr->curphyad, Anlpar) & 0x3E0; debug("an 0x%2.uX 0x%2.2uX 0x%2.2uX\n", miir(ctlr, ctlr->curphyad, Anar), miir(ctlr, ctlr->curphyad, Anlpar), an); if(an & 0x0100) x = 0x4000; else if(an & 0x0080) x = 0x2000; else if(an & 0x0040) x = 0x1000; else if(an & 0x0020) x = 0x0800; else x = 0; } else if((bmcr & 0x2100) == 0x2100) x = 0x4000; else if(bmcr & 0x2000) x = 0x2000; else if(bmcr & 0x0100) x = 0x1000; else x = 0x0800; csr6 = Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE; if(ctlr->fdx & x) csr6 |= Fd; if(ctlr->ttm & x) csr6 |= Ttm; debug("csr6 0x%2.2uX 0x%2.2uX\n", csr6, ctlr->csr6); if(csr6 != ctlr->csr6){ ctlr->csr6 = csr6; csr32w(ctlr, 6, csr6); } return 1; } static int typephymode(Ctlr* ctlr, uchar* block, int wait) { uchar *p; int len, mc, nway, phyx, timeo; if(DEBUG){ int i; len = (block[0] & ~0x80)+1; for(i = 0; i < len; i++) debug("%2.2uX ", block[i]); debug("\n"); } if(block[1] == 1) len = 1; else if(block[1] == 3) len = 2; else return -1; /* * Snarf the media capabilities, nway advertisment, * FDX and TTM bitmaps. */ p = &block[5+len*block[3]+len*block[4+len*block[3]]]; mc = *p++; mc |= *p++<<8; nway = *p++; nway |= *p++<<8; ctlr->fdx = *p++; ctlr->fdx |= *p++<<8; ctlr->ttm = *p++; ctlr->ttm |= *p<<8; debug("mc %4.4uX nway %4.4uX fdx %4.4uX ttm %4.4uX\n", mc, nway, ctlr->fdx, ctlr->ttm); phyx = block[2]; ctlr->curphyad = ctlr->phy[phyx]; ctlr->csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE; //csr32w(ctlr, 6, ctlr->csr6); if(typephylink(ctlr, block)) return 0; if(!(ctlr->phyreset & (1<type5block) type5block(ctlr, &ctlr->type5block[2]); else type5block(ctlr, &block[4+len*block[3]]); debug("\n"); ctlr->phyreset |= (1<csr6 = 0;//Sc|Mbo|Hbd|Ps|Ca|Sb|TrMODE; //csr32w(ctlr, 6, ctlr->csr6); if(typephylink(ctlr, block)) return 0; /* * Turn off auto-negotiation, set the auto-negotiation * advertisment register then start the auto-negotiation * process again. */ miiw(ctlr, ctlr->curphyad, Bmcr, 0); miiw(ctlr, ctlr->curphyad, Anar, nway|1); miiw(ctlr, ctlr->curphyad, Bmcr, 0x1000); if(!wait) return 0; for(timeo = 0; timeo < 30; timeo++){ if(typephylink(ctlr, block)) return 0; delay(100); } return -1; } static int type0link(Ctlr* ctlr, uchar* block) { int m, polarity, sense; m = (block[3]<<8)|block[2]; sense = 1<<((m & 0x000E)>>1); if(m & 0x0080) polarity = sense; else polarity = 0; return (csr32r(ctlr, 12) & sense)^polarity; } static int type0mode(Ctlr* ctlr, uchar* block, int wait) { int csr6, m, timeo; csr6 = Sc|Mbo|Hbd|Ca|Sb|TrMODE; debug("type0: medium 0x%uX, fd %d: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n", ctlr->medium, ctlr->fd, block[0], block[1], block[2], block[3]); switch(block[0]){ default: break; case 0x04: /* 10BASE-TFD */ case 0x05: /* 100BASE-TXFD */ case 0x08: /* 100BASE-FXFD */ /* * Don't attempt full-duplex * unless explicitly requested. */ if(!ctlr->fd) return -1; csr6 |= Fd; break; } m = (block[3]<<8)|block[2]; if(m & 0x0001) csr6 |= Ps; if(m & 0x0010) csr6 |= Ttm; if(m & 0x0020) csr6 |= Pcs; if(m & 0x0040) csr6 |= Scr; csr32w(ctlr, 12, block[1]); microdelay(10); csr32w(ctlr, 6, csr6); ctlr->csr6 = csr6; if(!wait) return 0; for(timeo = 0; timeo < 30; timeo++){ if(type0link(ctlr, block)) return 0; delay(100); } return -1; } static int mediaxx(Ether* ether, int wait) { Ctlr* ctlr; uchar *block; ctlr = ether->ctlr; block = ctlr->infoblock[ctlr->curk]; if(block[0] & 0x80){ switch(block[1]){ default: return -1; case 0: if(ctlr->medium >= 0 && block[2] != ctlr->medium) return 0; /* need this test? */ if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[2]) return 0; if(type0mode(ctlr, block+2, wait)) return 0; break; case 1: if(typephymode(ctlr, block, wait)) return 0; break; case 3: if(typephymode(ctlr, block, wait)) return 0; break; } } else{ if(ctlr->medium >= 0 && block[0] != ctlr->medium) return 0; /* need this test? */if(ctlr->sct != 0x0800 && (ctlr->sct & 0x3F) != block[0]) return 0; if(type0mode(ctlr, block, wait)) return 0; } if(ctlr->csr6){ if(!(ctlr->csr6 & Ps) || (ctlr->csr6 & Ttm)) return 10; return 100; } return 0; } static int media(Ether* ether, int wait) { Ctlr* ctlr; int k, mbps; ctlr = ether->ctlr; for(k = 0; k < ctlr->k; k++){ mbps = mediaxx(ether, wait); if(mbps > 0) return mbps; if(ctlr->curk == 0) ctlr->curk = ctlr->k-1; else ctlr->curk--; } return 0; } static char* mediatable[9] = { "10BASE-T", /* TP */ "10BASE-2", /* BNC */ "10BASE-5", /* AUI */ "100BASE-TX", "10BASE-TFD", "100BASE-TXFD", "100BASE-T4", "100BASE-FX", "100BASE-FXFD", }; static uchar en1207[] = { /* Accton EN1207-COMBO */ 0x00, 0x00, 0xE8, /* [0] vendor ethernet code */ 0x00, /* [3] spare */ 0x00, 0x08, /* [4] connection (LSB+MSB = 0x0800) */ 0x1F, /* [6] general purpose control */ 2, /* [7] block count */ 0x00, /* [8] media code (10BASE-TX) */ 0x0B, /* [9] general purpose port data */ 0x9E, 0x00, /* [10] command (LSB+MSB = 0x009E) */ 0x03, /* [8] media code (100BASE-TX) */ 0x1B, /* [9] general purpose port data */ 0x6D, 0x00, /* [10] command (LSB+MSB = 0x006D) */ /* There is 10BASE-2 as well, but... */ }; static uchar ana6910fx[] = { /* Adaptec (Cogent) ANA-6910FX */ 0x00, 0x00, 0x92, /* [0] vendor ethernet code */ 0x00, /* [3] spare */ 0x00, 0x08, /* [4] connection (LSB+MSB = 0x0800) */ 0x3F, /* [6] general purpose control */ 1, /* [7] block count */ 0x07, /* [8] media code (100BASE-FX) */ 0x03, /* [9] general purpose port data */ 0x2D, 0x00 /* [10] command (LSB+MSB = 0x000D) */ }; static uchar smc9332[] = { /* SMC 9332 */ 0x00, 0x00, 0xC0, /* [0] vendor ethernet code */ 0x00, /* [3] spare */ 0x00, 0x08, /* [4] connection (LSB+MSB = 0x0800) */ 0x1F, /* [6] general purpose control */ 2, /* [7] block count */ 0x00, /* [8] media code (10BASE-TX) */ 0x00, /* [9] general purpose port data */ 0x9E, 0x00, /* [10] command (LSB+MSB = 0x009E) */ 0x03, /* [8] media code (100BASE-TX) */ 0x09, /* [9] general purpose port data */ 0x6D, 0x00, /* [10] command (LSB+MSB = 0x006D) */ }; static uchar* leaf21140[] = { en1207, /* Accton EN1207-COMBO */ ana6910fx, /* Adaptec (Cogent) ANA-6910FX */ smc9332, /* SMC 9332 */ nil, }; static int srom(Ctlr* ctlr) { int i, k, oui, phy, x; uchar *p; /* * This is a partial decoding of the SROM format described in * 'Digital Semiconductor 21X4 Serial ROM Format, Version 4.05, * 2-Mar-98'. Only the 2114[03] are handled, support for other * controllers can be added as needed. */ for(i = 0; i < sizeof(ctlr->srom)/2; i++){ x = sromr(ctlr, i); ctlr->srom[2*i] = x; ctlr->srom[2*i+1] = x>>8; } /* * There are 2 SROM layouts: * e.g. Digital EtherWORKS station address at offset 20; * this complies with the 21140A SROM * application note from Digital; * e.g. SMC9332 station address at offset 0 followed by * 2 additional bytes, repeated at offset * 6; the 8 bytes are also repeated in * reverse order at offset 8. * To check which it is, read the SROM and check for the repeating * patterns of the non-compliant cards; if that fails use the one at * offset 20. */ ctlr->sromea = ctlr->srom; for(i = 0; i < 8; i++){ x = ctlr->srom[i]; if(x != ctlr->srom[15-i] || x != ctlr->srom[16+i]){ ctlr->sromea = &ctlr->srom[20]; break; } } /* * Next, try to find the info leaf in the SROM for media detection. * If it's a non-conforming card try to match the vendor ethernet code * and point p at a fake info leaf with compact 21140 entries. */ if(ctlr->sromea == ctlr->srom){ p = nil; for(i = 0; leaf21140[i] != nil; i++){ if(memcmp(leaf21140[i], ctlr->sromea, 3) == 0){ p = &leaf21140[i][4]; break; } } if(p == nil) return -1; } else p = &ctlr->srom[(ctlr->srom[28]<<8)|ctlr->srom[27]]; /* * Set up the info needed for later media detection. * For the 21140, set the general-purpose mask in CSR12. * The info block entries are stored in order of increasing * precedence, so detection will work backwards through the * stored indexes into ctlr->srom. * If an entry is found which matches the selected connection * type, save the index. Otherwise, start at the last entry. * If any MII entries are found (type 1 and 3 blocks), scan * for PHYs. */ ctlr->leaf = p; ctlr->sct = *p++; ctlr->sct |= *p++<<8; if(ctlr->pcidev->did == 0x0009){ csr32w(ctlr, 12, Gpc|*p++); delay(200); } ctlr->k = *p++; if(ctlr->k >= nelem(ctlr->infoblock)) ctlr->k = nelem(ctlr->infoblock)-1; ctlr->sctk = ctlr->k-1; phy = 0; for(k = 0; k < ctlr->k; k++){ ctlr->infoblock[k] = p; /* * The RAMIX PMC665 has a badly-coded SROM, * hence the test for 21143 and type 3. */ if((*p & 0x80) || (ctlr->pcidev->did == 0x0019 && *(p+1) == 3)){ *p |= 0x80; if(*(p+1) == 1 || *(p+1) == 3) phy = 1; if(*(p+1) == 5) ctlr->type5block = p; p += (*p & ~0x80)+1; } else{ debug("type0: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n", p[0], p[1], p[2], p[3]); if(ctlr->sct != 0x0800 && *p == (ctlr->sct & 0xFF)) ctlr->sctk = k; p += 4; } } ctlr->curk = ctlr->sctk; debug("sct 0x%uX medium 0x%uX k %d curk %d phy %d\n", ctlr->sct, ctlr->medium, ctlr->k, ctlr->curk, phy); if(phy){ x = 0; for(k = 0; k < nelem(ctlr->phy); k++){ if((oui = miir(ctlr, k, 2)) == -1 || oui == 0) continue; if(DEBUG){ oui = (oui & 0x3FF)<<6; oui |= miir(ctlr, k, 3)>>10; miir(ctlr, k, 1); debug("phy%d: index %d oui %uX reg1 %uX\n", x, k, oui, miir(ctlr, k, 1)); } ctlr->phy[x] = k; } } ctlr->fd = 0; ctlr->medium = -1; return 0; } static void dec2114xpci(void) { Ctlr *ctlr; Pcidev *p; int cfdd; p = nil; while(p = pcimatch(p, 0x1011, 0)){ switch(p->did){ default: break; case 0x0019: /* 21143 */ /* * Exit sleep mode. */ cfdd = pcicfgr32(p, 0x40); cfdd &= ~0xc0000000; pcicfgw32(p, 0x40, cfdd); /*FALLTHROUGH*/ case 0x0009: /* 21140 */ ctlr = malloc(sizeof(Ctlr)); /* * bar[0] is the I/O port register address and * bar[1] is the memory-mapped register address. */ ctlr->port = p->mem[0].bar & ~0x01; ctlr->pcidev = p; /* * Some cards (e.g. ANA-6910FX) seem to need the Ps bit * set or they don't always work right after a hardware * reset. */ csr32w(ctlr, 6, Mbo|Ps); softreset(ctlr); if(srom(ctlr)){ free(ctlr); break; } if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; break; } } } static int reset(Ether* ether) { Ctlr *ctlr; int i, x; uchar ea[Eaddrlen]; static int scandone; if(scandone == 0){ dec2114xpci(); scandone = 1; } /* * Any adapter matches if no ether->port is supplied, * otherwise the ports must match. */ for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){ if(ctlr->active) continue; if(ether->port == 0 || ether->port == ctlr->port){ ctlr->active = 1; break; } } if(ctlr == nil) return -1; ether->ctlr = ctlr; ether->port = ctlr->port; ether->irq = ctlr->pcidev->intl; ether->tbdf = ctlr->pcidev->tbdf; /* * Check if the adapter's station address is to be overridden. * If not, read it from the EEPROM and set in ether->ea prior to * loading the station address in the hardware. */ memset(ea, 0, Eaddrlen); if(memcmp(ea, ether->ea, Eaddrlen) == 0) memmove(ether->ea, ctlr->sromea, Eaddrlen); /* * Look for a medium override in case there's no autonegotiation * (no MII) or the autonegotiation fails. */ for(i = 0; i < ether->nopt; i++){ if(cistrcmp(ether->opt[i], "FD") == 0){ ctlr->fd = 1; continue; } for(x = 0; x < nelem(mediatable); x++){ debug("compare <%s> <%s>\n", mediatable[x], ether->opt[i]); if(cistrcmp(mediatable[x], ether->opt[i])) continue; ctlr->medium = x; switch(ctlr->medium){ default: ctlr->fd = 0; break; case 0x04: /* 10BASE-TFD */ case 0x05: /* 100BASE-TXFD */ case 0x08: /* 100BASE-FXFD */ ctlr->fd = 1; break; } break; } } ether->mbps = media(ether, 1); /* * Initialise descriptor rings, ethernet address. */ ctlr->nrdr = Nrde; ctlr->ntdr = Ntde; ctlrinit(ether); /* * Linkage to the generic ethernet driver. */ ether->attach = attach; ether->transmit = transmit; ether->interrupt = interrupt; ether->ifstat = ifstat; ether->arg = ether; ether->promiscuous = promiscuous; return 0; } void ether2114xlink(void) { addethercard("21140", reset); } . ## diffname pc/ether2114x.c 1999/0314 ## diff -e /n/emeliedump/1999/0312/sys/src/brazil/pc/ether2114x.c /n/emeliedump/1999/0314/sys/src/brazil/pc/ether2114x.c 1394a pcisetbme(ctlr->pcidev); . 1311a if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; . 1305,1309c if(srom(ctlr)){ free(ctlr); . 1300,1303c /* * Some cards (e.g. ANA-6910FX) seem to need the Ps bit * set or they don't always work right after a hardware * reset. */ csr32w(ctlr, 6, Mbo|Ps); softreset(ctlr); . 1292,1298c /* * bar[0] is the I/O port register address and * bar[1] is the memory-mapped register address. */ ctlr = malloc(sizeof(Ctlr)); ctlr->port = p->mem[0].bar & ~0x01; ctlr->pcidev = p; . 1284,1290c break; } . 1278,1280c x = pcicfgr32(p, 0x40); x &= ~0xc0000000; pcicfgw32(p, 0x40, x); . 1272c continue; . 1266c int x; . 1249a USED(oui); . 875a USED(mc); . ## diffname pc/ether2114x.c 1999/0402 ## diff -e /n/emeliedump/1999/0314/sys/src/brazil/pc/ether2114x.c /n/emeliedump/1999/0402/sys/src/brazil/pc/ether2114x.c 1237,1238c debug("sct 0x%uX medium 0x%uX k %d curk %d phy %d\n", ctlr->sct, ctlr->medium, ctlr->k, ctlr->curk, phy); . 1229,1230c debug("type0: 0x%2.2uX 0x%2.2uX 0x%2.2uX 0x%2.2uX\n", p[0], p[1], p[2], p[3]); . 830c debug("csr6 0x%8.8uX 0x%8.8uX 0x%8.8luX\n", csr6, ctlr->csr6, csr32r(ctlr, 6)); . ## diffname pc/ether2114x.c 1999/0711 ## diff -e /n/emeliedump/1999/0402/sys/src/brazil/pc/ether2114x.c /n/emeliedump/1999/0711/sys/src/brazil/pc/ether2114x.c 818,819c else if(bmcr & 0x2000){ /* * If FD capable, force it if necessary. */ if((bmsr & 0x4000) && ctlr->fd){ miiw(ctlr, ctlr->curphyad, Bmcr, 0x2100); x = 0x4000; } else x = 0x2000; } . ## diffname pc/ether2114x.c 1999/0714 ## diff -e /n/emeliedump/1999/0711/sys/src/brazil/pc/ether2114x.c /n/emeliedump/1999/0714/sys/src/brazil/pc/ether2114x.c 1306a if(ioalloc(ctlr->port, p->mem[0].size, 0, "dec2114x") < 0){ print("dec2114x: port %d in use\n", ctlr->port); free(ctlr); continue; } . ## diffname pc/ether2114x.c 1999/0715 ## diff -e /n/emeliedump/1999/0714/sys/src/brazil/pc/ether2114x.c /n/emeliedump/1999/0715/sys/src/brazil/pc/ether2114x.c 1434a addethercard("2114x", reset); . ## diffname pc/ether2114x.c 2000/0619 ## diff -e /n/emeliedump/1999/0715/sys/src/brazil/pc/ether2114x.c /n/emeliedump/2000/0619/sys/src/9/pc/ether2114x.c 1308c print("dec2114x: port 0x%uX in use\n", ctlr->port); . ## diffname pc/ether2114x.c 2000/0718 ## diff -e /n/emeliedump/2000/0619/sys/src/9/pc/ether2114x.c /n/emeliedump/2000/0718/sys/src/9/pc/ether2114x.c 1322a break; } switch(ctlr->id){ default: break; case Pnic: /* PNIC */ /* * Turn off the jabber timer. */ csr32w(ctlr, 15, 0x00000001); . 1305a ctlr->id = (p->did<<16)|p->vid; . 1295c case Pnic: /* PNIC */ case Pnic2: /* PNIC-II */ case Tulip0: /* 21140 */ . 1286c case Tulip3: /* 21143 */ . 1281,1282c while(p = pcimatch(p, 0, 0)){ if(p->ccrb != 0x02 || p->ccru != 0) continue; switch((p->did<<16)|p->vid){ . 1230c if((*p & 0x80) || (ctlr->id == Tulip3 && *(p+1) == 3)){ . 1215c if(ctlr->id != Tulip3){ . 1182a * Fake up the SROM for the PNIC. * It looks like a 21140 with a PHY. * The MAC address is byte-swapped in the orginal SROM data. */ if(ctlr->id == Pnic){ memmove(&ctlr->srom[20], leafpnic, sizeof(leafpnic)); for(i = 0; i < Eaddrlen; i += 2){ ctlr->srom[20+i] = ctlr->srom[i+1]; ctlr->srom[20+i+1] = ctlr->srom[i]; } } /* . 1141a /* * Copied to ctlr->srom at offset 20. */ static uchar leafpnic[] = { 0x00, 0x00, 0x00, 0x00, /* MAC address */ 0x00, 0x00, 0x00, /* controller 0 device number */ 0x1E, 0x00, /* controller 0 info leaf offset */ 0x00, /* reserved */ 0x00, 0x08, /* selected connection type */ 0x00, /* general purpose control */ 0x01, /* block count */ 0x8C, /* format indicator and count */ 0x01, /* block type */ 0x00, /* PHY number */ 0x00, /* GPR sequence length */ 0x00, /* reset sequence length */ 0x00, 0x78, /* media capabilities */ 0xE0, 0x01, /* Nway advertisment */ 0x00, 0x50, /* FDX bitmap */ 0x00, 0x18, /* TTM bitmap */ }; . 763c if(ctlr->id != Tulip3){ . 692a if(ctlr->id == Pnic){ i = 1000; csr32w(ctlr, 19, 0x600|r); do{ microdelay(1); data = csr32r(ctlr, 19); }while((data & 0x80000000) && --i); return csr32r(ctlr, 9) & 0xFFFF; } . 656a if(ctlr->id == Pnic){ i = 1000; csr32w(ctlr, 20, 0x60020000|(phyad<<23)|(regad<<18)); do{ microdelay(1); data = csr32r(ctlr, 20); }while((data & 0x80000000) && --i); if(i == 0) return -1; return data & 0xFFFF; } . 655c int data, i; . 584a csr32w(ctlr, 5, ctlr->mask); . 583a /* * Clear any bits in the Status Register (CSR5) as * the PNIC has a different reset value from a true 2114x. */ . 571c des->control = Rbsz; . 569c des->bp = allocb(Rbsz); . 467c des->control |= Rbsz; . 458c else if(bp = iallocb(Rbsz)){ . 189a int id; /* (pcidev->did<<16)|pcidev->vid */ . 183a enum { /* Variants */ Tulip0 = (0x0009<<16)|0x1011, Tulip3 = (0x0019<<16)|0x1011, Pnic = (0x0002<<16)|0x11AD, Pnic2 = (0xC115<<16)|0x11AD, }; . 29a #define Rbsz ROUNDUP(sizeof(Etherpkt)+4, 4) . 22c #define DEBUG (1) . ## diffname pc/ether2114x.c 2000/0727 ## diff -e /n/emeliedump/2000/0718/sys/src/9/pc/ether2114x.c /n/emeliedump/2000/0727/sys/src/9/pc/ether2114x.c 1404c continue; . 1402a iofree(ctlr->port); . 22c #define DEBUG (0) . ## diffname pc/ether2114x.c 2001/0504 ## diff -e /n/emeliedump/2000/0727/sys/src/9/pc/ether2114x.c /n/emeliedump/2001/0504/sys/src/9/pc/ether2114x.c 610c bp = iallocb(Eaddrlen*2*16); if(bp == nil) panic("can't allocate ethernet setup buffer"); . 579c des->bp = iallocb(Rbsz); if(des->bp == nil) panic("can't allocate ethernet receive ring"); . ## diffname pc/ether2114x.c 2001/0527 ## diff -e /n/emeliedump/2001/0504/sys/src/9/pc/ether2114x.c /n/emeliedump/2001/0527/sys/src/9/pc/ether2114x.c 614c panic("can't allocate ethernet setup buffer\n"); . 581c panic("can't allocate ethernet receive ring\n"); . ## diffname pc/ether2114x.c 2001/0721 ## diff -e /n/emeliedump/2001/0527/sys/src/9/pc/ether2114x.c /n/emeliedump/2001/0721/sys/src/9/pc/ether2114x.c 1221c sromr(ctlr, 0); for(i = 0; i < (1<sromsz); i++){ . 1219a * Do a dummy read first to get the size * and allocate ctlr->srom. . 770a if(ctlr->sromsz == 0){ ctlr->sromsz = 8-size; ctlr->srom = malloc((1<sromsz)*sizeof(ushort)); goto reread; } . 758a microdelay(1); if(!(csr32r(ctlr, 9) & Sdo)) break; . 754,755c /* * First time through must work out the EEPROM size. */ if((size = ctlr->sromsz) == 0) size = 8; for(size = size-1; size >= 0; size--){ data = Rd|Ss|(((r>>size) & 0x01)<<2)|Scs; . 740a reread: . 723c int i, op, data, size; . 350c for(i = 0; i < (1<sromsz); i++){ . 201c uchar* srom; int sromsz; /* address size in bits */ . ## diffname pc/ether2114x.c 2001/0830 ## diff -e /n/emeliedump/2001/0721/sys/src/9/pc/ether2114x.c /n/emeliedump/2001/0830/sys/src/9/pc/ether2114x.c 1240a if(ctlr->srom == nil) ctlr->srom = malloc((1<sromsz)*sizeof(ushort)); . 1237,1238c * Do a dummy read first to get the size and allocate ctlr->srom. . 784d 733a if(ctlr->sromsz == 0) ctlr->sromsz = 6; . ## diffname pc/ether2114x.c 2001/1023 ## diff -e /n/emeliedump/2001/0830/sys/src/9/pc/ether2114x.c /n/emeliedump/2001/1023/sys/src/9/pc/ether2114x.c 1093a return 0; break; case 4: if(typesymmode(ctlr, block, wait)) . 1001a typesymmode(Ctlr *ctlr, uchar *block, int wait) { uint gpmode, gpdata, command; USED(wait); gpmode = block[3] | ((uint) block[4] << 8); gpdata = block[5] | ((uint) block[6] << 8); command = (block[7] | ((uint) block[8] << 8)) & 0x71; if (command & 0x8000) { print("ether2114x.c: FIXME: handle type 4 mode blocks where cmd.active_invalid != 0\n"); return -1; } csr32w(ctlr, 15, gpmode); csr32w(ctlr, 15, gpdata); ctlr->csr6 = (command & 0x71) << 18; csr32w(ctlr, 6, ctlr->csr6); return 0; } static int . 595c csr32w(ctlr, 4, PCIWADDR(ctlr->tdr)); . 589c csr32w(ctlr, 3, PCIWADDR(ctlr->rdr)); . 585c des->addr = PCIWADDR(des->bp->rp); . 578c ctlr->rdr = xspanalloc(ctlr->nrdr*sizeof(Des), 8*sizeof(ulong), 0); . 474c des->addr = PCIWADDR(bp->rp); . 389c des->addr = PCIWADDR(bp->rp); . ## diffname pc/ether2114x.c 2001/1026 ## diff -e /n/emeliedump/2001/1023/sys/src/9/pc/ether2114x.c /n/emeliedump/2001/1026/sys/src/9/pc/ether2114x.c 351c for(i = 0; i < (1<<(ctlr->sromsz)*sizeof(ushort)); i++){ . ## diffname pc/ether2114x.c 2001/1101 ## diff -e /n/emeliedump/2001/1026/sys/src/9/pc/ether2114x.c /n/emeliedump/2001/1101/sys/src/9/pc/ether2114x.c 1116a debug("type4: medium %d block[2] %d\n", ctlr->medium, block[2]); if(ctlr->medium >= 0 && ((block[2] & 0x3F) != ctlr->medium)) return 0; . 1111a case 2: debug("type2: medium %d block[2] %d\n", ctlr->medium, block[2]); if(ctlr->medium >= 0 && ((block[2] & 0x3F) != ctlr->medium)) return 0; if(type2mode(ctlr, block, wait)) return 0; break; . 1021a type2mode(Ctlr* ctlr, uchar* block, int) { uchar *p; int csr6, csr13, csr14, csr15, gpc, gpd; csr6 = Sc|Mbo|Ca|Sb|TrMODE; debug("type2mode: medium 0x%2.2uX\n", block[2]); /* * Don't attempt full-duplex * unless explicitly requested. */ if((block[2] & 0x3F) == 0x04){ /* 10BASE-TFD */ if(!ctlr->fd) return -1; csr6 |= Fd; } /* * Operating mode programming values from the datasheet * unless media specific data is explicitly given. */ p = &block[3]; if(block[2] & 0x40){ csr13 = (block[4]<<8)|block[3]; csr14 = (block[6]<<8)|block[5]; csr15 = (block[8]<<8)|block[7]; p += 6; } else switch(block[2] & 0x3F){ default: return -1; case 0x00: /* 10BASE-T */ csr13 = 0x00000001; csr14 = 0x00007F3F; csr15 = 0x00000008; break; case 0x01: /* 10BASE-2 */ csr13 = 0x00000009; csr14 = 0x00000705; csr15 = 0x00000006; break; case 0x02: /* 10BASE-5 (AUI) */ csr13 = 0x00000009; csr14 = 0x00000705; csr15 = 0x0000000E; break; case 0x04: /* 10BASE-TFD */ csr13 = 0x00000001; csr14 = 0x00007F3D; csr15 = 0x00000008; break; } gpc = *p++<<16; gpc |= *p++<<24; gpd = *p++<<16; gpd |= *p<<24; csr32w(ctlr, 13, 0); csr32w(ctlr, 14, csr14); csr32w(ctlr, 15, gpc|csr15); delay(10); csr32w(ctlr, 15, gpd|csr15); csr32w(ctlr, 13, csr13); ctlr->csr6 = csr6; csr32w(ctlr, 6, ctlr->csr6); debug("type2mode: csr13 %8.8uX csr14 %8.8uX csr15 %8.8uX\n", csr13, csr14, csr15); debug("type2mode: gpc %8.8uX gpd %8.8uX csr6 %8.8uX\n", gpc, gpd, csr6); return 0; } static int . ## diffname pc/ether2114x.c 2002/0711 ## diff -e /n/emeliedump/2001/1101/sys/src/9/pc/ether2114x.c /n/emeliedump/2002/0711/sys/src/9/pc/ether2114x.c 622c ether->oq = qopen(256*1024, Qmsg, 0, 0); . ## diffname pc/ether2114x.c 2002/1008 ## diff -e /n/emeliedump/2002/0711/sys/src/9/pc/ether2114x.c /n/emeliedump/2002/1008/sys/src/9/pc/ether2114x.c 1556a break; case CentaurP: /* * Nice - the register offsets change from *8 to *4 * for CSR16 and up... * CSR25/26 give the MAC address read from the SROM. * Don't really need to use this other than as a check, * the SROM will be read in anyway so the value there * can be used directly. */ debug("csr25 %8.8luX csr26 %8.8luX\n", inl(ctlr->port+0xA4), inl(ctlr->port+0xA8)); debug("phyidr1 %4.4luX phyidr2 %4.4luX\n", inl(ctlr->port+0xBC), inl(ctlr->port+0xC0)); . 1515c case CentaurP: /* ADMtek */ . 1512a case Tulip0: /* 21140 */ . 1470a debug("phy reg 2 %4.4uX\n", oui); . 1468a if(ctlr->id == CentaurP && k != 1) continue; . 1396a if(ctlr->id == CentaurP){ memmove(&ctlr->srom[20], leafpnic, sizeof(leafpnic)); for(i = 0; i < Eaddrlen; i += 2){ ctlr->srom[20+i] = ctlr->srom[8+i]; ctlr->srom[20+i+1] = ctlr->srom[8+i+1]; } } . 1386,1388c * Fake up the SROM for the PNIC and AMDtek. * They look like a 21140 with a PHY. * The MAC address is byte-swapped in the orginal * PNIC SROM data. . 1364c * There are at least 2 SROM layouts: . 992c for(timeo = 0; timeo < 45; timeo++){ . 190a CentaurP = (0x0985<<16)|0x1317, .