📄 etherigbe.c
字号:
igbereplenish(Ctlr* ctlr){ Rd *rd; int rdt; Block *bp; rdt = ctlr->rdt; while(NEXT(rdt, ctlr->nrd) != ctlr->rdh){ rd = &ctlr->rdba[rdt]; if(ctlr->rb[rdt] == nil){ bp = igberballoc(); if(bp == nil) { iprint("igbereplenish: no available buffers\n"); break; } ctlr->rb[rdt] = bp; rd->addr[0] = PCIWADDR(bp->rp); rd->addr[1] = 0; } coherence(); rd->status = 0; rdt = NEXT(rdt, ctlr->nrd); ctlr->rdfree++; } ctlr->rdt = rdt; csr32w(ctlr, Rdt, rdt);}static voidigberxinit(Ctlr* ctlr){ int i; Block *bp; csr32w(ctlr, Rctl, Dpf|Bsize2048|Bam|RdtmsHALF); csr32w(ctlr, Rdbal, PCIWADDR(ctlr->rdba)); csr32w(ctlr, Rdbah, 0); csr32w(ctlr, Rdlen, ctlr->nrd*sizeof(Rd)); ctlr->rdh = 0; csr32w(ctlr, Rdh, 0); ctlr->rdt = 0; csr32w(ctlr, Rdt, 0); ctlr->rdtr = 0; csr32w(ctlr, Rdtr, Fpd|0); for(i = 0; i < ctlr->nrd; i++){ if((bp = ctlr->rb[i]) != nil){ ctlr->rb[i] = nil; freeb(bp); } } igbereplenish(ctlr); switch(ctlr->id){ case i82540em: case i82540eplp: case i82541gi: case i82541gi2: case i82541pi: case i82545gmc: 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));}static intigberim(void* ctlr){ return ((Ctlr*)ctlr)->rim != 0;}static voidigberproc(PROCARG(void *arg)){ Rd *rd; Block *bp; Ctlr *ctlr; int r, rdh; Ether *edev; edev = GETARG(arg); ctlr = edev->ctlr; igberxinit(ctlr); r = csr32r(ctlr, Rctl); r |= Ren; csr32w(ctlr, Rctl, r); for(;;){ ctlr->rim = 0; igbeim(ctlr, Rxt0|Rxo|Rxdmt0|Rxseq); ctlr->rsleep++; sleep(&ctlr->rrendez, igberim, ctlr); rdh = ctlr->rdh; for(;;){ rd = &ctlr->rdba[rdh]; if(!(rd->status & Rdd)) break; /* * Accept eop packets with no errors. * With no errors and the Ixsm bit set, * the descriptor status Tpcs and Ipcs bits give * an indication of whether the checksums were * calculated and valid. */ if((rd->status & Reop) && rd->errors == 0){ bp = ctlr->rb[rdh]; ctlr->rb[rdh] = nil; INCRPTR(bp, rd->length); bp->next = nil; if(!(rd->status & Ixsm)){ ctlr->ixsm++; if(rd->status & Ipcs){ /* * IP checksum calculated * (and valid as errors == 0). */ ctlr->ipcs++;#ifndef FS bp->flag |= Bipck;#endif } if(rd->status & Tcpcs){ /* * TCP/UDP checksum calculated * (and valid as errors == 0). */ ctlr->tcpcs++;#ifndef FS bp->flag |= Btcpck|Budpck;#endif }#ifndef FS bp->checksum = rd->checksum; bp->flag |= Bpktck;#endif } ETHERIQ(edev, bp, 1); } else if(ctlr->rb[rdh] != nil){ freeb(ctlr->rb[rdh]); ctlr->rb[rdh] = nil; } memset(rd, 0, sizeof(Rd)); coherence(); ctlr->rdfree--; rdh = NEXT(rdh, ctlr->nrd); } ctlr->rdh = rdh; if(ctlr->rdfree < ctlr->nrd/2 || (ctlr->rim & Rxdmt0)) igbereplenish(ctlr); }}static voidigbeattach(Ether* edev){ Block *bp; Ctlr *ctlr; char name[KNAMELEN]; ctlr = edev->ctlr; qlock(&ctlr->alock); if(ctlr->alloc != nil){ qunlock(&ctlr->alock); return; } ctlr->nrd = ROUND(Nrd, 8); ctlr->ntd = ROUND(Ntd, 8); ctlr->alloc = malloc(ctlr->nrd*sizeof(Rd)+ctlr->ntd*sizeof(Td) + 127); if(ctlr->alloc == nil){ qunlock(&ctlr->alock); return; } ctlr->rdba = (Rd*)ROUNDUP((uintptr)ctlr->alloc, 128); ctlr->tdba = (Td*)(ctlr->rdba+ctlr->nrd); ctlr->rb = malloc(ctlr->nrd*sizeof(Block*)); ctlr->tb = malloc(ctlr->ntd*sizeof(Block*)); if (ctlr->tb == nil) panic("igbeattach: no mem"); if(waserror()){ while(ctlr->nrb > 0){ bp = igberballoc(); if (bp == nil) panic("igbeattach: no mem for rcv bufs"); bp->free = nil; freeb(bp); ctlr->nrb--; } free(ctlr->tb); ctlr->tb = nil; free(ctlr->rb); ctlr->rb = nil; free(ctlr->alloc); ctlr->alloc = nil; qunlock(&ctlr->alock); nexterror(); } for(ctlr->nrb = 0; ctlr->nrb < Nrb; ctlr->nrb++){ if((bp = allocb(Rbsz)) == nil) break;#ifdef FS bp->flags |= Mbrcvbuf;#endif bp->free = igberbfree; freeb(bp); } snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno); kproc(name, igbelproc, edev); snprint(name, KNAMELEN, "#l%drproc", edev->ctlrno); kproc(name, igberproc, edev); igbetxinit(ctlr); qunlock(&ctlr->alock); poperror();}static voidigbeinterrupt(Ureg*, void* arg){ Ctlr *ctlr; Ether *edev; int icr, im, txdw; edev = arg; ctlr = edev->ctlr; ilock(&ctlr->imlock); csr32w(ctlr, Imc, ~0); im = ctlr->im; txdw = 0; while((icr = csr32r(ctlr, Icr) & ctlr->im) != 0){ if(icr & Lsc){ im &= ~Lsc; ctlr->lim = icr & Lsc; wakeup(&ctlr->lrendez); ctlr->lintr++; } if(icr & (Rxt0|Rxo|Rxdmt0|Rxseq)){ im &= ~(Rxt0|Rxo|Rxdmt0|Rxseq); ctlr->rim = icr & (Rxt0|Rxo|Rxdmt0|Rxseq); wakeup(&ctlr->rrendez); ctlr->rintr++; } if(icr & Txdw){ im &= ~Txdw; txdw++; ctlr->tintr++; } } ctlr->im = im; csr32w(ctlr, Ims, im); iunlock(&ctlr->imlock); if(txdw) igbetransmit(edev);}static inti82543mdior(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 inti82543mdiow(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 inti82543miimir(Mii* mii, int pa, int ra){ int data; Ctlr *ctlr; ctlr = mii->ctlr; /* * MII Management Interface Read. * * Preamble; * ST+OP+PHYAD+REGAD; * TA + 16 data bits. */ i82543mdiow(ctlr, 0xFFFFFFFF, 32); i82543mdiow(ctlr, 0x1800|(pa<<5)|ra, 14); data = i82543mdior(ctlr, 18); if(data & 0x10000) return -1; return data & 0xFFFF;}static inti82543miimiw(Mii* mii, int pa, int ra, int data){ Ctlr *ctlr; ctlr = mii->ctlr; /* * MII Management Interface Write. * * Preamble; * ST+OP+PHYAD+REGAD+TA + 16 data bits; * Z. */ i82543mdiow(ctlr, 0xFFFFFFFF, 32); data &= 0xFFFF; data |= (0x05<<(5+5+2+16))|(pa<<(5+2+16))|(ra<<(2+16))|(0x02<<16); i82543mdiow(ctlr, data, 32); return 0;}static intigbemiimir(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 intigbemiimiw(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 intigbemii(Ctlr* ctlr){ MiiPhy *phy; int ctrl, p, r; r = csr32r(ctlr, Status); if(r & Tbimode) return -1; if((ctlr->mii = malloc(sizeof(Mii))) == nil) return -1; ctlr->mii->ctlr = ctlr; ctrl = csr32r(ctlr, Ctrl); ctrl |= Slu; switch(ctlr->id){ case i82543gc: ctrl |= Frcdplx|Frcspd; csr32w(ctlr, Ctrl, ctrl); /* * The reset pin direction (Mdro) should already * be set from the EEPROM load. * If it's not set this configuration is unexpected * so bail. */ r = csr32r(ctlr, Ctrlext); if(!(r & Mdro)) return -1; csr32w(ctlr, Ctrlext, r); delay(20); r = csr32r(ctlr, Ctrlext); r &= ~Mdr; csr32w(ctlr, Ctrlext, r); delay(20); r = csr32r(ctlr, Ctrlext); r |= Mdr; csr32w(ctlr, Ctrlext, r); delay(20); ctlr->mii->mir = i82543miimir; ctlr->mii->miw = i82543miimiw; break; case i82544ei: case i82547ei: case i82540em: case i82540eplp: case i82547gi: case i82541gi: case i82541gi2: case i82541pi: case i82545gmc: case i82546gb: case i82546eb: ctrl &= ~(Frcdplx|Frcspd); csr32w(ctlr, Ctrl, ctrl); ctlr->mii->mir = igbemiimir; ctlr->mii->miw = igbemiimiw; break; default: free(ctlr->mii); ctlr->mii = nil; return -1; } if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){ free(ctlr->mii); ctlr->mii = nil; return -1; } USED(phy); // print("oui %X phyno %d\n", phy->oui, phy->phyno); /* * 8254X-specific PHY registers not in 802.3: * 0x10 PHY specific control * 0x14 extended PHY specific control * Set appropriate values then reset the PHY to have * changes noted. */ switch(ctlr->id){ case i82547gi: case i82541gi: case i82541gi2: case i82541pi: case i82545gmc: case i82546gb: case i82546eb: break; default: r = miimir(ctlr->mii, 16); r |= 0x0800; /* assert CRS on Tx */ r |= 0x0060; /* auto-crossover all speeds */ r |= 0x0002; /* polarity reversal enabled */ miimiw(ctlr->mii, 16, r); r = miimir(ctlr->mii, 20); r |= 0x0070; /* +25MHz clock */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -