/* * Intel 82557 Fast Ethernet PCI Bus LAN Controller * as found on the Intel EtherExpress PRO/100B. This chip is full * of smarts, unfortunately they're not all in the right place. * To do: * the PCI scanning code could be made common to other adapters; * auto-negotiation, full-duplex; * optionally use memory-mapped registers; * detach for PCI reset problems (also towards loadable drivers). */#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 */ Ncb = 64, /* maximum control blocks queued */ 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 */ General = 0x04, /* dword */ Port = 0x08, /* dword */ Fcr = 0x0C, /* Flash control register */ Ecr = 0x0E, /* EEPROM control register */ Mcr = 0x10, /* MDI control register */ Gstatus = 0x1D, /* General status 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; uchar data[1700];} 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 = 0x4000, RfdEOF = 0x8000,}; typedef struct Cb Cb;typedef struct Cb { ushort status; ushort command; ulong link; union { uchar data[24]; /* CbIAS + CbConfigure */ struct { ulong tbd; ushort count; uchar threshold; uchar number; ulong tba; ushort tbasz; ushort pad; }; }; Block* bp; Cb* next;} Cb; enum { /* action command */ CbU = 0x1000, /* transmit underrun */ CbOK = 0x2000, /* DMA completed OK */ CbC = 0x8000, /* execution Complete */ CbNOP = 0x0000, CbIAS = 0x0001, /* Individual Address Setup */ CbConfigure = 0x0002, CbMAS = 0x0003, /* Multicast Address Setup */ CbTransmit = 0x0004, CbDump = 0x0006, CbDiagnose = 0x0007, CbCommand = 0x0007, /* mask */ CbSF = 0x0008, /* Flexible-mode CbTransmit */ CbI = 0x2000, /* Interrupt after completion */ CbS = 0x4000, /* Suspend after completion */ CbEL = 0x8000, /* End of List */}; enum { /* CbTransmit count */ CbEOF = 0x8000,}; typedef struct Ctlr Ctlr;typedef struct Ctlr { Lock slock; /* attach */ int state; int port; Pcidev* pcidev; Ctlr* next; int active; int eepromsz; /* address size in bits */ ushort* eeprom; Lock miilock; int tick; Lock rlock; /* registers */ int command; /* last command issued */ Block* rfdhead; /* receive side */ Block* rfdtail; int nrfd; Lock cblock; /* transmit side */ int action; int nop; uchar configdata[24]; int threshold; int ncb; Cb* cbr; Cb* cbhead; Cb* cbtail; int cbq; int cbqmax; int cbqmaxhw; Lock dlock; /* dump statistical counters */ ulong dump[17];} Ctlr; static Ctlr* ctlrhead;static Ctlr* ctlrtail; static uchar configdata[24] = { 0x16, /* byte count */ 0x08, /* Rx/Tx FIFO limit */ 0x00, /* adaptive IFS */ 0x00, 0x00, /* Rx DMA maximum byte count */// 0x80, /* Tx DMA maximum byte count */ 0x00, /* Tx DMA maximum byte count */ 0x32, /* !late SCB, CNA interrupts */ 0x03, /* discard short Rx frames */ 0x00, /* 503/MII */ 0x00, 0x2E, /* normal operation, NSAI */ 0x00, /* linear priority */ 0x60, /* inter-frame spacing */ 0x00, 0xF2, 0xC8, /* 503, promiscuous mode off */ 0x00, 0x40, 0xF3, /* 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 voidcommand(Ctlr* ctlr, int c, int v){ int timeo; 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. * Unfortunately there's a chip errata where back-to-back * CUresumes can be lost, the fix is to always wait. if(c == CUresume && ctlr->command == CUresume){ csr8w(ctlr, CommandR, c); iunlock(&ctlr->rlock); return; } */ 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 %#ux %#ux timeout\n", c, v); return; } 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);} 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 voidwatchdog(void* arg){ Ether *ether; Ctlr *ctlr; static void txstart(Ether*); ether = arg; for(;;){ tsleep(&up->sleep, 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); } ilock(&ctlr->cblock); if(ctlr->tick++){ ctlr->action = CbMAS; txstart(ether); } iunlock(&ctlr->cblock); }} static voidattach(Ether* ether){ Ctlr *ctlr; char name[KNAMELEN]; ctlr = ether->ctlr; lock(&ctlr->slock); if(ctlr->state == 0){ ilock(&ctlr->rlock); csr8w(ctlr, Interrupt, 0); iunlock(&ctlr->rlock); command(ctlr, RUstart, PADDR(ctlr->rfdhead->rp)); ctlr->state = 1; /* * 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, KNAMELEN, "#l%dwatchdog", ether->ctlrno); kproc(name, watchdog, ether, 0); } } unlock(&ctlr->slock);} static longifstat(Ether* ether, void* a, long n, ulong offset){ char *p; int i, len, phyaddr; Ctlr *ctlr; ulong dump[17]; ctlr = ether->ctlr; lock(&ctlr->dlock); /* * Start the command then * wait for completion status, * should be 0xA005. */ ctlr->dump[16] = 0; command(ctlr, DumpSC, 0); 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; } memmove(dump, ctlr->dump, sizeof(dump)); unlock(&ctlr->dlock); p = malloc(READSTR); 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]); len += snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]); len += snprint(p+len, READSTR-len, "nop: %d\n", ctlr->nop); if(ctlr->cbqmax > ctlr->cbqmaxhw) ctlr->cbqmaxhw = ctlr->cbqmax; len += snprint(p+len, READSTR-len, "cbqmax: %d\n", ctlr->cbqmax); ctlr->cbqmax = 0; len += snprint(p+len, READSTR-len, "threshold: %d\n", ctlr->threshold); len += snprint(p+len, READSTR-len, "eeprom:"); for(i = 0; i < (1<<ctlr->eepromsz); 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"); n = readstr(offset, a, n, p); free(p); return n;} static voidtxstart(Ether* ether){ Ctlr *ctlr; Block *bp; Cb *cb; 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; Lines 1–500 of 1327. Load more
/* * Intel 82557 Fast Ethernet PCI Bus LAN Controller * as found on the Intel EtherExpress PRO/100B. This chip is full * of smarts, unfortunately they're not all in the right place. * To do: * the PCI scanning code could be made common to other adapters; * auto-negotiation, full-duplex; * optionally use memory-mapped registers; * detach for PCI reset problems (also towards loadable drivers). */ #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 */ Ncb = 64, /* maximum control blocks queued */ 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 */ General = 0x04, /* dword */ Port = 0x08, /* dword */ Fcr = 0x0C, /* Flash control register */ Ecr = 0x0E, /* EEPROM control register */ Mcr = 0x10, /* MDI control register */ Gstatus = 0x1D, /* General status 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; uchar data[1700]; } 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 = 0x4000, RfdEOF = 0x8000, }; typedef struct Cb Cb; typedef struct Cb { ushort status; ushort command; ulong link; union { uchar data[24]; /* CbIAS + CbConfigure */ struct { ulong tbd; ushort count; uchar threshold; uchar number; ulong tba; ushort tbasz; ushort pad; }; }; Block* bp; Cb* next; } Cb; enum { /* action command */ CbU = 0x1000, /* transmit underrun */ CbOK = 0x2000, /* DMA completed OK */ CbC = 0x8000, /* execution Complete */ CbNOP = 0x0000, CbIAS = 0x0001, /* Individual Address Setup */ CbConfigure = 0x0002, CbMAS = 0x0003, /* Multicast Address Setup */ CbTransmit = 0x0004, CbDump = 0x0006, CbDiagnose = 0x0007, CbCommand = 0x0007, /* mask */ CbSF = 0x0008, /* Flexible-mode CbTransmit */ CbI = 0x2000, /* Interrupt after completion */ CbS = 0x4000, /* Suspend after completion */ CbEL = 0x8000, /* End of List */ }; enum { /* CbTransmit count */ CbEOF = 0x8000, }; typedef struct Ctlr Ctlr; typedef struct Ctlr { Lock slock; /* attach */ int state; int port; Pcidev* pcidev; Ctlr* next; int active; int eepromsz; /* address size in bits */ ushort* eeprom; Lock miilock; int tick; Lock rlock; /* registers */ int command; /* last command issued */ Block* rfdhead; /* receive side */ Block* rfdtail; int nrfd; Lock cblock; /* transmit side */ int action; int nop; uchar configdata[24]; int threshold; int ncb; Cb* cbr; Cb* cbhead; Cb* cbtail; int cbq; int cbqmax; int cbqmaxhw; Lock dlock; /* dump statistical counters */ ulong dump[17]; } Ctlr; static Ctlr* ctlrhead; static Ctlr* ctlrtail; static uchar configdata[24] = { 0x16, /* byte count */ 0x08, /* Rx/Tx FIFO limit */ 0x00, /* adaptive IFS */ 0x00, 0x00, /* Rx DMA maximum byte count */ // 0x80, /* Tx DMA maximum byte count */ 0x00, /* Tx DMA maximum byte count */ 0x32, /* !late SCB, CNA interrupts */ 0x03, /* discard short Rx frames */ 0x00, /* 503/MII */ 0x00, 0x2E, /* normal operation, NSAI */ 0x00, /* linear priority */ 0x60, /* inter-frame spacing */ 0x00, 0xF2, 0xC8, /* 503, promiscuous mode off */ 0x00, 0x40, 0xF3, /* 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 command(Ctlr* ctlr, int c, int v) { int timeo; 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. * Unfortunately there's a chip errata where back-to-back * CUresumes can be lost, the fix is to always wait. if(c == CUresume && ctlr->command == CUresume){ csr8w(ctlr, CommandR, c); iunlock(&ctlr->rlock); return; } */ 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 %#ux %#ux timeout\n", c, v); return; } 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); } 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 void watchdog(void* arg) { Ether *ether; Ctlr *ctlr; static void txstart(Ether*); ether = arg; for(;;){ tsleep(&up->sleep, 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); } ilock(&ctlr->cblock); if(ctlr->tick++){ ctlr->action = CbMAS; txstart(ether); } iunlock(&ctlr->cblock); } } static void attach(Ether* ether) { Ctlr *ctlr; char name[KNAMELEN]; ctlr = ether->ctlr; lock(&ctlr->slock); if(ctlr->state == 0){ ilock(&ctlr->rlock); csr8w(ctlr, Interrupt, 0); iunlock(&ctlr->rlock); command(ctlr, RUstart, PADDR(ctlr->rfdhead->rp)); ctlr->state = 1; /* * 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, KNAMELEN, "#l%dwatchdog", ether->ctlrno); kproc(name, watchdog, ether, 0); } } unlock(&ctlr->slock); } static long ifstat(Ether* ether, void* a, long n, ulong offset) { char *p; int i, len, phyaddr; Ctlr *ctlr; ulong dump[17]; ctlr = ether->ctlr; lock(&ctlr->dlock); /* * Start the command then * wait for completion status, * should be 0xA005. */ ctlr->dump[16] = 0; command(ctlr, DumpSC, 0); 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; } memmove(dump, ctlr->dump, sizeof(dump)); unlock(&ctlr->dlock); p = malloc(READSTR); 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]); len += snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]); len += snprint(p+len, READSTR-len, "nop: %d\n", ctlr->nop); if(ctlr->cbqmax > ctlr->cbqmaxhw) ctlr->cbqmaxhw = ctlr->cbqmax; len += snprint(p+len, READSTR-len, "cbqmax: %d\n", ctlr->cbqmax); ctlr->cbqmax = 0; len += snprint(p+len, READSTR-len, "threshold: %d\n", ctlr->threshold); len += snprint(p+len, READSTR-len, "eeprom:"); for(i = 0; i < (1<<ctlr->eepromsz); 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"); n = readstr(offset, a, n, p); free(p); return n; } static void txstart(Ether* ether) { Ctlr *ctlr; Block *bp; Cb *cb; 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;