📄 ether8139.c
字号:
ctlr = edev->ctlr; qlock(&ctlr->alock); if(ctlr->alloc == nil){ ctlr->rblen = 1<<((Rblen>>RblenSHIFT)+13); ctlr->alloc = mallocz(ctlr->rblen+16 + Ntd*Tdbsz + 32, 0); rtl8139init(edev); } qunlock(&ctlr->alock);}static voidrtl8139txstart(Ether* edev){ Td *td; int size; Block *bp; Ctlr *ctlr; ctlr = edev->ctlr; while(ctlr->ntd < Ntd){ bp = etheroq(edev); if(bp == nil) break; size = BLEN(bp); td = &ctlr->td[ctlr->tdh]; if(((int)bp->rp) & 0x03){ memmove(td->data, bp->rp, size); freeb(bp); csr32w(ctlr, td->tsad, PCIWADDR(td->data)); ctlr->tunaligned++; } else{ td->bp = bp; csr32w(ctlr, td->tsad, PCIWADDR(bp->rp)); ctlr->taligned++; } csr32w(ctlr, td->tsd, (ctlr->etxth<<EtxthSHIFT)|size); ctlr->ntd++; ctlr->tdh = NEXT(ctlr->tdh, Ntd); }}static voidrtl8139transmit(Ether* edev){ Ctlr *ctlr; ctlr = edev->ctlr; ilock(&ctlr->tlock); rtl8139txstart(edev); iunlock(&ctlr->tlock);}static voidrtl8139receive(Ether* edev){ Block *bp; Ctlr *ctlr; ushort capr; uchar cr, *p; int l, length, status; ctlr = edev->ctlr; /* * Capr is where the host is reading from, * Cbr is where the NIC is currently writing. */ capr = (csr16r(ctlr, Capr)+16) % ctlr->rblen; while(!(csr8r(ctlr, Cr) & Bufe)){ p = ctlr->rbstart+capr; /* * Apparently the packet length may be 0xFFF0 if * the NIC is still copying the packet into memory. */ length = (*(p+3)<<8)|*(p+2); if(length == 0xFFF0) break; status = (*(p+1)<<8)|*p; if(!(status & Rcok)){#ifndef FS if(status & (Ise|Fae)) edev->frames++; if(status & Crc) edev->crcs++; if(status & (Runt|Long)) edev->buffs++;#endif /* * Reset the receiver. * Also may have to restore the multicast list * here too if it ever gets used. */ cr = csr8r(ctlr, Cr); csr8w(ctlr, Cr, cr & ~Re); csr32w(ctlr, Rbstart, PCIWADDR(ctlr->rbstart)); csr8w(ctlr, Cr, cr); csr32w(ctlr, Rcr, ctlr->rcr); continue; } /* * Receive Completed OK. * Very simplistic; there are ways this could be done * without copying, but the juice probably isn't worth * the squeeze. * The packet length includes a 4 byte CRC on the end. */ capr = (capr+4) % ctlr->rblen; p = ctlr->rbstart+capr; capr = (capr+length) % ctlr->rblen; if((bp = iallocb(length)) != nil){ SETWPCNT(bp, 0); if(p+length >= ctlr->rbstart+ctlr->rblen){ l = ctlr->rbstart+ctlr->rblen - p; memmove(ENDDATA(bp), p, l); INCRPTR(bp, l); length -= l; p = ctlr->rbstart; } if(length > 0){ memmove(ENDDATA(bp), p, length); INCRPTR(bp, length); } INCRPTR(bp, -4); if (BLEN(bp) < 0) { print("rtl8139receive: input packet of negative length\n"); SETWPCNT(bp, 0); freeb(bp); } else ETHERIQ(edev, bp, 1); } capr = ROUNDUP(capr, 4); csr16w(ctlr, Capr, capr-16); }}static voidrtl8139interrupt(Ureg*, void* arg){ Td *td; Ctlr *ctlr; Ether *edev; int isr, msr, tsd; edev = arg; ctlr = edev->ctlr; while((isr = csr16r(ctlr, Isr)) != 0){ csr16w(ctlr, Isr, isr); if(isr & (Fovw|PunLc|Rxovw|Rer|Rok)){ rtl8139receive(edev); if(!(isr & Rok)) ctlr->ierrs++; isr &= ~(Fovw|Rxovw|Rer|Rok); } if(isr & (Ter|Tok)){ ilock(&ctlr->tlock); while(ctlr->ntd){ td = &ctlr->td[ctlr->tdi]; tsd = csr32r(ctlr, td->tsd); if(!(tsd & (Tabt|Tun|Tcok))) break; if(!(tsd & Tcok)){ if(tsd & Tun){ if(ctlr->etxth < ETHERMAXTU/32) ctlr->etxth++; }#ifndef FS edev->oerrs++;#endif } if(td->bp != nil){ freeb(td->bp); td->bp = nil; } ctlr->ntd--; ctlr->tdi = NEXT(ctlr->tdi, Ntd); } rtl8139txstart(edev); iunlock(&ctlr->tlock); isr &= ~(Ter|Tok); } if(isr & PunLc){ /* * Maybe the link changed - do we care very much? */ msr = csr8r(ctlr, Msr); if(!(msr & Linkb)){ if(!(msr & Speed10) && edev->mbps != 100){ edev->mbps = 100; qsetlimit(edev->oq, 256*1024); } else if((msr & Speed10) && edev->mbps != 10){ edev->mbps = 10; qsetlimit(edev->oq, 65*1024); } } isr &= ~(Clc|PunLc); } /* * Only Serr|Timerbit should be left by now. * Should anything be done to tidy up? TimerInt isn't * used so that can be cleared. A PCI bus error is indicated * by Serr, that's pretty serious; is there anyhing to do * other than try to reinitialise the chip? */ if(isr != 0){ iprint("rtl8139interrupt: imr %4.4ux isr %4.4ux\n", csr16r(ctlr, Imr), isr); if(isr & Timerbit) csr32w(ctlr, TimerInt, 0); if(isr & Serr) rtl8139init(edev); } }}static Ctlr*rtl8139match(Ether* edev, int id){ int port; Pcidev *p; Ctlr *ctlr; /* * Any adapter matches if no edev->port is supplied, * otherwise the ports must match. */ for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){ if(ctlr->active) continue; p = ctlr->pcidev; if(((p->did<<16)|p->vid) != id) continue; port = p->mem[0].bar & ~0x01; if(edev->port != 0 && edev->port != port) continue; if(ioalloc(port, p->mem[0].size, 0, "rtl8139") < 0){ print("rtl8139: port 0x%ux in use\n", port); continue; } ctlr->port = port; if(rtl8139reset(ctlr)) continue; pcisetbme(p); ctlr->active = 1; return ctlr; } return nil;}static struct { char* name; int id;} rtl8139pci[] = { { "rtl8139", (0x8139<<16)|0x10EC, }, /* generic */ { "smc1211", (0x1211<<16)|0x1113, }, /* SMC EZ-Card */ { "dfe-538tx", (0x1300<<16)|0x1186, }, /* D-Link DFE-538TX */ { "dfe-560txd", (0x1340<<16)|0x1186, }, /* D-Link DFE-560TXD */ { nil },};intrtl8139pnp(Ether* edev){ int i, id; Pcidev *p; Ctlr *ctlr; uchar ea[Eaddrlen]; /* * Make a list of all ethernet controllers * if not already done. */ if(ctlrhead == nil){ p = nil; while(p = pcimatch(p, 0, 0)){#ifdef FS if(p->ccru != ((0x02<<8)|0x00))#else if(p->ccrb != 0x02 || p->ccru != 0)#endif continue; ctlr = malloc(sizeof(Ctlr)); ctlr->pcidev = p; ctlr->id = (p->did<<16)|p->vid; if(ctlrhead != nil) ctlrtail->next = ctlr; else ctlrhead = ctlr; ctlrtail = ctlr; } } /* * Is it an RTL8139 under a different name? * Normally a search is made through all the found controllers * for one which matches any of the known vid+did pairs. * If a vid+did pair is specified a search is made for that * specific controller only. */ id = 0; for(i = 0; i < edev->nopt; i++){ if(cistrncmp(edev->opt[i], "id=", 3) == 0) id = strtol(&edev->opt[i][3], nil, 0); } ctlr = nil; if(id != 0) ctlr = rtl8139match(edev, id); else for(i = 0; rtl8139pci[i].name; i++){ if((ctlr = rtl8139match(edev, rtl8139pci[i].id)) != nil) break; } if(ctlr == nil) return -1; edev->ctlr = ctlr; edev->port = ctlr->port; edev->irq = ctlr->pcidev->intl; edev->tbdf = ctlr->pcidev->tbdf; /* * Check if the adapter's station address is to be overridden. * If not, read it from the device and set in edev->ea. */ memset(ea, 0, Eaddrlen); if(memcmp(ea, edev->ea, Eaddrlen) == 0){ i = csr32r(ctlr, Idr0); edev->ea[0] = i; edev->ea[1] = i>>8; edev->ea[2] = i>>16; edev->ea[3] = i>>24; i = csr32r(ctlr, Idr0+4); edev->ea[4] = i; edev->ea[5] = i>>8; } edev->attach = rtl8139attach; edev->transmit = rtl8139transmit; edev->interrupt = rtl8139interrupt;#ifndef FS edev->ifstat = rtl8139ifstat; edev->arg = edev; edev->promiscuous = rtl8139promiscuous;#endif /* * This should be much more dynamic but will do for now. */ if((csr8r(ctlr, Msr) & (Speed10|Linkb)) == 0) edev->mbps = 100; return 0;}voidether8139link(void){ addethercard("rtl8139", rtl8139pnp);}voidether8139bothlink(void){ ether8139link();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -