123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883 |
- /*
- * Intel 82557 Fast Ethernet PCI Bus LAN Controller
- * as found on the Intel EtherExpress PRO/100B. This chip is full
- * of smarts, unfortunately none of them are in the right place.
- * To do:
- * the PCI scanning code could be made common to other adapters;
- * PCI code needs rewritten to handle byte, word, dword accesses
- * and using the devno as a bus+dev+function triplet.
- */
- #include "u.h"
- #include "lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "etherif.h"
- enum {
- Nrfd = 4, /* receive frame area */
- NullPointer = 0xFFFFFFFF, /* 82557 NULL pointer */
- };
- enum { /* CSR */
- Status = 0x00, /* byte or word (word includes Ack) */
- Ack = 0x01, /* byte */
- CommandR = 0x02, /* byte or word (word includes Interrupt) */
- Interrupt = 0x03, /* byte */
- Pointer = 0x04, /* dword */
- Port = 0x08, /* dword */
- Fcr = 0x0C, /* Flash control register */
- Ecr = 0x0E, /* EEPROM control register */
- Mcr = 0x10, /* MDI control register */
- };
- enum { /* Status */
- RUidle = 0x0000,
- RUsuspended = 0x0004,
- RUnoresources = 0x0008,
- RUready = 0x0010,
- RUrbd = 0x0020, /* bit */
- RUstatus = 0x003F, /* mask */
- CUidle = 0x0000,
- CUsuspended = 0x0040,
- CUactive = 0x0080,
- CUstatus = 0x00C0, /* mask */
- StatSWI = 0x0400, /* SoftWare generated Interrupt */
- StatMDI = 0x0800, /* MDI r/w done */
- StatRNR = 0x1000, /* Receive unit Not Ready */
- StatCNA = 0x2000, /* Command unit Not Active (Active->Idle) */
- StatFR = 0x4000, /* Finished Receiving */
- StatCX = 0x8000, /* Command eXecuted */
- StatTNO = 0x8000, /* Transmit NOT OK */
- };
- enum { /* Command (byte) */
- CUnop = 0x00,
- CUstart = 0x10,
- CUresume = 0x20,
- LoadDCA = 0x40, /* Load Dump Counters Address */
- DumpSC = 0x50, /* Dump Statistical Counters */
- LoadCUB = 0x60, /* Load CU Base */
- ResetSA = 0x70, /* Dump and Reset Statistical Counters */
- RUstart = 0x01,
- RUresume = 0x02,
- RUabort = 0x04,
- LoadHDS = 0x05, /* Load Header Data Size */
- LoadRUB = 0x06, /* Load RU Base */
- RBDresume = 0x07, /* Resume frame reception */
- };
- enum { /* Interrupt (byte) */
- InterruptM = 0x01, /* interrupt Mask */
- InterruptSI = 0x02, /* Software generated Interrupt */
- };
- enum { /* Ecr */
- EEsk = 0x01, /* serial clock */
- EEcs = 0x02, /* chip select */
- EEdi = 0x04, /* serial data in */
- EEdo = 0x08, /* serial data out */
- EEstart = 0x04, /* start bit */
- EEread = 0x02, /* read opcode */
- };
- enum { /* Mcr */
- MDIread = 0x08000000, /* read opcode */
- MDIwrite = 0x04000000, /* write opcode */
- MDIready = 0x10000000, /* ready bit */
- MDIie = 0x20000000, /* interrupt enable */
- };
- typedef struct Rfd {
- int field;
- ulong link;
- ulong rbd;
- ushort count;
- ushort size;
- Etherpkt;
- } Rfd;
- enum { /* field */
- RfdCollision = 0x00000001,
- RfdIA = 0x00000002, /* IA match */
- RfdRxerr = 0x00000010, /* PHY character error */
- RfdType = 0x00000020, /* Type frame */
- RfdRunt = 0x00000080,
- RfdOverrun = 0x00000100,
- RfdBuffer = 0x00000200,
- RfdAlignment = 0x00000400,
- RfdCRC = 0x00000800,
- RfdOK = 0x00002000, /* frame received OK */
- RfdC = 0x00008000, /* reception Complete */
- RfdSF = 0x00080000, /* Simplified or Flexible (1) Rfd */
- RfdH = 0x00100000, /* Header RFD */
- RfdI = 0x20000000, /* Interrupt after completion */
- RfdS = 0x40000000, /* Suspend after completion */
- RfdEL = 0x80000000, /* End of List */
- };
- enum { /* count */
- RfdF = 0x00004000,
- RfdEOF = 0x00008000,
- };
- typedef struct Cb {
- int command;
- ulong link;
- uchar data[24]; /* CbIAS + CbConfigure */
- } Cb;
- typedef struct TxCB {
- int command;
- ulong link;
- ulong tbd;
- ushort count;
- uchar threshold;
- uchar number;
- } TxCB;
- enum { /* action command */
- CbOK = 0x00002000, /* DMA completed OK */
- CbC = 0x00008000, /* execution Complete */
- CbNOP = 0x00000000,
- CbIAS = 0x00010000, /* Indvidual Address Setup */
- CbConfigure = 0x00020000,
- CbMAS = 0x00030000, /* Multicast Address Setup */
- CbTransmit = 0x00040000,
- CbDump = 0x00060000,
- CbDiagnose = 0x00070000,
- CbCommand = 0x00070000, /* mask */
- CbSF = 0x00080000, /* CbTransmit */
- CbI = 0x20000000, /* Interrupt after completion */
- CbS = 0x40000000, /* Suspend after completion */
- CbEL = 0x80000000, /* End of List */
- };
- enum { /* CbTransmit count */
- CbEOF = 0x00008000,
- };
- typedef struct Ctlr Ctlr;
- typedef struct Ctlr {
- int port;
- Pcidev* pcidev;
- Ctlr* next;
- int active;
- int eepromsz; /* address size in bits */
- ushort* eeprom;
- int ctlrno;
- char* type;
- uchar configdata[24];
- Rfd rfd[Nrfd];
- int rfdl;
- int rfdx;
- Block* cbqhead;
- Block* cbqtail;
- int cbqbusy;
- } Ctlr;
- static Ctlr* ctlrhead;
- static Ctlr* ctlrtail;
- static uchar configdata[24] = {
- 0x16, /* byte count */
- 0x44, /* Rx/Tx FIFO limit */
- 0x00, /* adaptive IFS */
- 0x00,
- 0x04, /* Rx DMA maximum byte count */
- 0x84, /* Tx DMA maximum byte count */
- 0x33, /* late SCB, CNA interrupts */
- 0x01, /* discard short Rx frames */
- 0x00, /* 503/MII */
- 0x00,
- 0x2E, /* normal operation, NSAI */
- 0x00, /* linear priority */
- 0x60, /* inter-frame spacing */
- 0x00,
- 0xF2,
- 0x48, /* promiscuous mode off */
- 0x00,
- 0x40,
- 0xF2, /* transmit padding enable */
- 0x80, /* full duplex pin enable */
- 0x3F, /* no Multi IA */
- 0x05, /* no Multi Cast ALL */
- };
- #define csr8r(c, r) (inb((c)->port+(r)))
- #define csr16r(c, r) (ins((c)->port+(r)))
- #define csr32r(c, r) (inl((c)->port+(r)))
- #define csr8w(c, r, b) (outb((c)->port+(r), (int)(b)))
- #define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w)))
- #define csr32w(c, r, l) (outl((c)->port+(r), (ulong)(l)))
- static void
- custart(Ctlr* ctlr)
- {
- if(ctlr->cbqhead == 0){
- ctlr->cbqbusy = 0;
- return;
- }
- ctlr->cbqbusy = 1;
- csr32w(ctlr, Pointer, PADDR(ctlr->cbqhead->rp));
- while(csr8r(ctlr, CommandR))
- ;
- csr8w(ctlr, CommandR, CUstart);
- }
- static void
- action(Ctlr* ctlr, Block* bp)
- {
- Cb *cb;
- cb = (Cb*)bp->rp;
- cb->command |= CbEL;
- if(ctlr->cbqhead){
- ctlr->cbqtail->next = bp;
- cb = (Cb*)ctlr->cbqtail->rp;
- cb->link = PADDR(bp->rp);
- cb->command &= ~CbEL;
- }
- else
- ctlr->cbqhead = bp;
- ctlr->cbqtail = bp;
- if(ctlr->cbqbusy == 0)
- custart(ctlr);
- }
- static void
- attach(Ether* ether)
- {
- int status;
- Ctlr *ctlr;
- ctlr = ether->ctlr;
- status = csr16r(ctlr, Status);
- if((status & RUstatus) == RUidle){
- csr32w(ctlr, Pointer, PADDR(&ctlr->rfd[ctlr->rfdx]));
- while(csr8r(ctlr, CommandR))
- ;
- csr8w(ctlr, CommandR, RUstart);
- }
- }
- static void
- configure(void* arg, int promiscuous)
- {
- Ctlr *ctlr;
- Block *bp;
- Cb *cb;
- ctlr = ((Ether*)arg)->ctlr;
- bp = allocb(sizeof(Cb));
- cb = (Cb*)bp->rp;
- bp->wp += sizeof(Cb);
- cb->command = CbConfigure;
- cb->link = NullPointer;
- memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata));
- if(promiscuous)
- cb->data[15] |= 0x01;
- action(ctlr, bp);
- }
- static void
- transmit(Ether* ether)
- {
- Block *bp;
- TxCB *txcb;
- RingBuf *tb;
- for(tb = ðer->tb[ether->ti]; tb->owner == Interface; tb = ðer->tb[ether->ti]){
- bp = allocb(tb->len+sizeof(TxCB));
- txcb = (TxCB*)bp->wp;
- bp->wp += sizeof(TxCB);
- txcb->command = CbTransmit;
- txcb->link = NullPointer;
- txcb->tbd = NullPointer;
- txcb->count = CbEOF|tb->len;
- txcb->threshold = 2;
- txcb->number = 0;
- memmove(bp->wp, tb->pkt, tb->len);
- memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen);
- bp->wp += tb->len;
- action(ether->ctlr, bp);
- tb->owner = Host;
- ether->ti = NEXT(ether->ti, ether->ntb);
- }
- }
- static void
- interrupt(Ureg*, void* arg)
- {
- Rfd *rfd;
- Block *bp;
- Ctlr *ctlr;
- Ether *ether;
- int status;
- RingBuf *rb;
- ether = arg;
- ctlr = ether->ctlr;
- for(;;){
- status = csr16r(ctlr, Status);
- csr8w(ctlr, Ack, (status>>8) & 0xFF);
- if((status & (StatCX|StatFR|StatCNA|StatRNR)) == 0)
- return;
- if(status & StatFR){
- rfd = &ctlr->rfd[ctlr->rfdx];
- while(rfd->field & RfdC){
- rb = ðer->rb[ether->ri];
- if(rb->owner == Interface){
- rb->owner = Host;
- rb->len = rfd->count & 0x3FFF;
- memmove(rb->pkt, rfd->d, rfd->count & 0x3FFF);
- ether->ri = NEXT(ether->ri, ether->nrb);
- }
- /*
- * Reinitialise the frame for reception and bump
- * the receive frame processing index;
- * bump the sentinel index, mark the new sentinel
- * and clear the old sentinel suspend bit;
- * set bp and rfd for the next receive frame to
- * process.
- */
- rfd->field = 0;
- rfd->count = 0;
- ctlr->rfdx = NEXT(ctlr->rfdx, Nrfd);
- rfd = &ctlr->rfd[ctlr->rfdl];
- ctlr->rfdl = NEXT(ctlr->rfdl, Nrfd);
- ctlr->rfd[ctlr->rfdl].field |= RfdS;
- rfd->field &= ~RfdS;
- rfd = &ctlr->rfd[ctlr->rfdx];
- }
- status &= ~StatFR;
- }
- if(status & StatRNR){
- while(csr8r(ctlr, CommandR))
- ;
- csr8w(ctlr, CommandR, RUresume);
- status &= ~StatRNR;
- }
- if(status & StatCNA){
- while(bp = ctlr->cbqhead){
- if((((Cb*)bp->rp)->command & CbC) == 0)
- break;
- ctlr->cbqhead = bp->next;
- freeb(bp);
- }
- custart(ctlr);
- status &= ~StatCNA;
- }
- if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI))
- panic("%s#%d: status %uX", ctlr->type, ctlr->ctlrno, status);
- }
- }
- static void
- ctlrinit(Ctlr* ctlr)
- {
- int i;
- Rfd *rfd;
- ulong link;
- link = NullPointer;
- for(i = Nrfd-1; i >= 0; i--){
- rfd = &ctlr->rfd[i];
- rfd->field = 0;
- rfd->link = link;
- link = PADDR(rfd);
- rfd->rbd = NullPointer;
- rfd->count = 0;
- rfd->size = sizeof(Etherpkt);
- }
- ctlr->rfd[Nrfd-1].link = PADDR(&ctlr->rfd[0]);
- ctlr->rfdl = 0;
- ctlr->rfd[0].field |= RfdS;
- ctlr->rfdx = 2;
- memmove(ctlr->configdata, configdata, sizeof(configdata));
- }
- static int
- miir(Ctlr* ctlr, int phyadd, int regadd)
- {
- int mcr, timo;
- csr32w(ctlr, Mcr, MDIread|(phyadd<<21)|(regadd<<16));
- mcr = 0;
- for(timo = 64; timo; timo--){
- mcr = csr32r(ctlr, Mcr);
- if(mcr & MDIready)
- break;
- microdelay(1);
- }
- if(mcr & MDIready)
- return mcr & 0xFFFF;
- return -1;
- }
- static int
- miiw(Ctlr* ctlr, int phyadd, int regadd, int data)
- {
- int mcr, timo;
- csr32w(ctlr, Mcr, MDIwrite|(phyadd<<21)|(regadd<<16)|(data & 0xFFFF));
- mcr = 0;
- for(timo = 64; timo; timo--){
- mcr = csr32r(ctlr, Mcr);
- if(mcr & MDIready)
- break;
- microdelay(1);
- }
- if(mcr & MDIready)
- return 0;
- return -1;
- }
- static int
- hy93c46r(Ctlr* ctlr, int r)
- {
- int data, i, op, size;
- /*
- * Hyundai HY93C46 or equivalent serial EEPROM.
- * This sequence for reading a 16-bit register 'r'
- * in the EEPROM is taken straight from Section
- * 3.3.4.2 of the Intel 82557 User's Guide.
- */
- reread:
- csr16w(ctlr, Ecr, EEcs);
- op = EEstart|EEread;
- for(i = 2; i >= 0; i--){
- data = (((op>>i) & 0x01)<<2)|EEcs;
- csr16w(ctlr, Ecr, data);
- csr16w(ctlr, Ecr, data|EEsk);
- microdelay(1);
- csr16w(ctlr, Ecr, data);
- microdelay(1);
- }
- /*
- * First time through must work out the EEPROM size.
- */
- if((size = ctlr->eepromsz) == 0)
- size = 8;
- for(size = size-1; size >= 0; size--){
- data = (((r>>size) & 0x01)<<2)|EEcs;
- csr16w(ctlr, Ecr, data);
- csr16w(ctlr, Ecr, data|EEsk);
- delay(1);
- csr16w(ctlr, Ecr, data);
- microdelay(1);
- if(!(csr16r(ctlr, Ecr) & EEdo))
- break;
- }
- data = 0;
- for(i = 15; i >= 0; i--){
- csr16w(ctlr, Ecr, EEcs|EEsk);
- microdelay(1);
- if(csr16r(ctlr, Ecr) & EEdo)
- data |= (1<<i);
- csr16w(ctlr, Ecr, EEcs);
- microdelay(1);
- }
- csr16w(ctlr, Ecr, 0);
- if(ctlr->eepromsz == 0){
- ctlr->eepromsz = 8-size;
- ctlr->eeprom = malloc((1<<ctlr->eepromsz)*sizeof(ushort));
- goto reread;
- }
- return data;
- }
- static void
- i82557pci(void)
- {
- Pcidev *p;
- Ctlr *ctlr;
- p = nil;
- while(p = pcimatch(p, 0x8086, 0)){
- switch(p->did){
- default:
- continue;
- case 0x1031: /* Intel 82562EM */
- case 0x1050: /* Intel 82562EZ */
- case 0x1039: /* Intel 82801BD PRO/100 VE */
- case 0x103A: /* Intel 82562 PRO/100 VE */
- case 0x1064: /* Intel 82562 PRO/100 VE */
- case 0x2449: /* Intel 82562ET */
- case 0x27DC: /* Intel 82801G PRO/100 VE */
- case 0x1209: /* Intel 82559ER */
- case 0x1229: /* Intel 8255[789] */
- case 0x1030: /* Intel 82559 InBusiness 10/100 */
- break;
- }
- /*
- * bar[0] is the memory-mapped register address (4KB),
- * bar[1] is the I/O port register address (32 bytes) and
- * bar[2] is for the flash ROM (1MB).
- */
- ctlr = malloc(sizeof(Ctlr));
- ctlr->port = p->mem[1].bar & ~0x01;
- ctlr->pcidev = p;
- if(ctlrhead != nil)
- ctlrtail->next = ctlr;
- else
- ctlrhead = ctlr;
- ctlrtail = ctlr;
- pcisetbme(p);
- }
- }
- static void
- detach(Ether* ether)
- {
- Ctlr *ctlr;
- ctlr = ether->ctlr;
- csr32w(ctlr, Port, 0);
- delay(1);
- while(csr8r(ctlr, CommandR))
- ;
- }
- static int
- scanphy(Ctlr* ctlr)
- {
- int i, oui, x;
- for(i = 0; i < 32; i++){
- if((oui = miir(ctlr, i, 2)) == -1 || oui == 0 || oui == 0xFFFF)
- continue;
- oui <<= 6;
- x = miir(ctlr, i, 3);
- oui |= x>>10;
- //print("phy%d: oui %uX reg1 %uX\n", i, oui, miir(ctlr, i, 1));
- if(oui == 0xAA00)
- ctlr->eeprom[6] = 0x07<<8;
- else if(oui == 0x80017){
- if(x & 0x01)
- ctlr->eeprom[6] = 0x0A<<8;
- else
- ctlr->eeprom[6] = 0x04<<8;
- }
- return i;
- }
- return -1;
- }
- int
- i82557reset(Ether* ether)
- {
- int anar, anlpar, bmcr, bmsr, force, i, phyaddr, x;
- unsigned short sum;
- Block *bp;
- uchar ea[Eaddrlen];
- Ctlr *ctlr;
- Cb *cb;
- if(ctlrhead == nil)
- i82557pci();
- /*
- * 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;
- /*
- * Initialise the Ctlr structure.
- * Perform a software reset after which need to ensure busmastering
- * is still enabled. The EtherExpress PRO/100B appears to leave
- * the PCI configuration alone (see the 'To do' list above) so punt
- * for now.
- * Load the RUB and CUB registers for linear addressing (0).
- */
- ether->ctlr = ctlr;
- ether->port = ctlr->port;
- ether->irq = ctlr->pcidev->intl;
- ether->tbdf = ctlr->pcidev->tbdf;
- ctlr->ctlrno = ether->ctlrno;
- ctlr->type = ether->type;
- csr32w(ctlr, Port, 0);
- delay(1);
- while(csr8r(ctlr, CommandR))
- ;
- csr32w(ctlr, Pointer, 0);
- csr8w(ctlr, CommandR, LoadRUB);
- while(csr8r(ctlr, CommandR))
- ;
- csr8w(ctlr, CommandR, LoadCUB);
- /*
- * Initialise the action and receive frame areas.
- */
- ctlrinit(ctlr);
- /*
- * Read the EEPROM.
- * Do a dummy read first to get the size
- * and allocate ctlr->eeprom.
- */
- hy93c46r(ctlr, 0);
- sum = 0;
- for(i = 0; i < (1<<ctlr->eepromsz); i++){
- x = hy93c46r(ctlr, i);
- ctlr->eeprom[i] = x;
- sum += x;
- }
- if(sum != 0xBABA)
- print("#l%d: EEPROM checksum - 0x%4.4uX\n", ether->ctlrno, sum);
- /*
- * Eeprom[6] indicates whether there is a PHY and whether
- * it's not 10Mb-only, in which case use the given PHY address
- * to set any PHY specific options and determine the speed.
- * Unfortunately, sometimes the EEPROM is blank except for
- * the ether address and checksum; in this case look at the
- * controller type and if it's am 82558 or 82559 it has an
- * embedded PHY so scan for that.
- * If no PHY, assume 82503 (serial) operation.
- */
- if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000))
- phyaddr = ctlr->eeprom[6] & 0x00FF;
- else
- switch(ctlr->pcidev->rid){
- case 0x01: /* 82557 A-step */
- case 0x02: /* 82557 B-step */
- case 0x03: /* 82557 C-step */
- default:
- phyaddr = -1;
- break;
- case 0x04: /* 82558 A-step */
- case 0x05: /* 82558 B-step */
- case 0x06: /* 82559 A-step */
- case 0x07: /* 82559 B-step */
- case 0x08: /* 82559 C-step */
- case 0x09: /* 82559ER A-step */
- phyaddr = scanphy(ctlr);
- break;
- }
- if(phyaddr >= 0){
- /*
- * Resolve the highest common ability of the two
- * link partners. In descending order:
- * 0x0100 100BASE-TX Full Duplex
- * 0x0200 100BASE-T4
- * 0x0080 100BASE-TX
- * 0x0040 10BASE-T Full Duplex
- * 0x0020 10BASE-T
- */
- anar = miir(ctlr, phyaddr, 0x04);
- anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0;
- anar &= anlpar;
- bmcr = 0;
- if(anar & 0x380)
- bmcr = 0x2000;
- if(anar & 0x0140)
- bmcr |= 0x0100;
- switch((ctlr->eeprom[6]>>8) & 0x001F){
- case 0x04: /* DP83840 */
- case 0x0A: /* DP83840A */
- /*
- * The DP83840[A] requires some tweaking for
- * reliable operation.
- * The manual says bit 10 should be unconditionally
- * set although it supposedly only affects full-duplex
- * operation (an & 0x0140).
- */
- x = miir(ctlr, phyaddr, 0x17) & ~0x0520;
- x |= 0x0420;
- for(i = 0; i < ether->nopt; i++){
- if(cistrcmp(ether->opt[i], "congestioncontrol"))
- continue;
- x |= 0x0100;
- break;
- }
- miiw(ctlr, phyaddr, 0x17, x);
- /*
- * If the link partner can't autonegotiate, determine
- * the speed from elsewhere.
- */
- if(anlpar == 0){
- miir(ctlr, phyaddr, 0x01);
- bmsr = miir(ctlr, phyaddr, 0x01);
- x = miir(ctlr, phyaddr, 0x19);
- if((bmsr & 0x0004) && !(x & 0x0040))
- bmcr = 0x2000;
- }
- break;
- case 0x07: /* Intel 82555 */
- /*
- * Auto-negotiation may fail if the other end is
- * a DP83840A and the cable is short.
- */
- bmsr = miir(ctlr, phyaddr, 0x01);
- if((miir(ctlr, phyaddr, 0) & 0x1000) && !(bmsr & 0x0020)){
- miiw(ctlr, phyaddr, 0x1A, 0x2010);
- x = miir(ctlr, phyaddr, 0);
- miiw(ctlr, phyaddr, 0, 0x0200|x);
- for(i = 0; i < 3000; i++){
- delay(1);
- if(miir(ctlr, phyaddr, 0x01) & 0x0020)
- break;
- }
- miiw(ctlr, phyaddr, 0x1A, 0x2000);
-
- anar = miir(ctlr, phyaddr, 0x04);
- anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0;
- anar &= anlpar;
- bmcr = 0;
- if(anar & 0x380)
- bmcr = 0x2000;
- if(anar & 0x0140)
- bmcr |= 0x0100;
- }
- break;
- }
- /*
- * Force speed and duplex if no auto-negotiation.
- */
- if(anlpar == 0){
- force = 0;
- for(i = 0; i < ether->nopt; i++){
- if(cistrcmp(ether->opt[i], "fullduplex") == 0){
- force = 1;
- bmcr |= 0x0100;
- ctlr->configdata[19] |= 0x40;
- }
- else if(cistrcmp(ether->opt[i], "speed") == 0){
- force = 1;
- x = strtol(ðer->opt[i][6], 0, 0);
- if(x == 10)
- bmcr &= ~0x2000;
- else if(x == 100)
- bmcr |= 0x2000;
- else
- force = 0;
- }
- }
- if(force)
- miiw(ctlr, phyaddr, 0x00, bmcr);
- }
- ctlr->configdata[8] = 1;
- ctlr->configdata[15] &= ~0x80;
- }
- else{
- ctlr->configdata[8] = 0;
- ctlr->configdata[15] |= 0x80;
- }
- /*
- * Load the chip configuration
- */
- configure(ether, 0);
- /*
- * 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 with the Individual Address Setup command.
- */
- memset(ea, 0, Eaddrlen);
- if(memcmp(ea, ether->ea, Eaddrlen) == 0){
- for(i = 0; i < Eaddrlen/2; i++){
- x = ctlr->eeprom[i];
- ether->ea[2*i] = x & 0xFF;
- ether->ea[2*i+1] = (x>>8) & 0xFF;
- }
- }
- bp = allocb(sizeof(Cb));
- cb = (Cb*)bp->rp;
- bp->wp += sizeof(Cb);
- cb->command = CbIAS;
- cb->link = NullPointer;
- memmove(cb->data, ether->ea, Eaddrlen);
- action(ctlr, bp);
- /*
- * Linkage to the generic ethernet driver.
- */
- ether->attach = attach;
- ether->transmit = transmit;
- ether->interrupt = interrupt;
- ether->detach = detach;
- return 0;
- }
|