/* * AMD79C970 * PCnet-PCI Single-Chip Ethernet Controller for PCI Local Bus * To do: * finish this rewrite */#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 { Lognrdre = 6, Nrdre = (1<<Lognrdre),/* receive descriptor ring entries */ Logntdre = 4, Ntdre = (1<<Logntdre),/* transmit descriptor ring entries */ Rbsize = ETHERMAXTU+4, /* ring buffer size (+4 for CRC) */}; enum { /* DWIO I/O resource map */ Aprom = 0x0000, /* physical address */ Rdp = 0x0010, /* register data port */ Rap = 0x0014, /* register address port */ Sreset = 0x0018, /* software reset */ Bdp = 0x001C, /* bus configuration register data port */}; enum { /* CSR0 */ Init = 0x0001, /* begin initialisation */ Strt = 0x0002, /* enable chip */ Stop = 0x0004, /* disable chip */ Tdmd = 0x0008, /* transmit demand */ Txon = 0x0010, /* transmitter on */ Rxon = 0x0020, /* receiver on */ Iena = 0x0040, /* interrupt enable */ Intr = 0x0080, /* interrupt flag */ Idon = 0x0100, /* initialisation done */ Tint = 0x0200, /* transmit interrupt */ Rint = 0x0400, /* receive interrupt */ Merr = 0x0800, /* memory error */ Miss = 0x1000, /* missed frame */ Cerr = 0x2000, /* collision */ Babl = 0x4000, /* transmitter timeout */ Err = 0x8000, /* Babl|Cerr|Miss|Merr */}; enum { /* CSR3 */ Bswp = 0x0004, /* byte swap */ Emba = 0x0008, /* enable modified back-off algorithm */ Dxmt2pd = 0x0010, /* disable transmit two part deferral */ Lappen = 0x0020, /* look-ahead packet processing enable */}; enum { /* CSR4 */ ApadXmt = 0x0800, /* auto pad transmit */}; enum { /* CSR15 */ Prom = 0x8000, /* promiscuous mode */}; typedef struct Iblock Iblock;struct Iblock { /* Initialisation Block */ ushort mode; uchar rlen; /* upper 4 bits */ uchar tlen; /* upper 4 bits */ uchar padr[6]; uchar res[2]; uchar ladr[8]; ulong rdra; ulong tdra;}; typedef struct Dre Dre;struct Dre { /* descriptor ring entry */ ulong addr; ulong md1; /* status|bcnt */ ulong md2; /* rcc|rpc|mcnt */ Block* bp;}; enum { /* md1 */ Enp = 0x01000000, /* end of packet */ Stp = 0x02000000, /* start of packet */ RxBuff = 0x04000000, /* buffer error */ Def = 0x04000000, /* deferred */ Crc = 0x08000000, /* CRC error */ One = 0x08000000, /* one retry needed */ Oflo = 0x10000000, /* overflow error */ More = 0x10000000, /* more than one retry needed */ Fram = 0x20000000, /* framing error */ RxErr = 0x40000000, /* Fram|Oflo|Crc|RxBuff */ TxErr = 0x40000000, /* Uflo|Lcol|Lcar|Rtry */ Own = 0x80000000,}; enum { /* md2 */ Rtry = 0x04000000, /* failed after repeated retries */ Lcar = 0x08000000, /* loss of carrier */ Lcol = 0x10000000, /* late collision */ Uflo = 0x40000000, /* underflow error */ TxBuff = 0x80000000, /* buffer error */}; typedef struct Ctlr Ctlr;struct Ctlr { Lock; int port; Pcidev* pcidev; Ctlr* next; int active; int init; /* initialisation in progress */ Iblock iblock; Dre* rdr; /* receive descriptor ring */ int rdrx; Dre* tdr; /* transmit descriptor ring */ int tdrh; /* host index into tdr */ int tdri; /* interface index into tdr */ int ntq; /* descriptors active */ ulong rxbuff; /* receive statistics */ ulong crc; ulong oflo; ulong fram; ulong rtry; /* transmit statistics */ ulong lcar; ulong lcol; ulong uflo; ulong txbuff; ulong merr; /* bobf is such a whiner */ ulong miss; ulong babl; int (*ior)(Ctlr*, int); void (*iow)(Ctlr*, int, int);}; static Ctlr* ctlrhead;static Ctlr* ctlrtail; /* * The Rdp, Rap, Sreset, Bdp ports are 32-bit port offset in the enumeration above. * To get to 16-bit offsets, scale down with 0x10 staying the same. */static intio16r(Ctlr *c, int r){ if(r >= Rdp) r = (r-Rdp)/2+Rdp; return ins(c->port+r);} static voidio16w(Ctlr *c, int r, int v){ if(r >= Rdp) r = (r-Rdp)/2+Rdp; outs(c->port+r, v);} static intio32r(Ctlr *c, int r){ return inl(c->port+r);} static voidio32w(Ctlr *c, int r, int v){ outl(c->port+r, v);} static voidattach(Ether*){} static longifstat(Ether* ether, void* a, long n, ulong offset){ char *p; int len; Ctlr *ctlr; ctlr = ether->ctlr; ether->crcs = ctlr->crc; ether->frames = ctlr->fram; ether->buffs = ctlr->rxbuff+ctlr->txbuff; ether->overflows = ctlr->oflo; if(n == 0) return 0; p = malloc(READSTR); len = snprint(p, READSTR, "Rxbuff: %ld\n", ctlr->rxbuff); len += snprint(p+len, READSTR-len, "Crc: %ld\n", ctlr->crc); len += snprint(p+len, READSTR-len, "Oflo: %ld\n", ctlr->oflo); len += snprint(p+len, READSTR-len, "Fram: %ld\n", ctlr->fram); len += snprint(p+len, READSTR-len, "Rtry: %ld\n", ctlr->rtry); len += snprint(p+len, READSTR-len, "Lcar: %ld\n", ctlr->lcar); len += snprint(p+len, READSTR-len, "Lcol: %ld\n", ctlr->lcol); len += snprint(p+len, READSTR-len, "Uflo: %ld\n", ctlr->uflo); len += snprint(p+len, READSTR-len, "Txbuff: %ld\n", ctlr->txbuff); len += snprint(p+len, READSTR-len, "Merr: %ld\n", ctlr->merr); len += snprint(p+len, READSTR-len, "Miss: %ld\n", ctlr->miss); snprint(p+len, READSTR-len, "Babl: %ld\n", ctlr->babl); n = readstr(offset, a, n, p); free(p); return n;} static voidringinit(Ctlr* ctlr){ Dre *dre; /* * Initialise the receive and transmit buffer rings. * The ring entries must be aligned on 16-byte boundaries. * * This routine is protected by ctlr->init. */ if(ctlr->rdr == 0){ ctlr->rdr = xspanalloc(Nrdre*sizeof(Dre), 0x10, 0); for(dre = ctlr->rdr; dre < &ctlr->rdr[Nrdre]; dre++){ dre->bp = iallocb(Rbsize); if(dre->bp == nil) panic("can't allocate ethernet receive ring\n"); dre->addr = PADDR(dre->bp->rp); dre->md2 = 0; dre->md1 = Own|(-Rbsize & 0xFFFF); } } ctlr->rdrx = 0; if(ctlr->tdr == 0) ctlr->tdr = xspanalloc(Ntdre*sizeof(Dre), 0x10, 0); memset(ctlr->tdr, 0, Ntdre*sizeof(Dre)); ctlr->tdrh = ctlr->tdri = 0;} static voidpromiscuous(void* arg, int on){ Ether *ether; int x; Ctlr *ctlr; ether = arg; ctlr = ether->ctlr; /* * Put the chip into promiscuous mode. First must wait until * anyone transmitting is done, then stop the chip and put * it in promiscuous mode. Restarting is made harder by the chip * reloading the transmit and receive descriptor pointers with their * base addresses when Strt is set (unlike the older Lance chip), * so the rings must be re-initialised. */ ilock(ctlr); if(ctlr->init){ iunlock(ctlr); return; } ctlr->init = 1; iunlock(ctlr); while(ctlr->ntq) ; ctlr->iow(ctlr, Rdp, Stop); ctlr->iow(ctlr, Rap, 15); x = ctlr->ior(ctlr, Rdp) & ~Prom; if(on) x |= Prom; ctlr->iow(ctlr, Rdp, x); ctlr->iow(ctlr, Rap, 0); ringinit(ctlr); ilock(ctlr); ctlr->init = 0; ctlr->iow(ctlr, Rdp, Iena|Strt); iunlock(ctlr);} static voidmulticast(void* arg, uchar*, int){ promiscuous(arg, 1);} static voidtxstart(Ether* ether){ Ctlr *ctlr; Block *bp; Dre *dre; ctlr = ether->ctlr; if(ctlr->init) return; while(ctlr->ntq < (Ntdre-1)){ bp = qget(ether->oq); if(bp == nil) break; /* * Give ownership of the descriptor to the chip, * increment the software ring descriptor pointer * and tell the chip to poll. * There's no need to pad to ETHERMINTU * here as ApadXmt is set in CSR4. */ dre = &ctlr->tdr[ctlr->tdrh]; dre->bp = bp; dre->addr = PADDR(bp->rp); dre->md2 = 0; dre->md1 = Own|Stp|Enp|(-BLEN(bp) & 0xFFFF); ctlr->ntq++; ctlr->iow(ctlr, Rdp, Iena|Tdmd); ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre); }} static voidtransmit(Ether* ether){ Ctlr *ctlr; ctlr = ether->ctlr; ilock(ctlr); txstart(ether); iunlock(ctlr);} static voidinterrupt(Ureg*, void* arg){ Ctlr *ctlr; Ether *ether; int csr0, len; Dre *dre; Block *bp; ether = arg; ctlr = ether->ctlr; /* * Acknowledge all interrupts and whine about those that shouldn't * happen. */intrloop: csr0 = ctlr->ior(ctlr, Rdp) & 0xFFFF; ctlr->iow(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena); if(csr0 & Merr) ctlr->merr++; if(csr0 & Miss) ctlr->miss++; if(csr0 & Babl) ctlr->babl++; //if(csr0 & (Babl|Miss|Merr)) // print("#l%d: csr0 = 0x%uX\n", ether->ctlrno, csr0); if(!(csr0 & (Rint|Tint))) return; /* * Receiver interrupt: run round the descriptor ring logging * errors and passing valid receive data up to the higher levels * until a descriptor is encountered still owned by the chip. */ if(csr0 & Rint){ dre = &ctlr->rdr[ctlr->rdrx]; while(!(dre->md1 & Own)){ if(dre->md1 & RxErr){ if(dre->md1 & RxBuff) ctlr->rxbuff++; if(dre->md1 & Crc) ctlr->crc++; if(dre->md1 & Oflo) ctlr->oflo++; if(dre->md1 & Fram) ctlr->fram++; } else if(bp = iallocb(Rbsize)){ len = (dre->md2 & 0x0FFF)-4; dre->bp->wp = dre->bp->rp+len; etheriq(ether, dre->bp, 1); dre->bp = bp; dre->addr = PADDR(bp->rp); } /* * Finished with this descriptor, reinitialise it, * give it back to the chip, then on to the next... */ dre->md2 = 0; dre->md1 = Own|(-Rbsize & 0xFFFF); ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre); dre = &ctlr->rdr[ctlr->rdrx]; } } /* * Transmitter interrupt: wakeup anyone waiting for a free descriptor. */ if(csr0 & Tint){ lock(ctlr); while(ctlr->ntq){ dre = &ctlr->tdr[ctlr->tdri]; if(dre->md1 & Own) break; if(dre->md1 & TxErr){ if(dre->md2 & Rtry) ctlr->rtry++; if(dre->md2 & Lcar) ctlr->lcar++; if(dre->md2 & Lcol) ctlr->lcol++; if(dre->md2 & Uflo) ctlr->uflo++; if(dre->md2 & TxBuff) ctlr->txbuff++; ether->oerrs++; } freeb(dre->bp); ctlr->ntq--; ctlr->tdri = NEXT(ctlr->tdri, Ntdre); } txstart(ether); unlock(ctlr); } goto intrloop;} static voidamd79c970pci(void){ int port; Ctlr *ctlr; Pcidev *p; p = nil; while(p = pcimatch(p, 0x1022, 0x2000)){ port = p->mem[0].bar & ~0x01; if(ioalloc(port, p->mem[0].size, 0, "amd79c970") < 0){ print("amd79c970: port 0x%uX in use\n", port); continue; } ctlr = malloc(sizeof(Ctlr)); ctlr->port = p->mem[0].bar & ~0x01; ctlr->pcidev = p; if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; }} static intreset(Ether* ether){ int x; uchar ea[Eaddrlen]; Ctlr *ctlr; if(ctlrhead == nil) amd79c970pci(); /* * Any adapter matches if no port is supplied, * otherwise the ports must match. */ for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){ if(ctlr->active) continue;Lines 1–500 of 645. Load more
/* * AMD79C970 * PCnet-PCI Single-Chip Ethernet Controller for PCI Local Bus * To do: * finish this rewrite */ #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 { Lognrdre = 6, Nrdre = (1<<Lognrdre),/* receive descriptor ring entries */ Logntdre = 4, Ntdre = (1<<Logntdre),/* transmit descriptor ring entries */ Rbsize = ETHERMAXTU+4, /* ring buffer size (+4 for CRC) */ }; enum { /* DWIO I/O resource map */ Aprom = 0x0000, /* physical address */ Rdp = 0x0010, /* register data port */ Rap = 0x0014, /* register address port */ Sreset = 0x0018, /* software reset */ Bdp = 0x001C, /* bus configuration register data port */ }; enum { /* CSR0 */ Init = 0x0001, /* begin initialisation */ Strt = 0x0002, /* enable chip */ Stop = 0x0004, /* disable chip */ Tdmd = 0x0008, /* transmit demand */ Txon = 0x0010, /* transmitter on */ Rxon = 0x0020, /* receiver on */ Iena = 0x0040, /* interrupt enable */ Intr = 0x0080, /* interrupt flag */ Idon = 0x0100, /* initialisation done */ Tint = 0x0200, /* transmit interrupt */ Rint = 0x0400, /* receive interrupt */ Merr = 0x0800, /* memory error */ Miss = 0x1000, /* missed frame */ Cerr = 0x2000, /* collision */ Babl = 0x4000, /* transmitter timeout */ Err = 0x8000, /* Babl|Cerr|Miss|Merr */ }; enum { /* CSR3 */ Bswp = 0x0004, /* byte swap */ Emba = 0x0008, /* enable modified back-off algorithm */ Dxmt2pd = 0x0010, /* disable transmit two part deferral */ Lappen = 0x0020, /* look-ahead packet processing enable */ }; enum { /* CSR4 */ ApadXmt = 0x0800, /* auto pad transmit */ }; enum { /* CSR15 */ Prom = 0x8000, /* promiscuous mode */ }; typedef struct Iblock Iblock; struct Iblock { /* Initialisation Block */ ushort mode; uchar rlen; /* upper 4 bits */ uchar tlen; /* upper 4 bits */ uchar padr[6]; uchar res[2]; uchar ladr[8]; ulong rdra; ulong tdra; }; typedef struct Dre Dre; struct Dre { /* descriptor ring entry */ ulong addr; ulong md1; /* status|bcnt */ ulong md2; /* rcc|rpc|mcnt */ Block* bp; }; enum { /* md1 */ Enp = 0x01000000, /* end of packet */ Stp = 0x02000000, /* start of packet */ RxBuff = 0x04000000, /* buffer error */ Def = 0x04000000, /* deferred */ Crc = 0x08000000, /* CRC error */ One = 0x08000000, /* one retry needed */ Oflo = 0x10000000, /* overflow error */ More = 0x10000000, /* more than one retry needed */ Fram = 0x20000000, /* framing error */ RxErr = 0x40000000, /* Fram|Oflo|Crc|RxBuff */ TxErr = 0x40000000, /* Uflo|Lcol|Lcar|Rtry */ Own = 0x80000000, }; enum { /* md2 */ Rtry = 0x04000000, /* failed after repeated retries */ Lcar = 0x08000000, /* loss of carrier */ Lcol = 0x10000000, /* late collision */ Uflo = 0x40000000, /* underflow error */ TxBuff = 0x80000000, /* buffer error */ }; typedef struct Ctlr Ctlr; struct Ctlr { Lock; int port; Pcidev* pcidev; Ctlr* next; int active; int init; /* initialisation in progress */ Iblock iblock; Dre* rdr; /* receive descriptor ring */ int rdrx; Dre* tdr; /* transmit descriptor ring */ int tdrh; /* host index into tdr */ int tdri; /* interface index into tdr */ int ntq; /* descriptors active */ ulong rxbuff; /* receive statistics */ ulong crc; ulong oflo; ulong fram; ulong rtry; /* transmit statistics */ ulong lcar; ulong lcol; ulong uflo; ulong txbuff; ulong merr; /* bobf is such a whiner */ ulong miss; ulong babl; int (*ior)(Ctlr*, int); void (*iow)(Ctlr*, int, int); }; static Ctlr* ctlrhead; static Ctlr* ctlrtail; /* * The Rdp, Rap, Sreset, Bdp ports are 32-bit port offset in the enumeration above. * To get to 16-bit offsets, scale down with 0x10 staying the same. */ static int io16r(Ctlr *c, int r) { if(r >= Rdp) r = (r-Rdp)/2+Rdp; return ins(c->port+r); } static void io16w(Ctlr *c, int r, int v) { if(r >= Rdp) r = (r-Rdp)/2+Rdp; outs(c->port+r, v); } static int io32r(Ctlr *c, int r) { return inl(c->port+r); } static void io32w(Ctlr *c, int r, int v) { outl(c->port+r, v); } static void attach(Ether*) { } static long ifstat(Ether* ether, void* a, long n, ulong offset) { char *p; int len; Ctlr *ctlr; ctlr = ether->ctlr; ether->crcs = ctlr->crc; ether->frames = ctlr->fram; ether->buffs = ctlr->rxbuff+ctlr->txbuff; ether->overflows = ctlr->oflo; if(n == 0) return 0; p = malloc(READSTR); len = snprint(p, READSTR, "Rxbuff: %ld\n", ctlr->rxbuff); len += snprint(p+len, READSTR-len, "Crc: %ld\n", ctlr->crc); len += snprint(p+len, READSTR-len, "Oflo: %ld\n", ctlr->oflo); len += snprint(p+len, READSTR-len, "Fram: %ld\n", ctlr->fram); len += snprint(p+len, READSTR-len, "Rtry: %ld\n", ctlr->rtry); len += snprint(p+len, READSTR-len, "Lcar: %ld\n", ctlr->lcar); len += snprint(p+len, READSTR-len, "Lcol: %ld\n", ctlr->lcol); len += snprint(p+len, READSTR-len, "Uflo: %ld\n", ctlr->uflo); len += snprint(p+len, READSTR-len, "Txbuff: %ld\n", ctlr->txbuff); len += snprint(p+len, READSTR-len, "Merr: %ld\n", ctlr->merr); len += snprint(p+len, READSTR-len, "Miss: %ld\n", ctlr->miss); snprint(p+len, READSTR-len, "Babl: %ld\n", ctlr->babl); n = readstr(offset, a, n, p); free(p); return n; } static void ringinit(Ctlr* ctlr) { Dre *dre; /* * Initialise the receive and transmit buffer rings. * The ring entries must be aligned on 16-byte boundaries. * * This routine is protected by ctlr->init. */ if(ctlr->rdr == 0){ ctlr->rdr = xspanalloc(Nrdre*sizeof(Dre), 0x10, 0); for(dre = ctlr->rdr; dre < &ctlr->rdr[Nrdre]; dre++){ dre->bp = iallocb(Rbsize); if(dre->bp == nil) panic("can't allocate ethernet receive ring\n"); dre->addr = PADDR(dre->bp->rp); dre->md2 = 0; dre->md1 = Own|(-Rbsize & 0xFFFF); } } ctlr->rdrx = 0; if(ctlr->tdr == 0) ctlr->tdr = xspanalloc(Ntdre*sizeof(Dre), 0x10, 0); memset(ctlr->tdr, 0, Ntdre*sizeof(Dre)); ctlr->tdrh = ctlr->tdri = 0; } static void promiscuous(void* arg, int on) { Ether *ether; int x; Ctlr *ctlr; ether = arg; ctlr = ether->ctlr; /* * Put the chip into promiscuous mode. First must wait until * anyone transmitting is done, then stop the chip and put * it in promiscuous mode. Restarting is made harder by the chip * reloading the transmit and receive descriptor pointers with their * base addresses when Strt is set (unlike the older Lance chip), * so the rings must be re-initialised. */ ilock(ctlr); if(ctlr->init){ iunlock(ctlr); return; } ctlr->init = 1; iunlock(ctlr); while(ctlr->ntq) ; ctlr->iow(ctlr, Rdp, Stop); ctlr->iow(ctlr, Rap, 15); x = ctlr->ior(ctlr, Rdp) & ~Prom; if(on) x |= Prom; ctlr->iow(ctlr, Rdp, x); ctlr->iow(ctlr, Rap, 0); ringinit(ctlr); ilock(ctlr); ctlr->init = 0; ctlr->iow(ctlr, Rdp, Iena|Strt); iunlock(ctlr); } static void multicast(void* arg, uchar*, int) { promiscuous(arg, 1); } static void txstart(Ether* ether) { Ctlr *ctlr; Block *bp; Dre *dre; ctlr = ether->ctlr; if(ctlr->init) return; while(ctlr->ntq < (Ntdre-1)){ bp = qget(ether->oq); if(bp == nil) break; /* * Give ownership of the descriptor to the chip, * increment the software ring descriptor pointer * and tell the chip to poll. * There's no need to pad to ETHERMINTU * here as ApadXmt is set in CSR4. */ dre = &ctlr->tdr[ctlr->tdrh]; dre->bp = bp; dre->addr = PADDR(bp->rp); dre->md2 = 0; dre->md1 = Own|Stp|Enp|(-BLEN(bp) & 0xFFFF); ctlr->ntq++; ctlr->iow(ctlr, Rdp, Iena|Tdmd); ctlr->tdrh = NEXT(ctlr->tdrh, Ntdre); } } static void transmit(Ether* ether) { Ctlr *ctlr; ctlr = ether->ctlr; ilock(ctlr); txstart(ether); iunlock(ctlr); } static void interrupt(Ureg*, void* arg) { Ctlr *ctlr; Ether *ether; int csr0, len; Dre *dre; Block *bp; ether = arg; ctlr = ether->ctlr; /* * Acknowledge all interrupts and whine about those that shouldn't * happen. */ intrloop: csr0 = ctlr->ior(ctlr, Rdp) & 0xFFFF; ctlr->iow(ctlr, Rdp, Babl|Cerr|Miss|Merr|Rint|Tint|Iena); if(csr0 & Merr) ctlr->merr++; if(csr0 & Miss) ctlr->miss++; if(csr0 & Babl) ctlr->babl++; //if(csr0 & (Babl|Miss|Merr)) // print("#l%d: csr0 = 0x%uX\n", ether->ctlrno, csr0); if(!(csr0 & (Rint|Tint))) return; /* * Receiver interrupt: run round the descriptor ring logging * errors and passing valid receive data up to the higher levels * until a descriptor is encountered still owned by the chip. */ if(csr0 & Rint){ dre = &ctlr->rdr[ctlr->rdrx]; while(!(dre->md1 & Own)){ if(dre->md1 & RxErr){ if(dre->md1 & RxBuff) ctlr->rxbuff++; if(dre->md1 & Crc) ctlr->crc++; if(dre->md1 & Oflo) ctlr->oflo++; if(dre->md1 & Fram) ctlr->fram++; } else if(bp = iallocb(Rbsize)){ len = (dre->md2 & 0x0FFF)-4; dre->bp->wp = dre->bp->rp+len; etheriq(ether, dre->bp, 1); dre->bp = bp; dre->addr = PADDR(bp->rp); } /* * Finished with this descriptor, reinitialise it, * give it back to the chip, then on to the next... */ dre->md2 = 0; dre->md1 = Own|(-Rbsize & 0xFFFF); ctlr->rdrx = NEXT(ctlr->rdrx, Nrdre); dre = &ctlr->rdr[ctlr->rdrx]; } } /* * Transmitter interrupt: wakeup anyone waiting for a free descriptor. */ if(csr0 & Tint){ lock(ctlr); while(ctlr->ntq){ dre = &ctlr->tdr[ctlr->tdri]; if(dre->md1 & Own) break; if(dre->md1 & TxErr){ if(dre->md2 & Rtry) ctlr->rtry++; if(dre->md2 & Lcar) ctlr->lcar++; if(dre->md2 & Lcol) ctlr->lcol++; if(dre->md2 & Uflo) ctlr->uflo++; if(dre->md2 & TxBuff) ctlr->txbuff++; ether->oerrs++; } freeb(dre->bp); ctlr->ntq--; ctlr->tdri = NEXT(ctlr->tdri, Ntdre); } txstart(ether); unlock(ctlr); } goto intrloop; } static void amd79c970pci(void) { int port; Ctlr *ctlr; Pcidev *p; p = nil; while(p = pcimatch(p, 0x1022, 0x2000)){ port = p->mem[0].bar & ~0x01; if(ioalloc(port, p->mem[0].size, 0, "amd79c970") < 0){ print("amd79c970: port 0x%uX in use\n", port); continue; } ctlr = malloc(sizeof(Ctlr)); ctlr->port = p->mem[0].bar & ~0x01; ctlr->pcidev = p; if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; } } static int reset(Ether* ether) { int x; uchar ea[Eaddrlen]; Ctlr *ctlr; if(ctlrhead == nil) amd79c970pci(); /* * Any adapter matches if no port is supplied, * otherwise the ports must match. */ for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){ if(ctlr->active) continue;