12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538 |
- /*
- * 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)print
- enum {
- Nrde = 4,
- 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,
- 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;
- 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 void
- attach(Ether* ether)
- {
- Ctlr *ctlr;
- ctlr = ether->ctlr;
- if(!(ctlr->csr6 & Sr)){
- ctlr->csr6 |= Sr;
- csr32w(ctlr, 6, ctlr->csr6);
- }
- }
- static void
- transmit(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 void
- interrupt(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 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 = 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 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<<i);
- csr9w(ctlr, Mii|Mdc);
- csr9w(ctlr, Mii);
- }
- csr9w(ctlr, 0);
- return data;
- }
- static void
- miimdo(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 int
- miir(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);
- }while((data & 0x80000000) && --i);
- if(i == 0)
- return -1;
- return data & 0xFFFF;
- }
- /*
- * 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 void
- miiw(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 int
- sromr(Ctlr* ctlr, int r)
- {
- int i, op, data, size;
- if(ctlr->id == Pnic){
- i = 1000;
- csr32w(ctlr, 19, 0x600|r);
- do{
- microdelay(1);
- data = csr32r(ctlr, 19);
- }while((data & 0x80000000) && --i);
- if(ctlr->sromsz == 0)
- ctlr->sromsz = 6;
- return csr32r(ctlr, 9) & 0xFFFF;
- }
- /*
- * 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.
- */
- reread:
- 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);
- }
- /*
- * 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;
- csr9w(ctlr, data);
- csr9w(ctlr, data|Sclk);
- csr9w(ctlr, data);
- microdelay(1);
- if(!(csr32r(ctlr, 9) & Sdo))
- break;
- }
- 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);
- if(ctlr->sromsz == 0){
- ctlr->sromsz = 8-size;
- goto reread;
- }
- return data & 0xFFFF;
- }
- static void
- softreset(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 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->id != Tulip3){
- 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){
- /*
- * If FD capable, force it if necessary.
- */
- if((bmsr & 0x4000) && ctlr->fd){
- miiw(ctlr, ctlr->curphyad, Bmcr, 0x2100);
- x = 0x4000;
- }
- else
- 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%8.8uX 0x%8.8uX 0x%8.8luX\n",
- csr6, ctlr->csr6, csr32r(ctlr, 6));
- 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);
- USED(mc);
- 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<<phyx))){
- debug("reset seq: len %d: ", block[3]);
- if(ctlr->type5block)
- type5block(ctlr, &ctlr->type5block[2]);
- else
- type5block(ctlr, &block[4+len*block[3]]);
- debug("\n");
- ctlr->phyreset |= (1<<phyx);
- }
- /*
- * GPR sequence.
- */
- debug("gpr seq: len %d: ", block[3]);
- type5block(ctlr, &block[3]);
- debug("\n");
- ctlr->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
- 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
- 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
- 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 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;
- case 3:
- if(typephymode(ctlr, block, wait))
- return 0;
- break;
- case 4:
- debug("type4: medium %d block[2] %d\n",
- ctlr->medium, block[2]);
- if(ctlr->medium >= 0 && ((block[2] & 0x3F) != ctlr->medium))
- return 0;
- if(typesymmode(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 */
- 0,
- };
- /*
- * 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 */
- };
- 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.
- */
- sromr(ctlr, 0);
- if(ctlr->srom == nil)
- ctlr->srom = malloc((1<<ctlr->sromsz)*sizeof(ushort));
- for(i = 0; i < (1<<ctlr->sromsz); 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;
- }
- }
- /*
- * 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];
- }
- }
- /*
- * 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->id != Tulip3){
- 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->id == Tulip3 && *(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));
- USED(oui);
- }
- ctlr->phy[x] = k;
- }
- }
- ctlr->fd = 0;
- ctlr->medium = -1;
- return 0;
- }
- static void
- dec2114xpci(void)
- {
- Ctlr *ctlr;
- Pcidev *p;
- int x;
- p = nil;
- while(p = pcimatch(p, 0, 0)){
- if(p->ccrb != 0x02 || p->ccru != 0)
- continue;
- switch((p->did<<16)|p->vid){
- default:
- continue;
- case Tulip3: /* 21143 */
- /*
- * Exit sleep mode.
- */
- x = pcicfgr32(p, 0x40);
- x &= ~0xc0000000;
- pcicfgw32(p, 0x40, x);
- /*FALLTHROUGH*/
- case Pnic: /* PNIC */
- case Pnic2: /* PNIC-II */
- case Tulip0: /* 21140 */
- break;
- }
- /*
- * 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;
- ctlr->id = (p->did<<16)|p->vid;
- debug("2114x: type 0x%8.8uX at port 0x%4.4uX\n",
- ctlr->id, ctlr->port);
- /*
- * 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;
- }
- switch(ctlr->id){
- default:
- break;
- case Pnic: /* PNIC */
- /*
- * Turn off the jabber timer.
- */
- csr32w(ctlr, 15, 0x00000001);
- break;
- }
- if(ctlrhead != nil)
- ctlrtail->next = ctlr;
- else
- ctlrhead = ctlr;
- ctlrtail = ctlr;
- }
- }
- static void
- detach(Ether* ether)
- {
- softreset(ether->ctlr);
- }
- int
- ether2114xreset(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;
- }
- }
- /*
- * Determine media.
- */
- ctlr->mbps = media(ether, 1);
- /*
- * Initialise descriptor rings, ethernet address.
- */
- ctlr->nrdr = Nrde;
- ctlr->ntdr = Ntde;
- pcisetbme(ctlr->pcidev);
- ctlrinit(ether);
- /*
- * Linkage to the generic ethernet driver.
- */
- ether->attach = attach;
- ether->transmit = transmit;
- ether->interrupt = interrupt;
- ether->detach = detach;
- return 0;
- }
|