📄 etherigbe.c
字号:
enum { CMrdtr,};static Cmdtab igbectlmsg[] = { CMrdtr, "rdtr", 2,};static longigbectl(Ether* edev, void* buf, long n){ int v; char *p; Ctlr *ctlr; Cmdbuf *cb; Cmdtab *ct; if((ctlr = edev->ctlr) == nil) error(Enonexist); cb = parsecmd(buf, n); if(waserror()){ free(cb); nexterror(); } ct = lookupcmd(cb, igbectlmsg, nelem(igbectlmsg)); switch(ct->index){ case CMrdtr: v = strtol(cb->f[1], &p, 0); if(v < 0 || p == cb->f[1] || v > 0xFFFF) error(Ebadarg); ctlr->rdtr = v;; csr32w(ctlr, Rdtr, Fpd|v); break; } free(cb); poperror(); return n;}static voidigbepromiscuous(void* arg, int on){ int rctl; Ctlr *ctlr; Ether *edev; edev = arg; ctlr = edev->ctlr; rctl = csr32r(ctlr, Rctl); rctl &= ~MoMASK; rctl |= Mo47b36; if(on) rctl |= Upe|Mpe; else rctl &= ~(Upe|Mpe); csr32w(ctlr, Rctl, rctl);}static voidigbemulticast(void* arg, uchar* addr, int on){ int bit, x; Ctlr *ctlr; Ether *edev; edev = arg; ctlr = edev->ctlr; x = addr[5]>>1; bit = ((addr[5] & 1)<<4)|(addr[4]>>4); if(on) ctlr->mta[x] |= 1<<bit; else ctlr->mta[x] &= ~(1<<bit); csr32w(ctlr, Mta+x*4, ctlr->mta[x]);}static Block*igberballoc(void){ Block *bp; ilock(&igberblock); if((bp = igberbpool) != nil){ igberbpool = bp->next; bp->next = nil; } iunlock(&igberblock); return bp;}static voidigberbfree(Block* bp){ bp->rp = bp->lim - Rbsz; bp->wp = bp->rp; ilock(&igberblock); bp->next = igberbpool; igberbpool = bp; iunlock(&igberblock);}static voidigbeim(Ctlr* ctlr, int im){ ilock(&ctlr->imlock); ctlr->im |= im; csr32w(ctlr, Ims, ctlr->im); iunlock(&ctlr->imlock);}static intigbelim(void* ctlr){ return ((Ctlr*)ctlr)->lim != 0;}static voidigbelproc(void* arg){ Ctlr *ctlr; Ether *edev; MiiPhy *phy; int ctrl, r; edev = arg; ctlr = edev->ctlr; for(;;){ if(ctlr->mii == nil || ctlr->mii->curphy == nil) continue; /* * To do: * logic to manage status change, * this is incomplete but should work * one time to set up the hardware. * * MiiPhy.speed, etc. should be in Mii. */ if(miistatus(ctlr->mii) < 0) //continue; goto enable; phy = ctlr->mii->curphy; ctrl = csr32r(ctlr, Ctrl); switch(ctlr->id){ case i82543gc: case i82544ei: default: if(!(ctrl & Asde)){ ctrl &= ~(SspeedMASK|Ilos|Fd); ctrl |= Frcdplx|Frcspd; if(phy->speed == 1000) ctrl |= Sspeed1000; else if(phy->speed == 100) ctrl |= Sspeed100; if(phy->fd) ctrl |= Fd; } break; case i82540em: case i82540eplp: case i82547gi: case i82541gi: case i82541gi2: case i82541pi: break; } /* * Collision Distance. */ r = csr32r(ctlr, Tctl); r &= ~ColdMASK; if(phy->fd) r |= 64<<ColdSHIFT; else r |= 512<<ColdSHIFT; csr32w(ctlr, Tctl, r); /* * Flow control. */ if(phy->rfc) ctrl |= Rfce; if(phy->tfc) ctrl |= Tfce; csr32w(ctlr, Ctrl, ctrl);enable: ctlr->lim = 0; igbeim(ctlr, Lsc); ctlr->lsleep++; sleep(&ctlr->lrendez, igbelim, ctlr); }}static voidigbetxinit(Ctlr* ctlr){ int i, r; Block *bp; csr32w(ctlr, Tctl, (0x0F<<CtSHIFT)|Psp|(66<<ColdSHIFT)); switch(ctlr->id){ default: r = 6; break; case i82543gc: case i82544ei: case i82547ei: case i82540em: case i82540eplp: case i82541gi: case i82541gi2: case i82541pi: case i82545gmc: 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, Tdbal, PCIWADDR(ctlr->tdba)); csr32w(ctlr, Tdbah, 0); csr32w(ctlr, Tdlen, ctlr->ntd*sizeof(Td)); ctlr->tdh = PREV(0, ctlr->ntd); csr32w(ctlr, Tdh, 0); ctlr->tdt = 0; csr32w(ctlr, Tdt, 0); for(i = 0; i < ctlr->ntd; i++){ if((bp = ctlr->tb[i]) != nil){ ctlr->tb[i] = nil; freeb(bp); } memset(&ctlr->tdba[i], 0, sizeof(Td)); } ctlr->tdfree = ctlr->ntd; csr32w(ctlr, Tidv, 128); r = (4<<WthreshSHIFT)|(4<<HthreshSHIFT)|(8<<PthreshSHIFT); switch(ctlr->id){ default: break; case i82540em: case i82540eplp: case i82547gi: case i82545gmc: case i82546gb: case i82546eb: case i82541gi: case i82541gi2: case i82541pi: 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);}static voidigbetransmit(Ether* edev){ Td *td; Block *bp; Ctlr *ctlr; int tdh, tdt; ctlr = edev->ctlr; ilock(&ctlr->tlock); /* * Free any completed packets */ tdh = ctlr->tdh; while(NEXT(tdh, ctlr->ntd) != csr32r(ctlr, Tdh)){ if((bp = ctlr->tb[tdh]) != nil){ ctlr->tb[tdh] = nil; freeb(bp); } memset(&ctlr->tdba[tdh], 0, sizeof(Td)); tdh = NEXT(tdh, ctlr->ntd); } ctlr->tdh = tdh; /* * Try to fill the ring back up. */ tdt = ctlr->tdt; while(NEXT(tdt, ctlr->ntd) != tdh){ if((bp = qget(edev->oq)) == nil) break; td = &ctlr->tdba[tdt]; td->addr[0] = PCIWADDR(bp->rp); td->control = ((BLEN(bp) & LenMASK)<<LenSHIFT); td->control |= Dext|Ifcs|Teop|DtypeDD; ctlr->tb[tdt] = bp; tdt = NEXT(tdt, ctlr->ntd); if(NEXT(tdt, ctlr->ntd) == tdh){ td->control |= Rs; ctlr->txdw++; ctlr->tdt = tdt; csr32w(ctlr, Tdt, tdt); igbeim(ctlr, Txdw); break; } ctlr->tdt = tdt; csr32w(ctlr, Tdt, tdt); } iunlock(&ctlr->tlock);}static voidigbereplenish(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("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(void* arg){ Rd *rd; Block *bp; Ctlr *ctlr; int r, rdh; Ether *edev; edev = 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; bp->wp += 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++; bp->flag |= Bipck; } if(rd->status & Tcpcs){ /* * TCP/UDP checksum calculated * (and valid as errors == 0). */ ctlr->tcpcs++; bp->flag |= Btcpck|Budpck; } bp->checksum = rd->checksum; bp->flag |= Bpktck; } 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(waserror()){ while(ctlr->nrb > 0){ bp = igberballoc(); 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; 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -