📄 ethervt6102.c
字号:
ds = (Ds*)alloc; alloc += ctlr->cls; ds->control = Rdbsz; ds->branch = PCIWADDR(alloc); ds->bp = iallocb(Rdbsz+3); if(ds->bp == nil) error("vt6102: can't allocate receive ring\n"); ds->bp->rp = (uchar*)ROUNDUP((ulong)ds->bp->rp, 4); ds->addr = PCIWADDR(ds->bp->rp); ds->next = (Ds*)alloc; ds->prev = prev; prev = ds; ds->status = Own; } prev->branch = 0; prev->next = ctlr->rd; prev->status = 0; ctlr->rdh = ctlr->rd; ctlr->td = (Ds*)alloc; prev = ctlr->td + ctlr->ntd-1; bounce = alloc + ctlr->ntd*ctlr->cls; for(i = 0; i < ctlr->ntd; i++){ ds = (Ds*)alloc; alloc += ctlr->cls; ds->bounce = bounce; bounce += Txcopy; ds->next = (Ds*)alloc; ds->prev = prev; prev = ds; } prev->next = ctlr->td; ctlr->tdh = ctlr->tdt = ctlr->td; ctlr->tdused = 0; ctlr->cr = Dpoll|Rdmd|Txon|Rxon|Strt; /*Srci|Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx*/ ctlr->imr = Abti|Norbf|Pktrace|Ovfi|Udfi|Be|Ru|Tu|Txe|Rxe|Ptx|Prx; ilock(&ctlr->clock); csr32w(ctlr, Rxdaddr, PCIWADDR(ctlr->rd)); csr32w(ctlr, Txdaddr, PCIWADDR(ctlr->td)); csr16w(ctlr, Isr, ~0); csr16w(ctlr, Imr, ctlr->imr); csr16w(ctlr, Cr, ctlr->cr); iunlock(&ctlr->clock); snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno); kproc(name, vt6102lproc, edev); qunlock(&ctlr->alock); poperror();}static voidvt6102transmit(Ether* edev){ Block *bp; Ctlr *ctlr; Ds *ds, *next; int control, i, o, prefix, size, tdused, timeo; ctlr = edev->ctlr; ilock(&ctlr->tlock); /* * Free any completed packets */ ds = ctlr->tdh; for(tdused = ctlr->tdused; tdused > 0; tdused--){ /* * For some errors the chip will turn the Tx engine * off. Wait for that to happen. * Could reset and re-init the chip here if it doesn't * play fair. * To do: adjust Tx FIFO threshold on underflow. */ if(ds->status & (Abt|Tbuff|Udf)){ for(timeo = 0; timeo < 1000; timeo++){ if(!(csr16r(ctlr, Cr) & Txon)) break; microdelay(1); } ds->status = Own; csr32w(ctlr, Txdaddr, PCIWADDR(ds)); } if(ds->status & Own) break; ds->addr = 0; ds->branch = 0; if(ds->bp != nil){ freeb(ds->bp); ds->bp = nil; } for(i = 0; i < Ntxstats-1; i++){ if(ds->status & (1<<i)) ctlr->txstats[i]++; } ctlr->txstats[i] += (ds->status & NcrMASK)>>NcrSHIFT; ds = ds->next; } ctlr->tdh = ds; /* * Try to fill the ring back up. */ ds = ctlr->tdt; while(tdused < ctlr->ntd-2){ if((bp = qget(edev->oq)) == nil) break; tdused++; size = BLEN(bp); prefix = 0; if(o = (((int)bp->rp) & 0x03)){ prefix = Txcopy-o; if(prefix > size) prefix = size; memmove(ds->bounce, bp->rp, prefix); ds->addr = PCIWADDR(ds->bounce); bp->rp += prefix; size -= prefix; } next = ds->next; ds->branch = PCIWADDR(ds->next); if(size){ if(prefix){ next->bp = bp; next->addr = PCIWADDR(bp->rp); next->branch = PCIWADDR(next->next); next->control = Edp|Chain|((size<<TbsSHIFT) & TbsMASK); control = Stp|Chain|((prefix<<TbsSHIFT) & TbsMASK); next = next->next; tdused++; ctlr->tsplit++; } else{ ds->bp = bp; ds->addr = PCIWADDR(bp->rp); control = Edp|Stp|((size<<TbsSHIFT) & TbsMASK); ctlr->taligned++; } } else{ freeb(bp); control = Edp|Stp|((prefix<<TbsSHIFT) & TbsMASK); ctlr->tcopied++; } ds->control = control; if(tdused >= ctlr->ntd-2){ ds->control |= Ic; ctlr->txdw++; } coherence(); ds->status = Own; ds = next; } ctlr->tdt = ds; ctlr->tdused = tdused; if(ctlr->tdused) csr16w(ctlr, Cr, Tdmd|ctlr->cr); iunlock(&ctlr->tlock);}static voidvt6102receive(Ether* edev){ Ds *ds; Block *bp; Ctlr *ctlr; int i, len; ctlr = edev->ctlr; ds = ctlr->rdh; while(!(ds->status & Own) && ds->status != 0){ if(ds->status & Rerr){ for(i = 0; i < Nrxstats; i++){ if(ds->status & (1<<i)) ctlr->rxstats[i]++; } } else if(bp = iallocb(Rdbsz+3)){ len = ((ds->status & LengthMASK)>>LengthSHIFT)-4; ds->bp->wp = ds->bp->rp+len; etheriq(edev, ds->bp, 1); bp->rp = (uchar*)ROUNDUP((ulong)bp->rp, 4); ds->addr = PCIWADDR(bp->rp); ds->bp = bp; } ds->control = Rdbsz; ds->branch = 0; ds->status = 0; ds->prev->branch = PCIWADDR(ds); coherence(); ds->prev->status = Own; ds = ds->next; } ctlr->rdh = ds; csr16w(ctlr, Cr, ctlr->cr);}static voidvt6102interrupt(Ureg*, void* arg){ Ctlr *ctlr; Ether *edev; int imr, isr, r, timeo; edev = arg; ctlr = edev->ctlr; ilock(&ctlr->clock); csr16w(ctlr, Imr, 0); imr = ctlr->imr; ctlr->intr++; for(;;){ if((isr = csr16r(ctlr, Isr)) != 0) csr16w(ctlr, Isr, isr); if((isr & ctlr->imr) == 0) break; if(isr & Srci){ imr &= ~Srci; ctlr->lwakeup = isr & Srci; wakeup(&ctlr->lrendez); isr &= ~Srci; ctlr->lintr++; } if(isr & (Norbf|Pktrace|Ovfi|Ru|Rxe|Prx)){ vt6102receive(edev); isr &= ~(Norbf|Pktrace|Ovfi|Ru|Rxe|Prx); ctlr->rintr++; } if(isr & (Abti|Udfi|Tu|Txe|Ptx)){ if(isr & (Abti|Udfi|Tu)){ for(timeo = 0; timeo < 1000; timeo++){ if(!(csr16r(ctlr, Cr) & Txon)) break; microdelay(1); } if((isr & Udfi) && ctlr->tft < CtftSAF){ ctlr->tft += 1<<CtftSHIFT; r = csr8r(ctlr, Bcr1) & ~CtftMASK; csr8w(ctlr, Bcr1, r|ctlr->tft); } } vt6102transmit(edev); isr &= ~(Abti|Udfi|Tu|Txe|Ptx); ctlr->tintr++; } if(isr) panic("vt6102: isr %4.4uX\n", isr); } ctlr->imr = imr; csr16w(ctlr, Imr, ctlr->imr); iunlock(&ctlr->clock);}static intvt6102miimicmd(Mii* mii, int pa, int ra, int cmd, int data){ Ctlr *ctlr; int r, timeo; ctlr = mii->ctlr; csr8w(ctlr, Miicr, 0); r = csr8r(ctlr, Phyadr); csr8w(ctlr, Phyadr, (r & ~PhyadMASK)|pa); csr8w(ctlr, Phyadr, pa); csr8w(ctlr, Miiadr, ra); if(cmd == Wcmd) csr16w(ctlr, Miidata, data); csr8w(ctlr, Miicr, cmd); for(timeo = 0; timeo < 10000; timeo++){ if(!(csr8r(ctlr, Miicr) & cmd)) break; microdelay(1); } if(timeo >= 10000) return -1; if(cmd == Wcmd) return 0; return csr16r(ctlr, Miidata);}static intvt6102miimir(Mii* mii, int pa, int ra){ return vt6102miimicmd(mii, pa, ra, Rcmd, 0);}static intvt6102miimiw(Mii* mii, int pa, int ra, int data){ return vt6102miimicmd(mii, pa, ra, Wcmd, data);}static intvt6102detach(Ctlr* ctlr){ int timeo; /* * Soft reset the controller. */ csr16w(ctlr, Cr, Sfrst); for(timeo = 0; timeo < 10000; timeo++){ if(!(csr16r(ctlr, Cr) & Sfrst)) break; microdelay(1); } if(timeo >= 1000) return -1; return 0;}static intvt6102reset(Ctlr* ctlr){ MiiPhy *phy; int i, r, timeo; if(vt6102detach(ctlr) < 0) return -1; /* * Load the MAC address into the PAR[01] * registers. */ r = csr8r(ctlr, Eecsr); csr8w(ctlr, Eecsr, Autold|r); for(timeo = 0; timeo < 100; timeo++){ if(!(csr8r(ctlr, Cr) & Autold)) break; microdelay(1); } if(timeo >= 100) return -1; for(i = 0; i < Eaddrlen; i++) ctlr->par[i] = csr8r(ctlr, Par0+i); /* * Configure DMA and Rx/Tx thresholds. * If the Rx/Tx threshold bits in Bcr[01] are 0 then * the thresholds are determined by Rcr/Tcr. */ r = csr8r(ctlr, Bcr0) & ~(CrftMASK|DmaMASK); csr8w(ctlr, Bcr0, r|Crft64|Dma64); r = csr8r(ctlr, Bcr1) & ~CtftMASK; csr8w(ctlr, Bcr1, r|ctlr->tft); r = csr8r(ctlr, Rcr) & ~(RrftMASK|Prom|Ar|Sep); csr8w(ctlr, Rcr, r|Ab|Am); r = csr8r(ctlr, Tcr) & ~(RtsfMASK|Ofset|Lb1|Lb0); csr8w(ctlr, Tcr, r); /* * Link management. */ if((ctlr->mii = malloc(sizeof(Mii))) == nil) return -1; ctlr->mii->mir = vt6102miimir; ctlr->mii->miw = vt6102miimiw; ctlr->mii->ctlr = ctlr; if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){ free(ctlr->mii); ctlr->mii = nil; return -1; } // print("oui %X phyno %d\n", phy->oui, phy->phyno); USED(phy); //miiane(ctlr->mii, ~0, ~0, ~0); return 0;}static voidvt6102pci(void){ Pcidev *p; Ctlr *ctlr; int cls, port; p = nil; while(p = pcimatch(p, 0, 0)){ if(p->ccrb != 0x02 || p->ccru != 0) continue; switch((p->did<<16)|p->vid){ default: continue; case (0x3065<<16)|0x1106: /* Rhine II */ case (0x3106<<16)|0x1106: /* Rhine III */ break; } port = p->mem[0].bar & ~0x01; if(ioalloc(port, p->mem[0].size, 0, "vt6102") < 0){ print("vt6102: port 0x%uX in use\n", port); continue; } ctlr = malloc(sizeof(Ctlr)); ctlr->port = port; ctlr->pcidev = p; ctlr->id = (p->did<<16)|p->vid; if((cls = pcicfgr8(p, PciCLS)) == 0 || cls == 0xFF) cls = 0x10; ctlr->cls = cls*4; if(ctlr->cls < sizeof(Ds)){ print("vt6102: cls %d < sizeof(Ds)\n", ctlr->cls); free(ctlr); continue; } ctlr->tft = Ctft64; if(vt6102reset(ctlr)){ free(ctlr); continue; } pcisetbme(p); if(vt6102ctlrhead != nil) vt6102ctlrtail->next = ctlr; else vt6102ctlrhead = ctlr; vt6102ctlrtail = ctlr; }}static intvt6102pnp(Ether* edev){ Ctlr *ctlr; if(vt6102ctlrhead == nil) vt6102pci(); /* * Any adapter matches if no edev->port is supplied, * otherwise the ports must match. */ for(ctlr = vt6102ctlrhead; ctlr != nil; ctlr = ctlr->next){ if(ctlr->active) continue; if(edev->port == 0 || edev->port == ctlr->port){ ctlr->active = 1; break; } } if(ctlr == nil) return -1; edev->ctlr = ctlr; edev->port = ctlr->port; edev->irq = ctlr->pcidev->intl; edev->tbdf = ctlr->pcidev->tbdf; edev->mbps = 100; memmove(edev->ea, ctlr->par, Eaddrlen); /* * Linkage to the generic ethernet driver. */ edev->attach = vt6102attach; edev->transmit = vt6102transmit; edev->interrupt = vt6102interrupt; edev->ifstat = vt6102ifstat; edev->ctl = nil; edev->arg = edev; edev->promiscuous = vt6102promiscuous; edev->multicast = vt6102multicast; return 0;}voidethervt6102link(void){ addethercard("vt6102", vt6102pnp); addethercard("rhine", vt6102pnp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -