?? etherelnk3.c
字號:
COMMAND(port, AcknowledgeInterrupt, upComplete); receive905(ether); status &= ~upComplete; ctlr->upinterrupts++; } if(status & txComplete){ /* * Pop the TxStatus stack, accumulating errors. * Adjust the TX start threshold if there was an underrun. * If there was a Jabber or Underrun error, reset * the transmitter, taking care not to reset the dma logic * as a busmaster receive may be in progress. * For all conditions enable the transmitter. */ s = 0; do{ if(x = inb(port+TxStatus)) outb(port+TxStatus, 0); s |= x; }while(STATUS(port) & txComplete); if(s & txUnderrun){ if(ctlr->dnenabled){ while(inl(port+PktStatus) & dnInProg) ; } COMMAND(port, SelectRegisterWindow, Wdiagnostic); while(ins(port+MediaStatus) & txInProg) ; COMMAND(port, SelectRegisterWindow, Wop); if(ctlr->txthreshold < ETHERMAXTU) ctlr->txthreshold += ETHERMINTU; } /* * According to the manual, maxCollisions does not require * a TxReset, merely a TxEnable. However, evidence points to * it being necessary on the 3C905. The jury is still out. * On busy or badly configured networks maxCollisions can * happen frequently enough for messages to be annoying so * keep quiet about them by popular request. */ if(s & (txJabber|txUnderrun|maxCollisions)){ if(ctlr->busmaster == 0) COMMAND(port, TxReset, 0); else COMMAND(port, TxReset, (updnReset|dmaReset)); while(STATUS(port) & commandInProgress) ; COMMAND(port, SetTxStartThresh, ctlr->txthreshold>>ctlr->ts); if(ctlr->busmaster == 2) outl(port+TxFreeThresh, HOWMANY(ETHERMAXTU, 256)); if(ctlr->dnenabled) status |= dnComplete; } if(s & ~(txStatusComplete|maxCollisions)) print("#l%d: txstatus 0x%uX, threshold %d\n", ether->ctlrno, s, ctlr->txthreshold); COMMAND(port, TxEnable, 0); ether->oerrs++; status &= ~txComplete; status |= txAvailable; } if(status & txAvailable){ COMMAND(port, AcknowledgeInterrupt, txAvailable); ctlr->txbusy = 0; txstart(ether); status &= ~txAvailable; } if(status & dnComplete){ COMMAND(port, AcknowledgeInterrupt, dnComplete); txstart905(ether); status &= ~dnComplete; ctlr->dninterrupts++; } if(status & updateStats){ statistics(ether); status &= ~updateStats; } /* * Currently, this shouldn't happen. */ if(status & rxEarly){ COMMAND(port, AcknowledgeInterrupt, rxEarly); status &= ~rxEarly; } /* * Panic if there are any interrupts not dealt with. */ if(status & interruptMask) panic("#l%d: interrupt mask 0x%uX\n", ether->ctlrno, status); COMMAND(port, AcknowledgeInterrupt, interruptLatch); } COMMAND(port, SelectRegisterWindow, w); iunlock(&ctlr->wlock);}static longifstat(Ether* ether, void* a, long n, ulong offset){ char *p; int len; Ctlr *ctlr; if(n == 0) return 0; ctlr = ether->ctlr; ilock(&ctlr->wlock); statistics(ether); iunlock(&ctlr->wlock); p = malloc(READSTR); len = snprint(p, READSTR, "interrupts: %lud\n", ctlr->interrupts); len += snprint(p+len, READSTR-len, "timer: %lud\n", ctlr->timer); len += snprint(p+len, READSTR-len, "carrierlost: %lud\n", ctlr->stats[CarrierLost]); len += snprint(p+len, READSTR-len, "sqeerrors: %lud\n", ctlr->stats[SqeErrors]); len += snprint(p+len, READSTR-len, "multiplecolls: %lud\n", ctlr->stats[MultipleColls]); len += snprint(p+len, READSTR-len, "singlecollframes: %lud\n", ctlr->stats[SingleCollFrames]); len += snprint(p+len, READSTR-len, "latecollisions: %lud\n", ctlr->stats[LateCollisions]); len += snprint(p+len, READSTR-len, "rxoverruns: %lud\n", ctlr->stats[RxOverruns]); len += snprint(p+len, READSTR-len, "framesxmittedok: %lud\n", ctlr->stats[FramesXmittedOk]); len += snprint(p+len, READSTR-len, "framesrcvdok: %lud\n", ctlr->stats[FramesRcvdOk]); len += snprint(p+len, READSTR-len, "framesdeferred: %lud\n", ctlr->stats[FramesDeferred]); len += snprint(p+len, READSTR-len, "bytesrcvdok: %lud\n", ctlr->stats[BytesRcvdOk]); len += snprint(p+len, READSTR-len, "bytesxmittedok: %lud\n", ctlr->stats[BytesRcvdOk+1]); if(ctlr->upenabled){ if(ctlr->upqmax > ctlr->upqmaxhw) ctlr->upqmaxhw = ctlr->upqmax; len += snprint(p+len, READSTR-len, "up: q %lud i %lud m %d h %d s %lud\n", ctlr->upqueued, ctlr->upinterrupts, ctlr->upqmax, ctlr->upqmaxhw, ctlr->upstalls); ctlr->upqmax = 0; } if(ctlr->dnenabled){ if(ctlr->dnqmax > ctlr->dnqmaxhw) ctlr->dnqmaxhw = ctlr->dnqmax; len += snprint(p+len, READSTR-len, "dn: q %lud i %lud m %d h %d\n", ctlr->dnqueued, ctlr->dninterrupts, ctlr->dnqmax, ctlr->dnqmaxhw); ctlr->dnqmax = 0; } snprint(p+len, READSTR-len, "badssd: %lud\n", ctlr->stats[BytesRcvdOk+2]); n = readstr(offset, a, n, p); free(p); return n;}static voidtxrxreset(int port){ COMMAND(port, TxReset, 0); while(STATUS(port) & commandInProgress) ; COMMAND(port, RxReset, 0); while(STATUS(port) & commandInProgress) ;}typedef struct Adapter { int port; int irq; int tbdf;} Adapter;static Block* adapter;static voidtcmadapter(int port, int irq, int tbdf){ Block *bp; Adapter *ap; bp = allocb(sizeof(Adapter)); ap = (Adapter*)bp->rp; ap->port = port; ap->irq = irq; ap->tbdf = tbdf; bp->next = adapter; adapter = bp;}/* * Write two 0 bytes to identify the IDport and then reset the * ID sequence. Then send the ID sequence to the card to get * the card into command state. */static voididseq(void){ int i; uchar al; static int reset, untag; /* * One time only: * reset any adapters listening */ if(reset == 0){ outb(IDport, 0); outb(IDport, 0); outb(IDport, 0xC0); delay(20); reset = 1; } outb(IDport, 0); outb(IDport, 0); for(al = 0xFF, i = 0; i < 255; i++){ outb(IDport, al); if(al & 0x80){ al <<= 1; al ^= 0xCF; } else al <<= 1; } /* * One time only: * write ID sequence to get the attention of all adapters; * untag all adapters. * If a global reset is done here on all adapters it will confuse * any ISA cards configured for EISA mode. */ if(untag == 0){ outb(IDport, 0xD0); untag = 1; }}static ulongactivate(void){ int i; ushort x, acr; /* * Do the little configuration dance: * * 2. write the ID sequence to get to command state. */ idseq(); /* * 3. Read the Manufacturer ID from the EEPROM. * This is done by writing the IDPort with 0x87 (0x80 * is the 'read EEPROM' command, 0x07 is the offset of * the Manufacturer ID field in the EEPROM). * The data comes back 1 bit at a time. * A delay seems necessary between reading the bits. * * If the ID doesn't match, there are no more adapters. */ outb(IDport, 0x87); delay(20); for(x = 0, i = 0; i < 16; i++){ delay(20); x <<= 1; x |= inb(IDport) & 0x01; } if(x != 0x6D50) return 0; /* * 3. Read the Address Configuration from the EEPROM. * The Address Configuration field is at offset 0x08 in the EEPROM). */ outb(IDport, 0x88); for(acr = 0, i = 0; i < 16; i++){ delay(20); acr <<= 1; acr |= inb(IDport) & 0x01; } return (acr & 0x1F)*0x10 + 0x200;}static voidtcm509isa(void){ int irq, port; /* * Attempt to activate all adapters. If adapter is set for * EISA mode (0x3F0), tag it and ignore. Otherwise, activate * it fully. */ while(port = activate()){ if(ioalloc(port, 0x10, 0, "tcm509isa") < 0){ print("tcm509isa:port %d in use\n", port); continue; } /* * 6. Tag the adapter so it won't respond in future. */ outb(IDport, 0xD1); if(port == 0x3F0){ iofree(port); continue; } /* * 6. Activate the adapter by writing the Activate command * (0xFF). */ outb(IDport, 0xFF); delay(20); /* * 8. Can now talk to the adapter's I/O base addresses. * Use the I/O base address from the acr just read. * * Enable the adapter and clear out any lingering status * and interrupts. */ while(STATUS(port) & commandInProgress) ; COMMAND(port, SelectRegisterWindow, Wsetup); outs(port+ConfigControl, Ena); txrxreset(port); COMMAND(port, AcknowledgeInterrupt, 0xFF); irq = (ins(port+ResourceConfig)>>12) & 0x0F; tcmadapter(port, irq, BUSUNKNOWN); }}static voidtcm5XXeisa(void){ ushort x; int irq, port, slot; /* * Check if this is an EISA machine. * If not, nothing to do. */ if(strncmp((char*)KADDR(0xFFFD9), "EISA", 4)) return; /* * Continue through the EISA slots looking for a match on both * 3COM as the manufacturer and 3C579-* or 3C59[27]-* as the product. * If an adapter is found, select window 0, enable it and clear * out any lingering status and interrupts. */ for(slot = 1; slot < MaxEISA; slot++){ port = slot*0x1000; if(ioalloc(port, 0x1000, 0, "tcm5XXeisa") < 0){ print("tcm5XXeisa: port %d in use\n", port); continue; } if(ins(port+0xC80+ManufacturerID) != 0x6D50){ iofree(port); continue; } x = ins(port+0xC80+ProductID); if((x & 0xF0FF) != 0x9050 && (x & 0xFF00) != 0x5900){ iofree(port); continue; } COMMAND(port, SelectRegisterWindow, Wsetup); outs(port+ConfigControl, Ena); txrxreset(port); COMMAND(port, AcknowledgeInterrupt, 0xFF); irq = (ins(port+ResourceConfig)>>12) & 0x0F; tcmadapter(port, irq, BUSUNKNOWN); }}static voidtcm59Xpci(void){ Pcidev *p; int irq, port; p = nil; while(p = pcimatch(p, 0x10B7, 0)){ port = p->mem[0].bar & ~0x01; if(ioalloc(port, p->mem[0].size, 0, "tcm59Xpci") < 0){ print("tcm59Xpci: port %d in use\n", port); continue; } irq = p->intl; COMMAND(port, GlobalReset, 0); while(STATUS(port) & commandInProgress) ; tcmadapter(port, irq, p->tbdf); pcisetbme(p); }}static char* tcmpcmcia[] = { "3C589", /* 3COM 589[ABCD] */ "3C562", /* 3COM 562 */ "589E", /* 3COM Megahertz 589E */ nil,};static inttcm5XXpcmcia(Ether* ether){ int i; for(i = 0; tcmpcmcia[i] != nil; i++){ if(!cistrcmp(ether->type, tcmpcmcia[i])){ /* * No need for an ioalloc here, the 589 reset * code deals with it. if(ioalloc(ether->port, 0x10, 0, "tcm5XXpcmcia") < 0) return 0; */ return ether->port; } } return 0;}static voidsetxcvr(int port, int xcvr, int is9){ int x; if(is9){ COMMAND(port, SelectRegisterWindow, Wsetup); x = ins(port+AddressConfig) & ~xcvrMask9; x |= (xcvr>>20)<<14; outs(port+AddressConfig, x); } else{ COMMAND(port, SelectRegisterWindow, Wfifo); x = inl(port+InternalConfig) & ~xcvrMask; x |= xcvr; outl(port+InternalConfig, x); } txrxreset(port);}static voidsetfullduplex(int port){ int x; COMMAND(port, SelectRegisterWindow, Wfifo); x = ins(port+MacControl); outs(port+MacControl, fullDuplexEnable|x); txrxreset(port);}static intmiimdi(int port, int n){ int data, i; /* * Read n bits from the MII Management Register. */ data = 0; for(i = n-1; i >= 0; i--){ if(ins(port) & mgmtData) data |= (1<<i); microdelay(1); outs(port, mgmtClk); microdelay(1); outs(port, 0); microdelay(1); } return data;}static voidmiimdo(int port, int bits, int n){ int i, mdo; /* * Write n bits to the MII Management Register. */ for(i = n-1; i >= 0; i--){ if(bits & (1<<i)) mdo = mgmtDir|mgmtData; else
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -