## diffname pc/ether82557.c 1996/0418 ## diff -e /dev/null /n/fornaxdump/1996/0418/sys/src/brazil/pc/ether82557.c 0a /* * 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; * stats. */ #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" enum { Nrfd = 64, /* receive frame area */ NullPointer = 0xFFFFFFFF, /* 82557 NULL pointer */ }; enum { /* CSR */ Status = 0x00, /* byte or word (word includes Ack) */ Ack = 0x01, /* byte */ Command = 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 */ EEaddrsz = 6, /* bits of address */ }; 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; Block* bp; } 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 { int port; int ctlrno; char* type; uchar configdata[24]; Lock rlock; Block* rfd[Nrfd]; int rfdl; int rfdx; Lock cbqlock; Block* cbqhead; Block* cbqtail; int cbqbusy; } Ctlr; 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, Command)) ; csr8w(ctlr, Command, CUstart); } static void action(Ctlr* ctlr, Block* bp) { Cb *cb; ilock(&ctlr->cbqlock); 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); iunlock(&ctlr->cbqlock); } static void attach(Ether* ether) { int status; Ctlr *ctlr; ctlr = ether->ctlr; ilock(&ctlr->rlock); status = csr16r(ctlr, Status); if((status & RUstatus) == RUidle){ csr32w(ctlr, Pointer, PADDR(ctlr->rfd[ctlr->rfdx]->rp)); while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, RUstart); } iunlock(&ctlr->rlock); } 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 long write(Ether* ether, void* buf, long n) { Block *bp; TxCB *txcb; bp = allocb(n+sizeof(TxCB)); txcb = (TxCB*)bp->wp; bp->wp += sizeof(TxCB); txcb->command = CbTransmit; txcb->link = NullPointer; txcb->tbd = NullPointer; txcb->count = CbEOF|n; txcb->threshold = 2; txcb->number = 0; memmove(bp->wp, buf, n); memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); bp->wp += n; action(ether->ctlr, bp); ether->outpackets++; return n; } static void interrupt(Ureg*, void* arg) { Rfd *rfd; Block *bp; Ctlr *ctlr; Ether *ether; int status; 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){ bp = ctlr->rfd[ctlr->rfdx]; rfd = (Rfd*)bp->rp; while(rfd->field & RfdC){ etherrloop(ether, rfd, rfd->count & 0x3FFF); ether->inpackets++; /* * 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 = (Rfd*)ctlr->rfd[ctlr->rfdl]->rp; ctlr->rfdl = NEXT(ctlr->rfdl, Nrfd); ((Rfd*)ctlr->rfd[ctlr->rfdl]->rp)->field |= RfdS; rfd->field &= ~RfdS; bp = ctlr->rfd[ctlr->rfdx]; rfd = (Rfd*)bp->rp; } status &= ~StatFR; } if(status & StatRNR){ while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, RUresume); status &= ~StatRNR; } if(status & StatCNA){ lock(&ctlr->cbqlock); while(bp = ctlr->cbqhead){ if((((Cb*)bp->rp)->command & CbC) == 0) break; ctlr->cbqhead = bp->next; freeb(bp); } custart(ctlr); unlock(&ctlr->cbqlock); status &= ~StatCNA; } if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) panic("%s#%d: status %uX\n", ctlr->type, ctlr->ctlrno, status); } } static void ctlrinit(Ctlr* ctlr) { int i; Block *bp; Rfd *rfd; ulong link; link = NullPointer; for(i = Nrfd-1; i >= 0; i--){ if(ctlr->rfd[i] == 0){ bp = allocb(sizeof(Rfd)); ctlr->rfd[i] = bp; } else bp = ctlr->rfd[i]; rfd = (Rfd*)bp->rp; rfd->field = 0; rfd->link = link; link = PADDR(rfd); rfd->rbd = NullPointer; rfd->count = 0; rfd->size = sizeof(Etherpkt); rfd->bp = bp; } ((Rfd*)ctlr->rfd[Nrfd-1]->rp)->link = PADDR(ctlr->rfd[0]->rp); ctlr->rfdl = 0; ((Rfd*)ctlr->rfd[0]->rp)->field |= RfdS; ctlr->rfdx = 2; memmove(ctlr->configdata, configdata, sizeof(configdata)); } static int dp83840r(Ctlr* ctlr, int phyadd, int regadd) { int mcr, timo; /* * DP83840 * 10/100Mb/s Ethernet Physical Layer. */ csr32w(ctlr, Mcr, MDIread|(phyadd<<21)|(regadd<<16)); mcr = 0; for(timo = 10; timo; timo--){ mcr = csr32r(ctlr, Mcr); if(mcr & MDIready) break; delay(1); } if(mcr & MDIready) return mcr & 0xFFFF; return -1; } static int hy93c46r(Ctlr* ctlr, int r) { int i, op, data; /* * Hyundai HY93C46 or equivalent serial EEPROM. * This sequence for reading a 16-bit register 'r' * in the EEPROM is taken straight from Section * 2.3.4.2 of the Intel 82557 User's Guide. */ 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); delay(1); csr16w(ctlr, Ecr, data); delay(1); } for(i = EEaddrsz-1; i >= 0; i--){ data = (((r>>i) & 0x01)<<2)|EEcs; csr16w(ctlr, Ecr, data); csr16w(ctlr, Ecr, data|EEsk); delay(1); csr16w(ctlr, Ecr, data); delay(1); if((csr16r(ctlr, Ecr) & EEdo) == 0) break; } data = 0; for(i = 15; i >= 0; i--){ csr16w(ctlr, Ecr, EEcs|EEsk); delay(1); if(csr16r(ctlr, Ecr) & EEdo) data |= (1<port == 0 || ether->port == port){ ether->irq = irq; *pcidevno = devno-1; return port; } } if(port == 0) continue; ap = malloc(sizeof(Adapter)); ap->port = port; ap->irq = irq; ap->pcidevno = devno-1; ap->next = adapter; adapter = ap; } return 0; } static int reset(Ether* ether) { int i, pcidevno, port, x; Adapter *ap, **app; uchar ea[Eaddrlen]; Ctlr *ctlr; Block *bp; Cb *cb; /* * Any adapter matches if no ether->port is supplied, otherwise the * ports must match. First see if an adapter that fits the bill has * already been found. If not, scan for another. */ port = 0; pcidevno = -1; for(app = &adapter, ap = *app; ap; app = &ap->next, ap = ap->next){ if(ether->port == 0 || ether->port == ap->port){ ether->irq = ap->irq; pcidevno = ap->pcidevno; *app = ap->next; free(ap); break; } } if(port == 0 && (port = i82557(ether, &pcidevno)) == 0) return -1; /* * Allocate a controller structure and start to initialise it. * 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 = malloc(sizeof(Ctlr)); ctlr = ether->ctlr; ctlr->ctlrno = ether->ctlrno; ctlr->type = ether->type; ctlr->port = port; csr32w(ctlr, Port, 0); delay(1); pcicfgr(0, pcidevno, 0, 0x04, &x, 4); if((x & 0x05) != 0x05) print("PCI command = %uX\n", x); csr32w(ctlr, Pointer, 0); csr8w(ctlr, Command, LoadRUB); while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, LoadCUB); while(csr8r(ctlr, Command)) ; /* * Initialise the action and receive frame areas. */ ctlrinit(ctlr); /* * Possibly need to configure the physical-layer chip here, but the * EtherExpress PRO/100B appears to bring it up with a sensible default * configuration. However, should check for the existence of the PHY * and, if found, check whether to use 82503 (serial) or MII (nibble) * mode. Verify the PHY is a National Semiconductor DP83840 by looking * at the Organizationally Unique Identifier (OUI) in registers 2 and 3 * which should be 0x80017. */ for(i = 1; i < 32; i++){ if((x = dp83840r(ctlr, i, 2)) == 0xFFFF) continue; x <<= 6; x |= dp83840r(ctlr, i, 3)>>10; if(x != 0x80017) continue; x = dp83840r(ctlr, i, 0x1B); if((x & 0x0200) == 0){ ctlr->configdata[8] = 1; ctlr->configdata[15] |= 0x80; } break; } /* * 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 = hy93c46r(ctlr, 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->port = port; ether->attach = attach; ether->write = write; ether->interrupt = interrupt; ether->promiscuous = configure; ether->arg = ether; return 0; } void ether82557link(void) { addethercard("i82557", reset); } . ## diffname pc/ether82557.c 1996/0419 ## diff -e /n/fornaxdump/1996/0418/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0419/sys/src/brazil/pc/ether82557.c 440,441d 111,112d ## diffname pc/ether82557.c 1996/0423 ## diff -e /n/fornaxdump/1996/0419/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0423/sys/src/brazil/pc/ether82557.c 629c * Initialise the receive frame and configuration areas. . 626a csr8w(ctlr, Command, LoadCUB); . 624c csr8w(ctlr, Command, LoadRUB); . 620,621c csr32w(ctlr, General, 0); . 281c csr32w(ctlr, General, PADDR(ctlr->rfd[ctlr->rfdx]->rp)); . 240c csr32w(ctlr, General, PADDR(ctlr->cbqhead->rp)); . 159c CbIAS = 0x00010000, /* Individual Address Setup */ . 33c General = 0x04, /* dword */ . 8a * tidy/fix locking; * optionally use memory-mapped registers; . ## diffname pc/ether82557.c 1996/0601 ## diff -e /n/fornaxdump/1996/0423/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0601/sys/src/brazil/pc/ether82557.c 655c ctlr->configdata[15] &= ~0x80; ether->mbps = 100; . 217c 0xC8, /* promiscuous mode off */ . ## diffname pc/ether82557.c 1996/0607 ## diff -e /n/fornaxdump/1996/0601/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0607/sys/src/brazil/pc/ether82557.c 697c ether->promiscuous = promiscuous; . 695a ether->ifstat = ifstat; . 688a iunlock(&ctlr->rlock); . 664c bp = configure(ctlr, 0); action(ctlr, bp); . 641,642c * at the Organizationally Unique Identifier (OUI) in registers 2 and * 3 which should be 0x80017. . 629a while(csr8r(ctlr, Command)) ; csr32w(ctlr, General, PADDR(ctlr->dump)); csr8w(ctlr, Command, LoadDCA); . 625a . 624a csr32w(ctlr, General, 0); . 618,622d 614a ilock(&ctlr->rlock); . 413a iunlock(&ctlr->rlock); . 406d 398d 392a print("%s#%d: status %uX\n", ctlr->type, ctlr->ctlrno, status); . 363,364c if(rfd->field & RfdOK){ etherrloop(ether, rfd, rfd->count & 0x3FFF); ether->inpackets++; } else print("%s#%d: rfd->field %uX\n", ctlr->type, ctlr->ctlrno, rfd->field); . 356,357c if((status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) == 0) break; . 351a ilock(&ctlr->rlock); . 333c ctlr = ether->ctlr; ilock(&ctlr->rlock); action(ctlr, bp); iunlock(&ctlr->rlock); . 314a Ctlr *ctlr; . 312a ifstat(Ether* ether, void* a, long n, ulong offset) { Ctlr *ctlr; char buf[512]; int len; ctlr = ether->ctlr; lock(&ctlr->dlock); ctlr->dump[16] = 0; ilock(&ctlr->rlock); while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, DumpSC); iunlock(&ctlr->rlock); /* * Wait for completion status, should be 0xA005. */ while(ctlr->dump[16] == 0) ; ether->oerrs = ctlr->dump[1]+ctlr->dump[2]+ctlr->dump[3]; ether->crcs = ctlr->dump[10]; ether->frames = ctlr->dump[11]; ether->buffs = ctlr->dump[12]+ctlr->dump[15]; ether->overflows = ctlr->dump[13]; if(n == 0){ unlock(&ctlr->dlock); return 0; } len = sprint(buf, "transmit good frames: %ld\n", ctlr->dump[0]); len += sprint(buf+len, "transmit maximum collisions errors: %ld\n", ctlr->dump[1]); len += sprint(buf+len, "transmit late collisions errors: %ld\n", ctlr->dump[2]); len += sprint(buf+len, "transmit underrun errors: %ld\n", ctlr->dump[3]); len += sprint(buf+len, "transmit lost carrier sense: %ld\n", ctlr->dump[4]); len += sprint(buf+len, "transmit deferred: %ld\n", ctlr->dump[5]); len += sprint(buf+len, "transmit single collisions: %ld\n", ctlr->dump[6]); len += sprint(buf+len, "transmit multiple collisions: %ld\n", ctlr->dump[7]); len += sprint(buf+len, "transmit total collisions: %ld\n", ctlr->dump[8]); len += sprint(buf+len, "receive good frames: %ld\n", ctlr->dump[9]); len += sprint(buf+len, "receive CRC errors: %ld\n", ctlr->dump[10]); len += sprint(buf+len, "receive alignment errors: %ld\n", ctlr->dump[11]); len += sprint(buf+len, "receive resource errors: %ld\n", ctlr->dump[12]); len += sprint(buf+len, "receive overrun errors: %ld\n", ctlr->dump[13]); len += sprint(buf+len, "receive collision detect errors: %ld\n", ctlr->dump[14]); sprint(buf+len, "receive short frame errors: %ld\n", ctlr->dump[15]); unlock(&ctlr->dlock); return readstr(offset, a, n, buf); } static long . 309a iunlock(&ctlr->rlock); . 308a return bp; } static void promiscuous(void* arg, int on) { Ctlr *ctlr; Block *bp; ctlr = ((Ether*)arg)->ctlr; bp = configure(ctlr, on); ilock(&ctlr->rlock); . 298,299d 294d 291,292c static Block* configure(Ctlr* ctlr, int promiscuous) . 285a csr32w(ctlr, General, PADDR(ctlr->rfd[ctlr->rfdx]->rp)); . 283d 269,270d 253d 244a csr32w(ctlr, General, PADDR(ctlr->cbqhead->rp)); . 242d 197a Lock dlock; /* dump statistical counters */ ulong dump[17]; . 194,195c Block* cbqhead; /* transmit side */ . 190c Block* rfd[Nrfd]; /* receive side */ . 188c Lock rlock; /* registers */ . 144c uchar data[24]; /* CbIAS + CbConfigure */ . 9,11c * optionally use memory-mapped registers. . ## diffname pc/ether82557.c 1996/0608 ## diff -e /n/fornaxdump/1996/0607/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0608/sys/src/brazil/pc/ether82557.c 466d 437d ## diffname pc/ether82557.c 1996/0622 ## diff -e /n/fornaxdump/1996/0608/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0622/sys/src/brazil/pc/ether82557.c 766c iunlock(&ctlr->lock); . 686c ilock(&ctlr->lock); . 669c if(port == 0 && (port = i82557pci(ether, &pcidevno)) == 0) . 603c i82557pci(Ether* ether, int* pcidevno) . 484c iunlock(&ctlr->lock); . 421c ilock(&ctlr->lock); . 402c iunlock(&ctlr->lock); . 400c ilock(&ctlr->lock); . 336c iunlock(&ctlr->lock); . 332c ilock(&ctlr->lock); . 318c iunlock(&ctlr->lock); . 316c ilock(&ctlr->lock); . 285c iunlock(&ctlr->lock); . 277c ilock(&ctlr->lock); . 196c Lock dlock; /* dump statistical counters */ . 186c Lock lock; . ## diffname pc/ether82557.c 1996/0625 ## diff -e /n/fornaxdump/1996/0622/sys/src/brazil/pc/ether82557.c /n/fornaxdump/1996/0625/sys/src/brazil/pc/ether82557.c 732c } else{ x = dp83840r(ctlr, i, 0x1B); if((x & 0x0200) == 0){ ctlr->configdata[8] = 1; ctlr->configdata[15] &= ~0x80; } . 728,729c x = dp83840r(ctlr, i, 0x19); if((x & 0x0040) == 0){ ether->mbps = 100; . 8a * auto-negotiation; . ## diffname pc/ether82557.c 1997/0327 ## diff -e /n/fornaxdump/1996/0625/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0327/sys/src/brazil/pc/ether82557.c 781c ether->transmit = transmit; . 774d 772c action(ctlr, cb); . 765,770c cb = cballoc(ctlr, CbIAS); . 760,761c ether->ea[2*i] = x; ether->ea[2*i+1] = x>>8; . 757c if(!memcmp(ea, ether->ea, Eaddrlen)){ . 748,749c configure(ctlr, 0); . 737c if(!(x & 0x0200)){ . 730c if(!(x & 0x0040)){ . 706d 704a iunlock(&ctlr->rlock); . 687,688c ilock(&ctlr->rlock); . 683,684d 670c if(port == 0 && (port = i82557pci(ether)) == 0) . 664,666c ether->tbdf = ap->tbdf; *bpp = bp->next; freeb(bp); . 662a port = ap->port; . 660,661c bpp = &adapter; for(bp = *bpp; bp; bp = bp->next){ ap = (Adapter*)bp->rp; . 651d 647,648c int i, port, x; Block *bp, **bpp; Adapter *ap; . 633,638c i82557adapter(&adapter, port, irq, p->tbdf); . 630,631d 617,628c bp->next = *bpp; *bpp = bp; } static int i82557pci(Ether* ether) { static Pcidev *p; int irq, port; while(p = pcimatch(p, 0x8086, 0x1229)){ /* * 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). */ port = p->bar[1] & ~0x01; irq = p->intl; if(ether->port == 0 || ether->port == port){ ether->irq = irq; ether->tbdf = p->tbdf; return port; . 611,615c bp = allocb(sizeof(Adapter)); ap = (Adapter*)bp->rp; ap->port = port; ap->irq = irq; ap->tbdf = tbdf; . 606,608c Block *bp; . 603,604c static void i82557adapter(Block** bpp, int port, int irq, int tbdf) . 594,601c typedef struct Adapter { int port; int irq; int tbdf; } Adapter; static Block* adapter; . 575c if(!(csr16r(ctlr, Ecr) & EEdo)) . 515,518d 513c ctlr->rfdtail->next = ctlr->rfdhead; rfd = (Rfd*)ctlr->rfdtail->rp; rfd->link = PADDR(ctlr->rfdhead->rp); rfd->field |= RfdS; ctlr->rfdhead = ctlr->rfdhead->next; . 497,511c for(i = 0; i < Nrfd; i++){ bp = rfdalloc(link); if(ctlr->rfdhead == nil) ctlr->rfdtail = bp; bp->next = ctlr->rfdhead; ctlr->rfdhead = bp; link = PADDR(bp->rp); . 495a /* * Create the Receive Frame Area (RFA) as a ring of allocated * buffers. * A sentinel buffer is maintained between the last buffer in * the ring (marked with RfdS) and the head buffer to defeat the * hardware prefetch of the next RFD and allow dynamic buffer * allocation. */ . 485d 483c panic("#l%d: status %uX\n", ether->ctlrno, status); . 477a unlock(&ctlr->cbqlock); . 474,475c ctlr->cbqhead = cb->next; if(cb->bp) freeb(cb->bp); cbfree(ctlr, cb); . 471,472c lock(&ctlr->cbqlock); while(cb = ctlr->cbqhead){ if(!(cb->command & CbC)) . 465a unlock(&ctlr->rlock); . 462a lock(&ctlr->rlock); . 456c /* * Finally done with the current (possibly replaced) * head, move on to the next and maintain the sentinel * between tail and head. */ ctlr->rfdhead = bp->next; bp = ctlr->rfdhead; . 447,453c rfd = (Rfd*)ctlr->rfdtail->rp; ctlr->rfdtail = ctlr->rfdtail->next; ctlr->rfdtail->next = bp; ((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp); ((Rfd*)ctlr->rfdtail->rp)->field |= RfdS; . 440,445c * The ring tail pointer follows the head with with one * unused buffer in between to defeat hardware prefetch; * once the tail pointer has been bumped on to the next * and the new tail has the Suspend bit set, it can be * removed from the old tail buffer. * As a replacement for the current head buffer may have * been allocated above, ensure that the new tail points * to it (next and link). . 437a else{ rfd->field = 0; rfd->count = 0; } . 434,436c /* * If it's an OK receive frame and a replacement buffer * can be allocated then * adjust the received buffer pointers for the * actual data received; * initialise the replacement buffer to point to * the next in the ring; * pass the received buffer on for disposal; * initialise bp to point to the replacement. * If not, just adjust the necessary fields for reuse. */ if((rfd->field & RfdOK) && (xbp = rfdalloc(rfd->link))){ bp->rp += sizeof(Rfd)-sizeof(Etherpkt); bp->wp = bp->rp + (rfd->count & 0x3FFF); xbp->next = bp->next; bp->next = 0; etheriq(ether, bp, 1); bp = xbp; . 431c bp = ctlr->rfdhead; . 427c if(!(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI))) . 425a unlock(&ctlr->rlock); . 423a lock(&ctlr->rlock); . 422d 414c Cb* cb; Block *bp, *xbp; . 407c action(ctlr, cb); . 405c cb = cballoc(ctlr, CbSF|CbTransmit); cb->bp = bp; cb->tbd = PADDR(&cb->tba); cb->count = 0; cb->threshold = 2; cb->number = 1; cb->tba = PADDR(bp->rp); cb->tbasz = BLEN(bp); . 401,403d 389,399d 385,387c bp = qget(ether->oq); if(bp == nil) return; . 383c Cb *cb; . 378,379c static void transmit(Ether* ether) . 337c iunlock(&ctlr->rlock); . 333c ilock(&ctlr->rlock); . 311,319c configure(((Ether*)arg)->ctlr, on); . 304,305c action(ctlr, cb); . 295,300c cb = cballoc(ctlr, CbConfigure); . 292d 289c static void . 286c iunlock(&ctlr->rlock); . 283c csr32w(ctlr, General, PADDR(ctlr->rfdhead->rp)); . 278c ilock(&ctlr->rlock); . 268a iunlock(&ctlr->cbqlock); . 267c if(!ctlr->cbqbusy) . 264,265c ctlr->cbqhead = cb; ctlr->cbqtail = cb; . 258,261c tail = ctlr->cbqtail; tail->next = cb; tail->link = PADDR(&cb->command); tail->command &= ~CbEL; . 256a ilock(&ctlr->cbqlock); . 254d 252c Cb* tail; . 250c action(Ctlr* ctlr, Cb* cb) . 246a iunlock(&ctlr->rlock); . 245c csr32w(ctlr, General, PADDR(&ctlr->cbqhead->command)); . 242a ilock(&ctlr->rlock); . 234a cbfree(Ctlr* ctlr, Cb* cb) { ilock(&ctlr->cbplock); cb->next = ctlr->cbpool; ctlr->cbpool = cb; iunlock(&ctlr->cbplock); } static void . 233a static Block* rfdalloc(ulong link) { Block *bp; Rfd *rfd; if(bp = iallocb(sizeof(Rfd))){ rfd = (Rfd*)bp->rp; rfd->field = 0; rfd->link = link; rfd->rbd = NullPointer; rfd->count = 0; rfd->size = sizeof(Etherpkt); } return bp; } static Cb* cballoc(Ctlr* ctlr, int command) { Cb *cb; ilock(&ctlr->cbplock); if(cb = ctlr->cbpool){ ctlr->cbpool = cb->next; iunlock(&ctlr->cbplock); cb->next = 0; cb->bp = 0; } else{ iunlock(&ctlr->cbplock); cb = smalloc(sizeof(Cb)); } cb->command = command; cb->link = NullPointer; return cb; } . 221c 0xF3, /* transmit padding enable */ . 206,209c 0x00, /* Rx DMA maximum byte count */ 0x80, /* Tx DMA maximum byte count */ 0x32, /* !late SCB, CNA interrupts */ 0x03, /* discard short Rx frames */ . 203c 0x08, /* Rx/Tx FIFO limit */ . 196a Lock cbplock; /* pool of free Cb's */ Cb* cbpool; . 193,194c Lock cbqlock; /* transmit side */ Cb* cbqhead; Cb* cbqtail; . 189,191c Lock rfdlock; /* receive side */ Block* rfdhead; Block* rfdtail; int nrfd; . 187c Lock rlock; /* registers */ . 181,184d 168c CbSF = 0x00080000, /* Flexible-mode CbTransmit */ . 154a ulong tba; ushort tbasz; ushort pad; }; }; } Cb; . 149,153c union { uchar data[24]; /* CbIAS + CbConfigure */ struct { ulong tbd; ushort count; uchar threshold; uchar number; . 146d 141,144c Cb* next; Block* bp; . 139a typedef struct Cb Cb; . 111c uchar data[sizeof(Etherpkt)]; . 7,8d ## diffname pc/ether82557.c 1997/0417 ## diff -e /n/emeliedump/1997/0327/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0417/sys/src/brazil/pc/ether82557.c 420c p = malloc(READSTR); len = snprint(p, READSTR, "transmit good frames: %ld\n", dump[0]); len += snprint(p+len, READSTR-len, "transmit maximum collisions errors: %ld\n", dump[1]); len += snprint(p+len, READSTR-len, "transmit late collisions errors: %ld\n", dump[2]); len += snprint(p+len, READSTR-len, "transmit underrun errors: %ld\n", dump[3]); len += snprint(p+len, READSTR-len, "transmit lost carrier sense: %ld\n", dump[4]); len += snprint(p+len, READSTR-len, "transmit deferred: %ld\n", dump[5]); len += snprint(p+len, READSTR-len, "transmit single collisions: %ld\n", dump[6]); len += snprint(p+len, READSTR-len, "transmit multiple collisions: %ld\n", dump[7]); len += snprint(p+len, READSTR-len, "transmit total collisions: %ld\n", dump[8]); len += snprint(p+len, READSTR-len, "receive good frames: %ld\n", dump[9]); len += snprint(p+len, READSTR-len, "receive CRC errors: %ld\n", dump[10]); len += snprint(p+len, READSTR-len, "receive alignment errors: %ld\n", dump[11]); len += snprint(p+len, READSTR-len, "receive resource errors: %ld\n", dump[12]); len += snprint(p+len, READSTR-len, "receive overrun errors: %ld\n", dump[13]); len += snprint(p+len, READSTR-len, "receive collision detect errors: %ld\n", dump[14]); snprint(p+len, READSTR-len, "receive short frame errors: %ld\n", dump[15]); n = readstr(offset, a, n, p); free(p); return n; . 401,417c memmove(dump, ctlr->dump, sizeof(dump)); . 375a . 372a Ctlr *ctlr; ulong dump[17]; . 370,371c char *p; . ## diffname pc/ether82557.c 1997/0628 ## diff -e /n/emeliedump/1997/0417/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0628/sys/src/brazil/pc/ether82557.c 7a * full-duplex; . 4c * of smarts, unfortunately they're not all in the right place. . ## diffname pc/ether82557.c 1997/0723 ## diff -e /n/emeliedump/1997/0628/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0723/sys/src/brazil/pc/ether82557.c 804,805c if(x != 0x80017 && x != 0xAA00) print("#l%d: unrecognised PHY - OUI 0x%4.4uX\n", ether->ctlrno, x); . 795,797c * mode. Verify the PHY is a National Semiconductor DP83840 (OUI 0x80017) * or an Intel 82555 (OUI 0xAA00) by looking at the Organizationally Unique * Identifier (OUI) in registers 2 and 3. . 751c if(port == 0) . 749a bpp = &bp->next; . 732a if(scandone == 0){ i82557pci(); scandone = 1; } . 731a static int scandone; . 719,720d 709,717c i82557adapter(&adapter, p->bar[1] & ~0x01, p->intl, p->tbdf); . 702a p = nil; . 700,701c Pcidev *p; . 697,698c static void i82557pci(void) . 8d 4c * of smarts, unfortunately none of them are in the right place. . ## diffname pc/ether82557.c 1997/0806 ## diff -e /n/emeliedump/1997/0723/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0806/sys/src/brazil/pc/ether82557.c 830c if(memcmp(ea, ether->ea, Eaddrlen) == 0){ . 778c csr8w(ctlr, CommandR, LoadDCA); . 775c while(csr8r(ctlr, CommandR)) . 773c csr8w(ctlr, CommandR, LoadCUB); . 771c while(csr8r(ctlr, CommandR)) . 769c csr8w(ctlr, CommandR, LoadRUB); . 766c while(csr8r(ctlr, CommandR)) . 729,731c * Any adapter matches if no port is supplied, * otherwise the ports must match. . 540c csr8w(ctlr, CommandR, RUresume); . 538c while(csr8r(ctlr, CommandR)) . 383c csr8w(ctlr, CommandR, DumpSC); . 381c while(csr8r(ctlr, CommandR)) . 344c csr8w(ctlr, CommandR, RUstart); . 341c while(csr8r(ctlr, CommandR)) . 304c csr8w(ctlr, CommandR, CUstart); . 301c while(csr8r(ctlr, CommandR)) . 30c CommandR = 0x02, /* byte or word (word includes Interrupt) */ . 7a * full-duplex; . 4c * of smarts, unfortunately they're not all in the right place. . ## diffname pc/ether82557.c 1997/0807 ## diff -e /n/emeliedump/1997/0806/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0807/sys/src/brazil/pc/ether82557.c 408,423c len = snprint(p, READSTR, "transmit good frames: %lud\n", dump[0]); len += snprint(p+len, READSTR-len, "transmit maximum collisions errors: %lud\n", dump[1]); len += snprint(p+len, READSTR-len, "transmit late collisions errors: %lud\n", dump[2]); len += snprint(p+len, READSTR-len, "transmit underrun errors: %lud\n", dump[3]); len += snprint(p+len, READSTR-len, "transmit lost carrier sense: %lud\n", dump[4]); len += snprint(p+len, READSTR-len, "transmit deferred: %lud\n", dump[5]); len += snprint(p+len, READSTR-len, "transmit single collisions: %lud\n", dump[6]); len += snprint(p+len, READSTR-len, "transmit multiple collisions: %lud\n", dump[7]); len += snprint(p+len, READSTR-len, "transmit total collisions: %lud\n", dump[8]); len += snprint(p+len, READSTR-len, "receive good frames: %lud\n", dump[9]); len += snprint(p+len, READSTR-len, "receive CRC errors: %lud\n", dump[10]); len += snprint(p+len, READSTR-len, "receive alignment errors: %lud\n", dump[11]); len += snprint(p+len, READSTR-len, "receive resource errors: %lud\n", dump[12]); len += snprint(p+len, READSTR-len, "receive overrun errors: %lud\n", dump[13]); len += snprint(p+len, READSTR-len, "receive collision detect errors: %lud\n", dump[14]); snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]); . ## diffname pc/ether82557.c 1997/0823 ## diff -e /n/emeliedump/1997/0807/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/0823/sys/src/brazil/pc/ether82557.c 838,841c ilock(&ctlr->cblock); ctlr->action = CbIAS; txstart(ether); iunlock(&ctlr->cblock); . 822c if(ether->oq == 0) ether->oq = qopen(256*1024, 1, 0, 0); configure(ether, 0); command(ctlr, CUstart, PADDR(&ctlr->cbr->status)); . 820c * Load the chip configuration and start it off. . 783a ctlr->ncb = Ncb; . 782c * Initialise the receive frame, transmit ring and configuration areas. . 780a command(ctlr, LoadRUB, 0); command(ctlr, LoadCUB, 0); command(ctlr, LoadDCA, PADDR(ctlr->dump)); . 765,778d 752c * Perform a software reset after which should ensure busmastering . 721d 599a ctlr->threshold = 8; iunlock(&ctlr->cblock); . 598a /* * Create a ring of control blocks for the * transmit side. */ ilock(&ctlr->cblock); ctlr->cbr = malloc(ctlr->ncb*sizeof(Cb)); for(i = 0; i < ctlr->ncb; i++){ ctlr->cbr[i].status = CbC|CbOK; ctlr->cbr[i].command = CbS|CbNOP; ctlr->cbr[i].link = PADDR(&ctlr->cbr[NEXT(i, ctlr->ncb)].status); ctlr->cbr[i].next = &ctlr->cbr[NEXT(i, ctlr->ncb)]; } ctlr->cbhead = ctlr->cbr; ctlr->cbtail = ctlr->cbr; ctlr->cbq = 0; . 559a txstart(ether); unlock(&ctlr->cblock); . 557,558c ctlr->cbtail = cb; . 555c cb->bp = nil; } if((cb->status & CbU) && ctlr->threshold < 0xE0) ctlr->threshold++; ctlr->cbq--; cb = cb->next; . 552,553c if(cb->bp){ . 548,550c lock(&ctlr->cblock); cb = ctlr->cbtail; while(ctlr->cbq){ if(!(cb->status & CbC)) . 538,543c command(ctlr, RUresume, 0); . 453c static void transmit(Ether* ether) { Ctlr *ctlr; ctlr = ether->ctlr; ilock(&ctlr->cblock); txstart(ether); iunlock(&ctlr->cblock); . 444,451c static void promiscuous(void* arg, int on) { configure(arg, on); } . 442a ilock(&ctlr->cblock); if(promiscuous){ ctlr->configdata[6] |= 0x80; /* Save Bad Frames */ ctlr->configdata[6] &= ~0x40; /* !Discard Overrun Rx Frames */ ctlr->configdata[7] &= ~0x01; /* !Discard Short Rx Frames */ ctlr->configdata[15] |= 0x01; /* Promiscuous mode */ ctlr->configdata[18] &= ~0x01; /* (!Padding enable?), !stripping enable */ ctlr->configdata[21] |= 0x08; /* Multi Cast ALL */ } else{ ctlr->configdata[6] &= ~0x80; ctlr->configdata[7] |= 0x01; ctlr->configdata[15] &= ~0x01; ctlr->configdata[18] |= 0x01; /* 0x03? */ ctlr->configdata[21] &= ~0x08; } ctlr->action = CbConfigure; txstart(ether); iunlock(&ctlr->cblock); } . 441a cb->command = CbS|CbSF|CbTransmit; cb->tbd = PADDR(&cb->tba); cb->count = 0; cb->threshold = ctlr->threshold; cb->number = 1; cb->tba = PADDR(bp->rp); cb->bp = bp; cb->tbasz = BLEN(bp); } else if(ctlr->action == CbConfigure){ cb->command = CbS|CbConfigure; memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata)); ctlr->action = 0; } else if(ctlr->action == CbIAS){ cb->command = CbS|CbIAS; memmove(cb->data, ether->ea, Eaddrlen); ctlr->action = 0; } else{ print("#l%d: action 0x%uX\n", ether->ctlrno, ctlr->action); ctlr->action = 0; break; } cb->status = 0; ctlr->cbhead->command &= ~CbS; ctlr->cbhead = cb; ctlr->cbq++; } command(ctlr, CUresume, 0); if(ctlr->cbq > ctlr->cbqmax) ctlr->cbqmax = ctlr->cbq; } static void configure(Ether* ether, int promiscuous) { Ctlr *ctlr; . 438,440c ctlr = ether->ctlr; while(ctlr->cbq < (ctlr->ncb-1)){ cb = ctlr->cbhead->next; if(ctlr->action == 0){ bp = qget(ether->oq); if(bp == nil) break; . 432c txstart(Ether* ether) . 423c len += snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]); snprint(p+len, READSTR-len, "cbqmax: %lud\n", ctlr->cbqmax); ctlr->cbqmax = 0; . 389a ctlr->dump[16] = 0; command(ctlr, DumpSC, 0); . 388c * Start the command then * wait for completion status, * should be 0xA005. . 379,386d 350,367d 347c unlock(&ctlr->slock); . 339,345c lock(&ctlr->slock); if(ctlr->state == 0){ command(ctlr, RUstart, PADDR(ctlr->rfdhead->rp)); ctlr->state = 1; . 335d 284,332d 260,282d 241a static void command(Ctlr* ctlr, int c, int v) { ilock(&ctlr->rlock); /* * Only back-to-back CUresume can be done * without waiting for any previous command to complete. * This should be the common case. */ if(c == CUresume && ctlr->command == CUresume){ csr8w(ctlr, CommandR, c); iunlock(&ctlr->rlock); return; } while(csr8r(ctlr, CommandR)) ; switch(c){ case CUstart: case LoadDCA: case LoadCUB: case RUstart: case LoadHDS: case LoadRUB: csr32w(ctlr, General, v); break; /* case CUnop: case CUresume: case DumpSC: case ResetSA: case RUresume: case RUabort: */ default: break; } csr8w(ctlr, CommandR, c); ctlr->command = c; iunlock(&ctlr->rlock); } . 201,204d 196,199c Lock cblock; /* transmit side */ int action; uchar configdata[24]; int threshold; int ncb; Cb* cbr; Cb* cbhead; Cb* cbtail; int cbq; int cbqmax; . 191,192c Block* rfdhead; /* receive side */ . 189a int command; /* last command issued */ . 187d 185a Lock slock; /* attach */ int state; . 182c CbEOF = 0x8000, . 176,178c CbI = 0x2000, /* Interrupt after completion */ CbS = 0x4000, /* Suspend after completion */ CbEL = 0x8000, /* End of List */ . 174c CbSF = 0x0008, /* Flexible-mode CbTransmit */ . 165,172c CbNOP = 0x0000, CbIAS = 0x0001, /* Individual Address Setup */ CbConfigure = 0x0002, CbMAS = 0x0003, /* Multicast Address Setup */ CbTransmit = 0x0004, CbDump = 0x0006, CbDiagnose = 0x0007, CbCommand = 0x0007, /* mask */ . 162,163c CbU = 0x1000, /* transmit underrun */ CbOK = 0x2000, /* DMA completed OK */ CbC = 0x8000, /* execution Complete */ . 158a Block* bp; Cb* next; . 141,144c ushort status; ushort command; . 135,136c RfdF = 0x4000, RfdEOF = 0x8000, . 23a Ncb = 64, /* maximum control blocks queued */ . 7,9c * auto-negotiation, full-duplex; * optionally use memory-mapped registers; * detach for PCI reset problems (also towards loadable drivers). . ## diffname pc/ether82557.c 1997/1011 ## diff -e /n/emeliedump/1997/0823/sys/src/brazil/pc/ether82557.c /n/emeliedump/1997/1011/sys/src/brazil/pc/ether82557.c 760c i82557adapter(&adapter, p->mem[1].bar & ~0x01, p->intl, p->tbdf); . 263a */ . 258c * Unfortunately there's a chip errata where back-to-back * CUresumes can be lost, the fix is to always wait. . ## diffname pc/ether82557.c 1998/0304 ## diff -e /n/emeliedump/1997/1011/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0304/sys/src/brazil/pc/ether82557.c 878c x = ctlr->eeprom[i]; . 860a else{ ctlr->configdata[8] = 0; ctlr->configdata[15] |= 0x80; } . 859c ctlr->configdata[8] = 1; ctlr->configdata[15] &= ~0x80; . 857a if(an & 0x0140) x |= 0x0400; miiw(ctlr, phyaddr, 0x17, x); break; . 849,856c switch((ctlr->eeprom[6]>>8) & 0x001F){ case 0x04: /* DP83840 */ case 0x0A: /* DP83840A */ /* * The DP83840[A] requires some tweaking for * reliable operation. */ x = miir(ctlr, phyaddr, 0x17) & ~0x0520; x |= 0x0020; for(i = 0; i < ether->nopt; i++){ if(cistrcmp(ether->opt[i], "congestioncontrol")) continue; x |= 0x0100; break; . 846,847c /* * 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. * If no PHY, assume 82503 (serial) operation. */ if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)){ phyaddr = ctlr->eeprom[6] & 0x00FF; /* * 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 */ an = miir(ctlr, phyaddr, 0x04); an &= miir(ctlr, phyaddr, 0x05) & 0x03E0; if(an & 0x380) . 838,844c sum = 0; for(i = 0; i < 0x40; 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); . 830,836c * Read the EEPROM. . 769c int an, i, phyaddr, port, x; unsigned short sum; . 719c microdelay(1); . 715c microdelay(1); . 707c microdelay(1); . 698c microdelay(1); . 696c microdelay(1); . 688c * 3.3.4.2 of the Intel 82557 User's Guide. . 679a 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 . 670c microdelay(1); . 666c for(timo = 64; timo; timo--){ . 660,663d 656c miir(Ctlr* ctlr, int phyadd, int regadd) . 650a ctlr->tick = 0; . 507a /* * If the watchdog timer for the receiver lockup errata is running, * let it know the receiver is active. */ if(status & (StatFR|StatRNR)) ctlr->tick = 0; . 458a ctlr->configdata[6] |= 0x40; . 424a else if(ctlr->action == CbMAS){ cb->command = CbS|CbMAS; memset(cb->data, 0, sizeof(cb->data)); ctlr->action = 0; } . 382,383c if(ctlr->cbqmax > ctlr->cbqmaxhw) ctlr->cbqmaxhw = ctlr->cbqmax; len += snprint(p+len, READSTR-len, "cbqmax: %lud\n", ctlr->cbqmax); ctlr->cbqmax = 0; snprint(p+len, READSTR-len, "threshold: %lud\n", ctlr->threshold); . 325a /* * Start the watchdog timer for the receive lockup errata * unless the EEPROM compatibility word indicates it may be * omitted. */ if((ctlr->eeprom[0x03] & 0x0003) != 0x0003){ snprint(name, NAMELEN, "#l%dwatchdog", ether->ctlrno); kproc(name, watchdog, ether); } . 319a char name[NAMELEN]; . 316a watchdog(void* arg) { Ether *ether; Ctlr *ctlr; static void txstart(Ether*); ether = arg; for(;;){ ctlr = ether->ctlr; tsleep(&ctlr->timer, return0, 0, 4000); /* * Hmmm. This doesn't seem right. Currently * the device can't be disabled but it may be in * the future. */ ctlr = ether->ctlr; if(ctlr == nil || ctlr->state == 0){ print("%s: exiting\n", up->text); pexit("disabled", 0); } if(ctlr->tick++){ ilock(&ctlr->cblock); ctlr->action = CbMAS; txstart(ether); iunlock(&ctlr->cblock); } } } static void . 233c 0xC8, /* 503, promiscuous mode off */ . 210a int cbqmaxhw; . 193a Rendez timer; /* watchdog timer for receive lockup errata */ int tick; . 192a ushort eeprom[0x40]; . ## diffname pc/ether82557.c 1998/0331 ## diff -e /n/emeliedump/1998/0304/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0331/sys/src/brazil/pc/ether82557.c 656c iunlock(&ctlr->cblock); . 637c ilock(&ctlr->cblock); . 560c iunlock(&ctlr->rlock); . 557c ilock(&ctlr->rlock); . ## diffname pc/ether82557.c 1998/0507 ## diff -e /n/emeliedump/1998/0331/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0507/sys/src/brazil/pc/ether82557.c 1012a ether->multicast = multicast; . 532a multicast(void* arg, uchar *addr, int on) { USED(addr, on); configure(arg, 1); } static void . ## diffname pc/ether82557.c 1998/0511 ## diff -e /n/emeliedump/1998/0507/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0511/sys/src/brazil/pc/ether82557.c 972a case 0x07: /* Intel 82555 */ /* * Auto-negotiation may fail if the other end is * a DP83840A and the cable is short. */ miir(ctlr, phyaddr, 0x01); 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); . 971a /* * 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; } . 969,970d 962c x |= 0x0420; . 959a * The manual says bit 10 should be unconditionally * set although it supposedly only affects full-duplex * operation (an & 0x0140). . 948,951c 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; . 857c int anar, anlpar, bmcr, bmsr, force, i, phyaddr, port, x; . ## diffname pc/ether82557.c 1998/0522 ## diff -e /n/emeliedump/1998/0511/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0522/sys/src/brazil/pc/ether82557.c 623a coherence(); . 595c bp->rp += sizeof(Rfd)-sizeof(rfd->data); . 515c //ctlr->configdata[6] |= 0x40; . 507c //ctlr->configdata[6] &= ~0x40; /* !Discard Overrun Rx Frames */ . 487a coherence(); . 111c uchar data[1700]; . ## diffname pc/ether82557.c 1998/0825 ## diff -e /n/emeliedump/1998/0522/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0825/sys/src/brazil/pc/ether82557.c 434c snprint(p+len, READSTR-len, "threshold: %d\n", ctlr->threshold); . 432c len += snprint(p+len, READSTR-len, "cbqmax: %d\n", ctlr->cbqmax); . ## diffname pc/ether82557.c 1998/0929 ## diff -e /n/emeliedump/1998/0825/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0929/sys/src/brazil/pc/ether82557.c 1045c if(medium != -1) . 1034,1043d 1032a break; case 0x05: /* 100BASE-TXFD */ case 0x08: /* 100BASE-FXFD */ bmcr |= 0x2000|0x0100; ctlr->configdata[19] |= 0x40; break; . 1029,1031c for(k = 0; k < nelem(mediatable); k++){ if(cistrcmp(mediatable[k], ether->opt[i])) continue; medium = k; break; } switch(medium){ default: break; case 0x00: /* 10BASE-T */ case 0x01: /* 10BASE-2 */ case 0x02: /* 10BASE-5 */ bmcr &= ~(0x2000|0x0100); ctlr->configdata[19] &= ~0x40; break; case 0x03: /* 100BASE-TX */ case 0x06: /* 100BASE-T4 */ case 0x07: /* 100BASE-FX */ ctlr->configdata[19] &= ~0x40; bmcr |= 0x2000; break; case 0x04: /* 10BASE-TFD */ bmcr = (bmcr & ~0x2000)|0x0100; . 1027c medium = -1; . 859c int anar, anlpar, bmcr, bmsr, i, k, medium, phyaddr, port, x; . 855a 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", }; . 761a unlock(&ctlr->miilock); . 753a lock(&ctlr->miilock); . 741a unlock(&ctlr->miilock); . 733a lock(&ctlr->miilock); . 435a len += snprint(p+len, READSTR-len, "eeprom:"); for(i = 0; i < 0x40; i++){ if(i && ((i & 0x07) == 0)) len += snprint(p+len, READSTR-len, "\n "); len += snprint(p+len, READSTR-len, " %4.4uX", ctlr->eeprom[i]); } if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)){ phyaddr = ctlr->eeprom[6] & 0x00FF; len += snprint(p+len, READSTR-len, "\nphy %2d:", phyaddr); for(i = 0; i < 6; i++){ static int miir(Ctlr*, int, int); len += snprint(p+len, READSTR-len, " %4.4uX", miir(ctlr, phyaddr, i)); } } snprint(p+len, READSTR-len, "\n"); . 434c len += snprint(p+len, READSTR-len, "threshold: %d\n", ctlr->threshold); . 382c int i, len, phyaddr; . 194a Lock miilock; . ## diffname pc/ether82557.c 1998/0930 ## diff -e /n/emeliedump/1998/0929/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/0930/sys/src/brazil/pc/ether82557.c 602,657c receive(ether); . 577d 575a Ctlr *ctlr; int count; Block *bp, *pbp, *xbp; ctlr = ether->ctlr; bp = ctlr->rfdhead; for(rfd = (Rfd*)bp->rp; rfd->field & RfdC; rfd = (Rfd*)bp->rp){ /* * If it's an OK receive frame * 1) save the count * 2) if it's small, try to allocate a block and copy * the data, then adjust the necessary fields for reuse; * 3) if it's big, try to allocate a new Rfd and if * successful * adjust the received buffer pointers for the * actual data received; * initialise the replacement buffer to point to * the next in the ring; * initialise bp to point to the replacement; * 4) if there's a good packet, pass it on for disposal. */ if(rfd->field & RfdOK){ pbp = nil; count = rfd->count & 0x3FFF; if((count < ETHERMAXTU/4) && (pbp = iallocb(count))){ memmove(pbp->rp, bp->rp+sizeof(Rfd)-sizeof(rfd->data), count); pbp->wp = pbp->rp + count; rfd->count = 0; rfd->field = 0; } else if(xbp = rfdalloc(rfd->link)){ bp->rp += sizeof(Rfd)-sizeof(rfd->data); bp->wp = bp->rp + count; xbp->next = bp->next; bp->next = 0; pbp = bp; bp = xbp; } if(pbp != nil) etheriq(ether, pbp, 1); } else{ rfd->count = 0; rfd->field = 0; } /* * The ring tail pointer follows the head with with one * unused buffer in between to defeat hardware prefetch; * once the tail pointer has been bumped on to the next * and the new tail has the Suspend bit set, it can be * removed from the old tail buffer. * As a replacement for the current head buffer may have * been allocated above, ensure that the new tail points * to it (next and link). */ rfd = (Rfd*)ctlr->rfdtail->rp; ctlr->rfdtail = ctlr->rfdtail->next; ctlr->rfdtail->next = bp; ((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp); ((Rfd*)ctlr->rfdtail->rp)->field |= RfdS; coherence(); rfd->field &= ~RfdS; /* * Finally done with the current (possibly replaced) * head, move on to the next and maintain the sentinel * between tail and head. */ ctlr->rfdhead = bp->next; bp = ctlr->rfdhead; } } static void interrupt(Ureg*, void* arg) { . 573c receive(Ether* ether) . ## diffname pc/ether82557.c 1998/1024 ## diff -e /n/emeliedump/1998/0930/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/1024/sys/src/brazil/pc/ether82557.c 1129a if(bmcr & 0x2000) ether->mbps = 100; . 768c ctlr->threshold = 80; . 678a iunlock(&ctlr->cblock); } . 677c if(status & (StatFR|StatRNR)){ ilock(&ctlr->cblock); . 351a iunlock(&ctlr->cblock); . 350d 347d 345a ilock(&ctlr->cblock); . 229c // 0x80, /* Tx DMA maximum byte count */ 0x00, /* Tx DMA maximum byte count */ . ## diffname pc/ether82557.c 1998/1126 ## diff -e /n/emeliedump/1998/1024/sys/src/brazil/pc/ether82557.c /n/emeliedump/1998/1126/sys/src/brazil/pc/ether82557.c 972a csr8w(ctlr, Interrupt, InterruptM); . 364a ilock(&ctlr->rlock); csr8w(ctlr, Interrupt, 0); iunlock(&ctlr->rlock); . ## diffname pc/ether82557.c 1999/0314 ## diff -e /n/emeliedump/1998/1126/sys/src/brazil/pc/ether82557.c /n/emeliedump/1999/0314/sys/src/brazil/pc/ether82557.c 908a pcisetbme(p); . ## diffname pc/ether82557.c 1999/0714 ## diff -e /n/emeliedump/1999/0314/sys/src/brazil/pc/ether82557.c /n/emeliedump/1999/0714/sys/src/brazil/pc/ether82557.c 908c port = p->mem[1].bar & ~0x01; if(ioalloc(port, p->mem[1].size, 0, "i82557pci") < 0){ print("i82557pci: port %d in use\n", port); continue; } i82557adapter(&adapter, port, p->intl, p->tbdf); . 899a int port; . ## diffname pc/ether82557.c 2000/0317 ## diff -e /n/emeliedump/1999/0714/sys/src/brazil/pc/ether82557.c /n/emeliedump/2000/0317/sys/src/9/pc/ether82557.c 1016c else if(!(ctlr->eeprom[5] & 0xFF00)) phyaddr = scanphy(ctlr); else phyaddr = -1; if(phyaddr >= 0){ . 1014c if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)) . 1011a * Unfortunately, sometimes the EEPROM is blank except for * the ether address and checksum; in this case look at the * controller type and if 0 scan for the first PHY and try to * use that. . 931a 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)); ctlr->eeprom[6] = i; 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; } static int . ## diffname pc/ether82557.c 2000/0619 ## diff -e /n/emeliedump/2000/0317/sys/src/9/pc/ether82557.c /n/emeliedump/2000/0619/sys/src/9/pc/ether82557.c 911c print("i82557pci: port 0x%uX in use\n", port); . ## diffname pc/ether82557.c 2001/0301 ## diff -e /n/emeliedump/2000/0619/sys/src/9/pc/ether82557.c /n/emeliedump/2001/0301/sys/src/9/pc/ether82557.c 1027c for(i = 0; i < (1<eepromsz); i++){ . 1025a hy93c46r(ctlr, 0); . 1024a * Do a dummy read first to get the size * and allocate ctlr->eeprom. . 869a if(ctlr->eepromsz == 0){ ctlr->eepromsz = 8-size; ctlr->eeprom = malloc((1<eepromsz)*sizeof(ushort)); goto reread; } . 847,848c /* * 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; . 835a reread: . 828c int data, i, op, size; . 443c for(i = 0; i < (1<eepromsz); i++){ . 193c int eepromsz; /* address size in bits */ ushort* eeprom; . 93,94d ## diffname pc/ether82557.c 2001/0419 ## diff -e /n/emeliedump/2001/0301/sys/src/9/pc/ether82557.c /n/emeliedump/2001/0419/sys/src/9/pc/ether82557.c 1237d 1065a 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; } . 1064a switch(ctlr->pcidev->rid){ case 0x01: /* 82557 A-step */ case 0x02: /* 82557 B-step */ case 0x03: /* 82557 C-step */ default: . 1062,1063d 1056,1057c * controller type and if it's am 82558 or 82559 it has an * embedded PHY so scan for that. . 1015,1017c ether->ctlr = ctlr; ether->port = ctlr->port; ether->irq = ctlr->pcidev->intl; ether->tbdf = ctlr->pcidev->tbdf; . 1008c * Initialise the Ctlr structure. . 1004c if(ctlr == nil) . 1002d 990,999c for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){ if(ctlr->active) continue; if(ether->port == 0 || ether->port == ctlr->port){ ctlr->active = 1; . 987c * Any adapter matches if no ether->port is supplied, . 983,984d 981c if(ctlrhead == nil) . 979d 975,976d 973c int anar, anlpar, bmcr, bmsr, i, k, medium, phyaddr, x; . 926c ctlr = malloc(sizeof(Ctlr)); ctlr->port = port; ctlr->pcidev = p; if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; . 922,923c if(ioalloc(port, p->mem[1].size, 0, "i82557") < 0){ print("i82557: port 0x%uX in use\n", port); . 912a Pcidev *p; Ctlr *ctlr; . 911d 893,908d 885,891d 221a static Ctlr* ctlrhead; static Ctlr* ctlrtail; . 190a Pcidev* pcidev; Ctlr* next; int active; . 185a typedef struct Ctlr Ctlr; . ## diffname pc/ether82557.c 2001/0424 ## diff -e /n/emeliedump/2001/0419/sys/src/9/pc/ether82557.c /n/emeliedump/2001/0424/sys/src/9/pc/ether82557.c 917,921c /* * this is backwards from what we really wanted to do * but this keeps the numbering of ethernet cards * consistent with 9load. */ ctlr->next = ctlrhead; ctlrhead = ctlr; . 228d ## diffname pc/ether82557.c 2001/0527 ## diff -e /n/emeliedump/2001/0424/sys/src/9/pc/ether82557.c /n/emeliedump/2001/0527/sys/src/9/pc/ether82557.c 383c snprint(name, KNAMELEN, "#l%dwatchdog", ether->ctlrno); . 366c char name[KNAMELEN]; . ## diffname pc/ether82557.c 2001/0626 ## diff -e /n/emeliedump/2001/0527/sys/src/9/pc/ether82557.c /n/emeliedump/2001/0626/sys/src/9/pc/ether82557.c 916,922c if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; . 227a static Ctlr* ctlrtail; . ## diffname pc/ether82557.c 2001/1014 ## diff -e /n/emeliedump/2001/0626/sys/src/9/pc/ether82557.c /n/emeliedump/2001/1014/sys/src/9/pc/ether82557.c 901c while(p = pcimatch(p, 0x8086, 0)){ switch(p->did){ default: continue; case 0x1229: /* Intel 8255[789] */ case 0x1031: /* Intel 82562EM */ break; } . ## diffname pc/ether82557.c 2001/1016 ## diff -e /n/emeliedump/2001/1014/sys/src/9/pc/ether82557.c /n/emeliedump/2001/1016/sys/src/9/pc/ether82557.c 906a case 0x2449: /* Intel ????? */ . ## diffname pc/ether82557.c 2001/1017 ## diff -e /n/emeliedump/2001/1016/sys/src/9/pc/ether82557.c /n/emeliedump/2001/1017/sys/src/9/pc/ether82557.c 907c case 0x2449: /* Intel 82562ET */ . 904a case 0x1209: /* INtel 82559ER */ . ## diffname pc/ether82557.c 2002/0109 ## diff -e /n/emeliedump/2001/1017/sys/src/9/pc/ether82557.c /n/emeliedump/2002/0109/sys/src/9/pc/ether82557.c 1249a ether->shutdown = shutdown; . 975a static void shutdown(Ether* ether) { Ctlr *ctlr = ether->ctlr; print("ether82557 shutting down\n"); csr32w(ctlr, Port, 0); delay(1); csr8w(ctlr, Interrupt, InterruptM); } . ## diffname pc/ether82557.c 2002/0131 ## diff -e /n/emeliedump/2002/0109/sys/src/9/pc/ether82557.c /n/emeliedump/2002/0131/sys/src/9/pc/ether82557.c 905c case 0x1209: /* Intel 82559ER */ . ## diffname pc/ether82557.c 2002/0711 ## diff -e /n/emeliedump/2002/0131/sys/src/9/pc/ether82557.c /n/emeliedump/2002/0711/sys/src/9/pc/ether82557.c 1232c ether->oq = qopen(256*1024, Qmsg, 0, 0); . ## diffname pc/ether82557.c 2002/0920 ## diff -e /n/emeliedump/2002/0711/sys/src/9/pc/ether82557.c /n/emeliedump/2002/0920/sys/src/9/pc/ether82557.c 282,283c if(waitfordone(ctlr) < 0) print("82557: lastcmd %x, cmd %x(%x) \n", ctlr->command, c, v); . 269a * on a 10 Mbs half-duplex connection, we seem to * hang unless we do a nop before each command. * This comes from a fix for a chip errata that jmk * saw in a Linux driver. */ if(waitfordone(ctlr) < 0) print("82557: lastcmd %x, cmd nop \n", ctlr->command); csr8w(ctlr, CommandR, CUnop); /* . 263a int waitfordone(Ctlr *ctlr) { int loops; /* fast wait, we usually get lucky */ for(loops = 0; loops < 100; loops++){ if(csr8r(ctlr, CommandR) == 0) return 0; } /* slow wait */ for(loops = 0; loops < 1000; loops++){ if(csr8r(ctlr, CommandR) == 0) return 0; microdelay(1); } return -1; } . ## diffname pc/ether82557.c 2002/0921 ## diff -e /n/emeliedump/2002/0920/sys/src/9/pc/ether82557.c /n/emeliedump/2002/0921/sys/src/9/pc/ether82557.c 1256a /* * Workaround for some broken HUB chips when connected at 10Mb/s * half-duplex. * This is a band-aid, but as there's no dynamic auto-negotiation * code at the moment, only deactivate the workaround code in txstart * if the link is 100Mb/s. */ if(ether->mbps != 10) ctlr->nop = 0; . 955a ctlr->nop = nop; . 938a nop = 1; /*FALLTHROUGH*/ case 0x1209: /* Intel 82559ER */ case 0x1229: /* Intel 8255[789] */ . 935,936d 930a nop = 0; . 928a int nop, port; . 926d 554a /* * Workaround for some broken HUB chips * when connected at 10Mb/s half-duplex. */ if(ctlr->nop){ command(ctlr, CUnop, 0); microdelay(1); } . 472a len += snprint(p+len, READSTR-len, "nop: %d\n", ctlr->nop); . 312,313c for(timeo = 0; timeo < 100; timeo++){ if(!csr8r(ctlr, CommandR)) break; microdelay(1); } if(timeo >= 100){ ctlr->command = -1; iunlock(&ctlr->rlock); iprint("i82557: command 0x%uX %uX timeout\n", c, v); return; } . 290,299d 286a int timeo; . 264,283d 212a int nop; . ## diffname pc/ether82557.c 2003/0407 ## diff -e /n/emeliedump/2002/0921/sys/src/9/pc/ether82557.c /n/emeliedump/2003/0407/sys/src/9/pc/ether82557.c 352,353c tsleep(&up->sleep, return0, 0, 4000); . 201d