static char* poweron(Ctlr *ctlr) { char *err; if(ctlr->power) return nil; csr32w(ctlr, AnaPll, csr32r(ctlr, AnaPll) | Init); /* Disable L0s. */ csr32w(ctlr, GioChicken, csr32r(ctlr, GioChicken) | L1AnoL0Srx); if((err = clockwait(ctlr)) != nil) return err; if((err = niclock(ctlr)) != nil) return err; prphwrite(ctlr, ApmgClkEna, DmaClkRqt | BsmClkRqt); delay(20); /* Disable L1. */ prphwrite(ctlr, ApmgPciStt, prphread(ctlr, ApmgPciStt) | (1<<11)); nicunlock(ctlr); ctlr->power = 1; return nil; }
static char* eepromread(Ctlr *ctlr, void *data, int count, uint off) { uchar *out = data; char *err; u32int w = 0; int i; if((err = niclock(ctlr)) != nil) return err; for(; count > 0; count -= 2, off++){ csr32w(ctlr, Eeprom, off << 2); csr32w(ctlr, Eeprom, csr32r(ctlr, Eeprom) & ~(1<<1)); for(i = 0; i < 10; i++){ w = csr32r(ctlr, Eeprom); if(w & 1) break; delay(5); } if(i == 10) break; *out++ = w >> 16; if(count > 1) *out++ = w >> 24; } nicunlock(ctlr); if(count > 0) return "eeprompread: timeout"; return nil; }
static void wpiinterrupt(Ureg*, void *arg) { u32int isr, fhisr; Ether *edev; Ctlr *ctlr; edev = arg; ctlr = edev->ctlr; ilock(ctlr); csr32w(ctlr, Imr, 0); isr = csr32r(ctlr, Isr); fhisr = csr32r(ctlr, FhIsr); if(isr == 0xffffffff || (isr & 0xfffffff0) == 0xa5a5a5a0){ iunlock(ctlr); return; } if(isr == 0 && fhisr == 0) goto done; csr32w(ctlr, Isr, isr); csr32w(ctlr, FhIsr, fhisr); if((isr & (Iswrx | Ifhrx)) || (fhisr & Ifhrx)) receive(ctlr); if(isr & Ierr){ ctlr->broken = 1; iprint("#l%d: fatal firmware error, lastcmd %ud\n", edev->ctlrno, ctlr->tx[4].lastcmd); } ctlr->wait.m |= isr; if(ctlr->wait.m & ctlr->wait.w) wakeup(&ctlr->wait); done: csr32w(ctlr, Imr, ctlr->ie); iunlock(ctlr); }
static void prphwrite(Ctlr *ctlr, uint off, u32int data) { csr32w(ctlr, PrphWaddr, ((sizeof(u32int)-1)<<24) | off); coherence(); csr32w(ctlr, PrphWdata, data); }
static void i82563interrupt(Ureg*, void* arg) { int icr, im, rdh, txdw = 0; Block *bp; Ctlr *ctlr; Ether *edev; Rdesc *rdesc; edev = arg; ctlr = edev->ctlr; ilock(&ctlr->imlock); csr32w(ctlr, Imc, ~0); im = ctlr->im; for(icr = csr32r(ctlr, Icr); icr & ctlr->im; icr = csr32r(ctlr, Icr)){ if(icr & (Rxseq|Lsc)){ /* should be more here */ } rdh = ctlr->rdh; for (;;) { rdesc = &ctlr->rdba[rdh]; if(!(rdesc->status & Rdd)) break; if ((rdesc->status & Reop) && rdesc->errors == 0) { bp = ctlr->rb[rdh]; if(0 && memcmp(bp->rp, broadcast, 6) != 0) print("#l%d: rx %d %E %E %d\n", edev->ctlrno, rdh, bp->rp, bp->rp+6, rdesc->length); ctlr->rb[rdh] = nil; bp->wp += rdesc->length; if (interesting(bp)) toringbuf(edev, bp); freeb(bp); } else if (rdesc->status & Reop && rdesc->errors) print("%s: input packet error %#ux\n", tname[ctlr->type], rdesc->errors); rdesc->status = 0; rdh = NEXT(rdh, Nrdesc); } ctlr->rdh = rdh; if(icr & Rxdmt0) i82563replenish(ctlr); if(icr & Txdw){ im &= ~Txdw; txdw++; } } ctlr->im = im; csr32w(ctlr, Ims, im); iunlock(&ctlr->imlock); if(txdw) i82563transmit(edev); }
static void i82563attach(Ether* edev) { int ctl; Ctlr *ctlr; ctlr = edev->ctlr; i82563im(ctlr, 0); ctl = csr32r(ctlr, Rctl)|Ren; csr32w(ctlr, Rctl, ctl); ctl = csr32r(ctlr, Tctl)|Ten; csr32w(ctlr, Tctl, ctl); }
static void poweroff(Ctlr *ctlr) { int i, j; csr32w(ctlr, Reset, Nevo); /* Disable interrupts. */ csr32w(ctlr, Imr, 0); csr32w(ctlr, Isr, ~0); csr32w(ctlr, FhIsr, ~0); if(niclock(ctlr) == nil){ /* Stop TX scheduler. */ prphwrite(ctlr, AlmSchedMode, 0); prphwrite(ctlr, AlmSchedTxfact, 0); /* Stop all DMA channels */ for(i = 0; i < 6; i++){ csr32w(ctlr, FhTxConfig + i*32, 0); for(j = 0; j < 100; j++){ if((csr32r(ctlr, FhTxStatus) & (0x1010000<<i)) == (0x1010000<<i)) break; delay(10); } } nicunlock(ctlr); } /* Stop RX ring. */ if(niclock(ctlr) == nil){ csr32w(ctlr, FhRxConfig, 0); for(j = 0; j < 100; j++){ if(csr32r(ctlr, FhRxStatus) & (1<<24)) break; delay(10); } nicunlock(ctlr); } if(niclock(ctlr) == nil){ prphwrite(ctlr, ApmgClkDis, DmaClkRqt); nicunlock(ctlr); } delay(5); csr32w(ctlr, Reset, csr32r(ctlr, Reset) | StopMaster); if((csr32r(ctlr, Gpc) & (7<<24)) != (4<<24)){ for(j = 0; j < 100; j++){ if(csr32r(ctlr, Reset) & MasterDisabled) break; delay(10); } } csr32w(ctlr, Reset, csr32r(ctlr, Reset) | SW); ctlr->power = 0; }
static void txstart(Ether *edev) { int tdh, tdt; Ctlr *ctlr = edev->ctlr; Block *bp; Tdesc *tdesc; /* * Try to fill the ring back up, moving buffers from the transmit q. */ tdh = PREV(ctlr->tdh, Ntdesc); for(tdt = ctlr->tdt; tdt != tdh; tdt = NEXT(tdt, Ntdesc)){ /* pull off the head of the transmission queue */ if((bp = ctlr->bqhead) == nil) /* was qget(edev->oq) */ break; ctlr->bqhead = bp->next; if (ctlr->bqtail == bp) ctlr->bqtail = nil; /* set up a descriptor for it */ tdesc = &ctlr->tdba[tdt]; tdesc->addr[0] = PCIWADDR(bp->rp); tdesc->addr[1] = 0; tdesc->control = /* Ide | */ Rs | Ifcs | Teop | BLEN(bp); ctlr->tb[tdt] = bp; } ctlr->tdt = tdt; csr32w(ctlr, Tdt, tdt); i82563im(ctlr, Txdw); }
static u32int prphread(Ctlr *ctlr, uint off) { csr32w(ctlr, PrphRaddr, ((sizeof(u32int)-1)<<24) | off); coherence(); return csr32r(ctlr, PrphRdata); }
static void igbereplenish(Ctlr* ctlr) { int rdt; Block *bp; Rdesc *rdesc; rdt = ctlr->rdt; while(NEXT(rdt, Nrdesc) != ctlr->rdh){ rdesc = &ctlr->rdba[rdt]; if(ctlr->rb[rdt] != nil){ /* nothing to do */ } else if((bp = iallocb(2048)) != nil){ ctlr->rb[rdt] = bp; rdesc->addr[0] = PCIWADDR(bp->rp); rdesc->addr[1] = 0; } else break; rdesc->status = 0; rdt = NEXT(rdt, Nrdesc); } ctlr->rdt = rdt; csr32w(ctlr, Rdt, rdt); }
static void igbetransmit(Ether* edev) { Block *bp; Ctlr *ctlr; Tdesc *tdesc; RingBuf *tb; int tdh; /* * For now there are no smarts here. Tuning comes later. */ ctlr = edev->ctlr; ilock(&ctlr->tdlock); /* * Free any completed packets * - try to get the soft tdh to catch the tdt; * - if the packet had an underrun bump the threshold * - the Tu bit doesn't seem to ever be set, perhaps * because Rs mode is used? */ tdh = ctlr->tdh; for(;;){ tdesc = &ctlr->tdba[tdh]; if(!(tdesc->status & Tdd)) break; if(tdesc->status & Tu){ ctlr->ett++; csr32w(ctlr, Ett, ctlr->ett); } tdesc->status = 0; if(ctlr->tb[tdh] != nil){ freeb(ctlr->tb[tdh]); ctlr->tb[tdh] = nil; } tdh = NEXT(tdh, Ntdesc); } ctlr->tdh = tdh; /* copy packets from the software RingBuf to the transmission q */ /* from boot ether83815.c */ while((tb = &edev->tb[edev->ti])->owner == Interface){ bp = fromringbuf(edev); /* put the buffer on the transmit queue */ if(ctlr->bqhead) ctlr->bqtail->next = bp; else ctlr->bqhead = bp; ctlr->bqtail = bp; txstart(edev); /* kick transmitter */ tb->owner = Host; /* give descriptor back */ edev->ti = NEXT(edev->ti, edev->ntb); } iunlock(&ctlr->tdlock); }
static ushort eeread(Ctlr* ctlr, int adr) { csr32w(ctlr, Eerd, ee_start | adr << 2); while ((csr32r(ctlr, Eerd) & ee_done) == 0) ; return csr32r(ctlr, Eerd) >> 16; }
static void igbeim(Ctlr* ctlr, int im) { ilock(&ctlr->imlock); ctlr->im |= im; csr32w(ctlr, Ims, ctlr->im); iunlock(&ctlr->imlock); }
static void rtl8139init(Ether* edev) { int i; uint32_t r; Ctlr *ctlr; uint8_t *alloc; ctlr = edev->ctlr; ilock(&ctlr->ilock); rtl8139halt(ctlr); /* * MAC Address. */ r = (edev->ea[3]<<24)|(edev->ea[2]<<16)|(edev->ea[1]<<8)|edev->ea[0]; csr32w(ctlr, Idr0, r); r = (edev->ea[5]<<8)|edev->ea[4]; csr32w(ctlr, Idr0+4, r); /* * Receiver */ alloc = (uint8_t*)ROUNDUP((uint32_t)ctlr->alloc, 32); ctlr->rbstart = alloc; alloc += ctlr->rblen+16; memset(ctlr->rbstart, 0, ctlr->rblen+16); csr32w(ctlr, Rbstart, PADDR(ctlr->rbstart)); ctlr->rcr = Rxfth256|Rblen|Mrxdmaunlimited|Ab|Apm; /* * Transmitter. */ for(i = 0; i < Ntd; i++){ ctlr->td[i].tsd = Tsd0+i*4; ctlr->td[i].tsad = Tsad0+i*4; ctlr->td[i].data = alloc; alloc += Tdbsz; } ctlr->ntd = ctlr->tdh = ctlr->tdi = 0; ctlr->etxth = 128/32; /* * Interrupts. */ csr32w(ctlr, TimerInt, 0); csr16w(ctlr, Imr, Serr|Timer|Fovw|PunLc|Rxovw|Ter|Tok|Rer|Rok); csr32w(ctlr, Mpc, 0); /* * Enable receiver/transmitter. * Need to enable before writing the Rcr or it won't take. */ csr8w(ctlr, Cr, Te|Re); csr32w(ctlr, Tcr, Mtxdma2048); csr32w(ctlr, Rcr, ctlr->rcr); iunlock(&ctlr->ilock); }
static void detach(Ctlr *ctlr) { int r; csr32w(ctlr, Imc, ~0); csr32w(ctlr, Rctl, 0); csr32w(ctlr, Tctl, 0); delay(10); r = csr32r(ctlr, Ctrl); if(ctlr->type == i82566 || ctlr->type == i82567) r |= Phy_rst; csr32w(ctlr, Ctrl, Devrst | r); /* apparently needed on multi-GHz processors to avoid infinite loops */ delay(1); while(csr32r(ctlr, Ctrl) & Devrst) ; if(1 || ctlr->type != i82563){ r = csr32r(ctlr, Ctrl); csr32w(ctlr, Ctrl, Slu | r); } csr32w(ctlr, Ctrlext, Eerst | csr32r(ctlr, Ctrlext)); delay(1); while(csr32r(ctlr, Ctrlext) & Eerst) ; csr32w(ctlr, Imc, ~0); delay(1); while(csr32r(ctlr, Icr)) ; }
static void axpenable(Uart* uart, int ie) { Cc *cc; Ctlr *ctlr; u16int lp; cc = uart->regs; ctlr = cc->ctlr; /* * Enable interrupts and turn on DTR and RTS. * Be careful if this is called to set up a polled serial line * early on not to try to enable interrupts as interrupt- * -enabling mechanisms might not be set up yet. */ if(ie){ /* * The Uart is qlocked. */ if(ctlr->im == 0){ intrenable(ctlr->pcidev->intl, axpinterrupt, ctlr, ctlr->pcidev->tbdf, ctlr->name); csr32w(ctlr, Ics, 0x00031F00); csr32w(ctlr, Pdb, 1); ctlr->gcb->gcw2 = 1; } ctlr->im |= 1<<cc->uartno; } (*uart->phys->dtr)(uart, 1); (*uart->phys->rts)(uart, 1); /* * Make sure we control RTS, DTR and break. */ lp = cc->ccb->lp; cc->ccb->lp = Emcs|lp; cc->ccb->oblw = 64; axpcc(cc, Et|Er|Ccu); }
static int i82543mdior(Ctlr* ctlr, int n) { int ctrl, data, i, r; /* * Read n bits from the Management Data I/O Interface. */ ctrl = csr32r(ctlr, Ctrl); r = (ctrl & ~Mddo)|Mdco; data = 0; for(i = n-1; i >= 0; i--){ if(csr32r(ctlr, Ctrl) & Mdd) data |= (1<<i); csr32w(ctlr, Ctrl, Mdc|r); csr32w(ctlr, Ctrl, r); } csr32w(ctlr, Ctrl, ctrl); return data; }
static void igbeattach(Ether* edev) { int ctl; Ctlr *ctlr; /* * To do here: * one-time stuff; * start off a kproc for link status change: * adjust queue length depending on speed; * flow control. * more needed here... */ ctlr = edev->ctlr; igbeim(ctlr, 0); ctl = csr32r(ctlr, Rctl)|Ren; csr32w(ctlr, Rctl, ctl); ctl = csr32r(ctlr, Tctl)|Ten; csr32w(ctlr, Tctl, ctl); }
static char* niclock(Ctlr *ctlr) { int i; csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | MacAccessReq); for(i=0; i<1000; i++){ if((csr32r(ctlr, Gpc) & (NicSleep | MacAccessEna)) == MacAccessEna) return 0; delay(10); } return "niclock: timeout"; }
static void attach(Ether* ether) { Ctlr *ctlr; ctlr = ether->ctlr; ilock(&ctlr->lock); if(!(ctlr->csr6 & Sr)){ ctlr->csr6 |= Sr; csr32w(ctlr, 6, ctlr->csr6); } iunlock(&ctlr->lock); }
static int i82543mdiow(Ctlr* ctlr, int bits, int n) { int ctrl, i, r; /* * Write n bits to the Management Data I/O Interface. */ ctrl = csr32r(ctlr, Ctrl); r = Mdco|Mddo|ctrl; for(i = n-1; i >= 0; i--){ if(bits & (1<<i)) r |= Mdd; else r &= ~Mdd; csr32w(ctlr, Ctrl, Mdc|r); csr32w(ctlr, Ctrl, r); } csr32w(ctlr, Ctrl, ctrl); return 0; }
static void promiscuous(void* arg, int on) { Ctlr *ctlr; ctlr = ((Ether*)arg)->ctlr; ilock(&ctlr->lock); if(on) ctlr->csr6 |= Pr; else ctlr->csr6 &= ~Pr; csr32w(ctlr, 6, ctlr->csr6); iunlock(&ctlr->lock); }
static char* clockwait(Ctlr *ctlr) { int i; /* Set "initialization complete" bit. */ csr32w(ctlr, Gpc, csr32r(ctlr, Gpc) | InitDone); for(i=0; i<2500; i++){ if(csr32r(ctlr, Gpc) & MacClockReady) return nil; delay(10); } return "clockwait: timeout"; }
static void txstart(Ether *edev) { int tdh, tdt, len, olen; Ctlr *ctlr = edev->ctlr; Block *bp; Tdesc *tdesc; /* * Try to fill the ring back up, moving buffers from the transmit q. */ tdh = PREV(ctlr->tdh, Ntdesc); for(tdt = ctlr->tdt; tdt != tdh; tdt = NEXT(tdt, Ntdesc)){ /* pull off the head of the transmission queue */ if((bp = ctlr->bqhead) == nil) /* was qget(edev->oq) */ break; ctlr->bqhead = bp->next; if (ctlr->bqtail == bp) ctlr->bqtail = nil; len = olen = BLEN(bp); /* * if packet is too short, make it longer rather than relying * on ethernet interface to pad it and complain so the caller * will get fixed. I don't think Psp is working right, or it's * getting cleared. */ if (len < ETHERMINTU) { if (bp->rp + ETHERMINTU <= bp->lim) bp->wp = bp->rp + ETHERMINTU; else bp->wp = bp->lim; len = BLEN(bp); print("txstart: extended short pkt %d -> %d bytes\n", olen, len); } /* set up a descriptor for it */ tdesc = &ctlr->tdba[tdt]; tdesc->addr[0] = PCIWADDR(bp->rp); tdesc->addr[1] = 0; tdesc->control = /* Ide| */ Rs|Dext|Ifcs|Teop|DtypeDD|len; tdesc->status = 0; ctlr->tb[tdt] = bp; } ctlr->tdt = tdt; csr32w(ctlr, Tdt, tdt); igbeim(ctlr, Txdw); }
static void detach(Ctlr *ctlr) { int r; /* * Perform a device reset to get the chip back to the * power-on state, followed by an EEPROM reset to read * the defaults for some internal registers. */ csr32w(ctlr, Imc, ~0); csr32w(ctlr, Rctl, 0); csr32w(ctlr, Tctl, 0); delay(20); csr32w(ctlr, Ctrl, Devrst); /* apparently needed on multi-GHz processors to avoid infinite loops */ delay(1); while(csr32r(ctlr, Ctrl) & Devrst) ; csr32w(ctlr, Ctrlext, Eerst | csr32r(ctlr, Ctrlext)); delay(1); while(csr32r(ctlr, Ctrlext) & Eerst) ; switch(ctlr->id){ default: break; case i82540em: case i82540eplp: case i82541gi: case i82541pi: case i82547gi: case i82546gb: case i82546eb: r = csr32r(ctlr, Manc); r &= ~Arpen; csr32w(ctlr, Manc, r); break; } csr32w(ctlr, Imc, ~0); delay(1); while(csr32r(ctlr, Icr)) ; }
static int igbemiimiw(Mii* mii, int pa, int ra, int data) { Ctlr *ctlr; int mdic, timo; ctlr = mii->ctlr; data &= MDIdMASK; csr32w(ctlr, Mdic, MDIwop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT)|data); mdic = 0; for(timo = 64; timo; timo--){ mdic = csr32r(ctlr, Mdic); if(mdic & (MDIe|MDIready)) break; microdelay(1); } if((mdic & (MDIe|MDIready)) == MDIready) return 0; return -1; }
static int igbemiimir(Mii* mii, int pa, int ra) { Ctlr *ctlr; int mdic, timo; ctlr = mii->ctlr; csr32w(ctlr, Mdic, MDIrop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT)); mdic = 0; for(timo = 64; timo; timo--){ mdic = csr32r(ctlr, Mdic); if(mdic & (MDIe|MDIready)) break; microdelay(1); } if((mdic & (MDIe|MDIready)) == MDIready) return mdic & 0xFFFF; return -1; }
static void txstart(Ether* ether) { Ctlr *ctlr; Block *bp; Des *des; int control; ctlr = ether->ctlr; while(ctlr->ntq < (ctlr->ntdr-1)){ if(ctlr->setupbp){ bp = ctlr->setupbp; ctlr->setupbp = 0; control = Ic|Set|BLEN(bp); } else{ bp = qget(ether->oq); if(bp == nil) break; control = Ic|Lseg|Fseg|BLEN(bp); } ctlr->tdr[PREV(ctlr->tdrh, ctlr->ntdr)].control &= ~Ic; des = &ctlr->tdr[ctlr->tdrh]; des->bp = bp; des->addr = PCIWADDR(bp->rp); des->control |= control; ctlr->ntq++; coherence(); des->status = Own; csr32w(ctlr, 1, 0); ctlr->tdrh = NEXT(ctlr->tdrh, ctlr->ntdr); } if(ctlr->ntq > ctlr->ntqmax) ctlr->ntqmax = ctlr->ntq; }
static int igbeinit(Ether* edev) { int csr, i, r, ctrl, timeo; MiiPhy *phy; Ctlr *ctlr; ctlr = edev->ctlr; /* * Set up the receive addresses. * There are 16 addresses. The first should be the MAC address. * The others are cleared and not marked valid (MS bit of Rah). */ csr = (edev->ea[3]<<24)|(edev->ea[2]<<16)|(edev->ea[1]<<8)|edev->ea[0]; csr32w(ctlr, Ral, csr); csr = 0x80000000|(edev->ea[5]<<8)|edev->ea[4]; csr32w(ctlr, Rah, csr); for(i = 1; i < 16; i++){ csr32w(ctlr, Ral+i*8, 0); csr32w(ctlr, Rah+i*8, 0); } /* * Clear the Multicast Table Array. * It's a 4096 bit vector accessed as 128 32-bit registers. */ for(i = 0; i < 128; i++) csr32w(ctlr, Mta+i*4, 0); /* * Receive initialisation. * Mostly defaults from the datasheet, will * need some tuning for performance: * Rctl descriptor mimimum threshold size * discard pause frames * strip CRC * Rdtr interrupt delay * Rxdctl all the thresholds */ csr32w(ctlr, Rctl, 0); /* * Allocate the descriptor ring and load its * address and length into the NIC. */ ctlr->rdba = xspanalloc(Nrdesc*sizeof(Rdesc), 128 /* was 16 */, 0); csr32w(ctlr, Rdbal, PCIWADDR(ctlr->rdba)); csr32w(ctlr, Rdbah, 0); csr32w(ctlr, Rdlen, Nrdesc*sizeof(Rdesc)); /* * Initialise the ring head and tail pointers and * populate the ring with Blocks. * The datasheet says the tail pointer is set to beyond the last * descriptor hardware can process, which implies the initial * condition is Rdh == Rdt. However, experience shows Rdt must * always be 'behind' Rdh; the replenish routine ensures this. */ ctlr->rdh = 0; csr32w(ctlr, Rdh, ctlr->rdh); ctlr->rdt = 0; csr32w(ctlr, Rdt, ctlr->rdt); ctlr->rb = malloc(sizeof(Block*)*Nrdesc); igbereplenish(ctlr); /* * Set up Rctl but don't enable receiver (yet). */ csr32w(ctlr, Rdtr, 0); switch(ctlr->id){ case i82540em: case i82540eplp: case i82541gi: case i82541pi: case i82546gb: case i82546eb: case i82547gi: csr32w(ctlr, Radv, 64); break; } csr32w(ctlr, Rxdctl, (8<<WthreshSHIFT)|(8<<HthreshSHIFT)|4); /* * Enable checksum offload. */ csr32w(ctlr, Rxcsum, Tuofl|Ipofl|(ETHERHDRSIZE<<PcssSHIFT)); csr32w(ctlr, Rctl, Dpf|Bsize2048|Bam|RdtmsHALF); /* * VirtualBox does not like Rxt0, * it continually interrupts. */ ctlr->im |= /*Rxt0|*/Rxo|Rxdmt0|Rxseq; /* * Transmit initialisation. * Mostly defaults from the datasheet, will * need some tuning for performance. The normal mode will * be full-duplex and things to tune for half-duplex are * Tctl re-transmit on late collision * Tipg all IPG times * Tbt burst timer * Ait adaptive IFS throttle * and in general * Txdmac packet prefetching * Ett transmit early threshold * Tidv interrupt delay value * Txdctl all the thresholds */ csr32w(ctlr, Tctl, (0x0F<<CtSHIFT)|Psp|(66<<ColdSHIFT)); /* Fd */ switch(ctlr->id){ default: r = 6; break; case i82543gc: case i82544ei: case i82547ei: case i82540em: case i82540eplp: case i82541gi: case i82541pi: case i82546gb: case i82546eb: case i82547gi: r = 8; break; } csr32w(ctlr, Tipg, (6<<20)|(8<<10)|r); csr32w(ctlr, Ait, 0); csr32w(ctlr, Txdmac, 0); csr32w(ctlr, Tidv, 128); /* * Allocate the descriptor ring and load its * address and length into the NIC. */ ctlr->tdba = xspanalloc(Ntdesc*sizeof(Tdesc), 128 /* was 16 */, 0); csr32w(ctlr, Tdbal, PCIWADDR(ctlr->tdba)); csr32w(ctlr, Tdbah, 0); csr32w(ctlr, Tdlen, Ntdesc*sizeof(Tdesc)); /* * Initialise the ring head and tail pointers. */ ctlr->tdh = 0; csr32w(ctlr, Tdh, ctlr->tdh); ctlr->tdt = 0; csr32w(ctlr, Tdt, ctlr->tdt); ctlr->tb = malloc(sizeof(Block*)*Ntdesc); // ctlr->im |= Txqe|Txdw; r = (4<<WthreshSHIFT)|(4<<HthreshSHIFT)|(8<<PthreshSHIFT); switch(ctlr->id){ default: break; case i82540em: case i82540eplp: case i82547gi: case i82541pi: case i82546gb: case i82546eb: case i82541gi: r = csr32r(ctlr, Txdctl); r &= ~WthreshMASK; r |= Gran|(4<<WthreshSHIFT); csr32w(ctlr, Tadv, 64); break; } csr32w(ctlr, Txdctl, r); r = csr32r(ctlr, Tctl); r |= Ten; csr32w(ctlr, Tctl, r); igbeim(ctlr, ctlr->im); if(ctlr->mii == nil || ctlr->mii->curphy == nil) { print("igbe: no mii (yet)\n"); return 0; } /* wait for the link to come up */ for(timeo = 0; timeo < 3500; timeo++){ if(miistatus(ctlr->mii) == 0) break; delay(10); } print("igbe: phy: "); phy = ctlr->mii->curphy; if (phy->fd) print("full duplex"); else print("half duplex"); print(", %d Mb/s\n", phy->speed); /* * Flow control. */ ctrl = csr32r(ctlr, Ctrl); if(phy->rfc) ctrl |= Rfce; if(phy->tfc) ctrl |= Tfce; csr32w(ctlr, Ctrl, ctrl); return 0; }
static void igbeinterrupt(Ureg*, void* arg) { Block *bp; Ctlr *ctlr; Ether *edev; Rdesc *rdesc; int icr, im, rdh, txdw = 0; edev = arg; ctlr = edev->ctlr; ilock(&ctlr->imlock); csr32w(ctlr, Imc, ~0); im = ctlr->im; if((icr = csr32r(ctlr, Icr)) & ctlr->im){ /* * Link status changed. */ if(icr & (Rxseq|Lsc)){ /* * More here... */ } /* * Process any received packets. */ rdh = ctlr->rdh; for(;;){ rdesc = &ctlr->rdba[rdh]; if(!(rdesc->status & Rdd)) break; if ((rdesc->status & Reop) && rdesc->errors == 0) { bp = ctlr->rb[rdh]; ctlr->rb[rdh] = nil; /* * it appears that the original 82543 needed * to have the Ethernet CRC excluded, but that * the newer chips do not? */ bp->wp += rdesc->length /* -4 */; toringbuf(edev, bp); freeb(bp); } else if ((rdesc->status & Reop) && rdesc->errors) print("igbe: input packet error 0x%ux\n", rdesc->errors); rdesc->status = 0; rdh = NEXT(rdh, Nrdesc); } ctlr->rdh = rdh; if(icr & Rxdmt0) igbereplenish(ctlr); if(icr & Txdw){ im &= ~Txdw; txdw++; } } ctlr->im = im; csr32w(ctlr, Ims, im); iunlock(&ctlr->imlock); if(txdw) igbetransmit(edev); }