📄 ether8169.c
字号:
static intrtl8169init(Ether* edev){ int i; u32int r; Block *bp; Ctlr *ctlr; u8int cplusc; ctlr = edev->ctlr; ilock(&ctlr->ilock); rtl8169halt(ctlr); /* * MAC Address. * Must put chip into config register write enable mode. */ csr8w(ctlr, Cr9346, Eem1|Eem0); 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); /* * Transmitter. */ memset(ctlr->td, 0, sizeof(D)*ctlr->ntd); ctlr->tdh = ctlr->tdt = 0; ctlr->td[ctlr->ntd-1].control = Eor; /* * Receiver. * Need to do something here about the multicast filter. */ memset(ctlr->rd, 0, sizeof(D)*ctlr->nrd); ctlr->nrdfree = ctlr->rdh = ctlr->rdt = 0; ctlr->rd[ctlr->nrd-1].control = Eor; for(i = 0; i < ctlr->nrd; i++){ if((bp = ctlr->rb[i]) != nil){ ctlr->rb[i] = nil; freeb(bp); } } rtl8169replenish(ctlr); ctlr->rcr = Rxfthnone|Mrxdmaunlimited|Ab|Apm; /* * Mtps is in units of 128 except for the RTL8169 * where is is 32. If using jumbo frames should be * set to 0x3F. * Setting Mulrw in Cplusc disables the Tx/Rx DMA burst * settings in Tcr/Rcr; the (1<<14) is magic. */ ctlr->mtps = HOWMANY(Mps, 128); cplusc = csr16r(ctlr, Cplusc) & ~(1<<14); cplusc |= /*Rxchksum|*/Mulrw; dprint("mac = %.2ux\n", ctlr->macv); switch(ctlr->macv){ default: print("bad mac %.2ux\n", ctlr->macv); return -1; case Macv01: ctlr->mtps = HOWMANY(Mps, 32); break; case Macv02: case Macv03: cplusc |= (1<<14); /* magic */ break; case Macv05: /* * This is interpreted from clearly bogus code * in the manufacturer-supplied driver, it could * be wrong. Untested. */ r = csr8r(ctlr, Config2) & 0x07; if(r == 0x01) /* 66MHz PCI */ csr32w(ctlr, 0x7C, 0x0007FFFF); /* magic */ else csr32w(ctlr, 0x7C, 0x0007FF00); /* magic */ pciclrmwi(ctlr->pcidev); break; case Macv13: /* * This is interpreted from clearly bogus code * in the manufacturer-supplied driver, it could * be wrong. Untested. */ pcicfgw8(ctlr->pcidev, 0x68, 0x00); /* magic */ pcicfgw8(ctlr->pcidev, 0x69, 0x08); /* magic */ break; case Macv04: case Macv11: case Macv12: case Macv14: case Macv15: break; } /* * Enable receiver/transmitter. * Need to do this first or some of the settings below * won't take. */ switch(ctlr->pciv){ default: csr8w(ctlr, Cr, Te|Re); csr32w(ctlr, Tcr, Ifg1|Ifg0|Mtxdmaunlimited); csr32w(ctlr, Rcr, ctlr->rcr); case Rtl8169sc: case Rtl8168b: break; } /* * Interrupts. * Disable Tdu|Tok for now, the transmit routine will tidy. * Tdu means the NIC ran out of descriptors to send, so it * doesn't really need to ever be on. */ csr32w(ctlr, Timerint, 0); ctlr->imr = Serr|Timeout|Fovw|Punlc|Rdu|Ter|Rer|Rok; csr16w(ctlr, Imr, ctlr->imr); /* * Clear missed-packet counter; * initial early transmit threshold value; * set the descriptor ring base addresses; * set the maximum receive packet size; * no early-receive interrupts. */ csr32w(ctlr, Mpc, 0); csr8w(ctlr, Mtps, ctlr->mtps); csr32w(ctlr, Tnpds+4, 0); csr32w(ctlr, Tnpds, PCIWADDR(ctlr->td)); csr32w(ctlr, Rdsar+4, 0); csr32w(ctlr, Rdsar, PCIWADDR(ctlr->rd)); csr16w(ctlr, Rms, Mps); r = csr16r(ctlr, Mulint) & 0xF000; csr16w(ctlr, Mulint, r); csr16w(ctlr, Cplusc, cplusc); /* * Set configuration. */ switch(ctlr->pciv){ default: break; case Rtl8169sc: csr16w(ctlr, 0xE2, 0); /* magic */ csr8w(ctlr, Cr, Te|Re); csr32w(ctlr, Tcr, Ifg1|Ifg0|Mtxdmaunlimited); csr32w(ctlr, Rcr, ctlr->rcr); break; case Rtl8168b: case Rtl8169c: csr16w(ctlr, 0xE2, 0); /* magic */ csr16w(ctlr, Cplusc, 0x2000); /* magic */ csr8w(ctlr, Cr, Te|Re); csr32w(ctlr, Tcr, Ifg1|Ifg0|Mtxdmaunlimited); csr32w(ctlr, Rcr, ctlr->rcr); csr16w(ctlr, Rms, 0x0800); csr8w(ctlr, Mtps, 0x3F); break; } ctlr->tcr = csr32r(ctlr, Tcr); csr8w(ctlr, Cr9346, 0); iunlock(&ctlr->ilock);// rtl8169mii(ctlr); return 0;}static voidrtl8169attach(Ether* edev){ int timeo; Ctlr *ctlr; ctlr = edev->ctlr; qlock(&ctlr->alock); if(ctlr->init == 0){ /* * Handle allocation/init errors here. */ ctlr->td = mallocalign(sizeof(D)*Ntd, 256, 0, 0); ctlr->tb = malloc(Ntd*sizeof(Block*)); ctlr->ntd = Ntd; ctlr->rd = mallocalign(sizeof(D)*Nrd, 256, 0, 0); ctlr->rb = malloc(Nrd*sizeof(Block*)); ctlr->nrd = Nrd; ctlr->dtcc = mallocalign(sizeof(Dtcc), 64, 0, 0); rtl8169init(edev); ctlr->init = 1; } qunlock(&ctlr->alock); /* * Wait for link to be ready. */ for(timeo = 0; timeo < 3500; timeo++){ if(miistatus(ctlr->mii) == 0) break; delay(10); }}static voidrtl8169link(Ether* edev){ uint r; Ctlr *ctlr; ctlr = edev->ctlr; /* * Maybe the link changed - do we care very much? * Could stall transmits if no link, maybe? */ if(!((r = csr8r(ctlr, Phystatus)) & Linksts)) return; if(r & Speed10) edev->mbps = 10; else if(r & Speed100) edev->mbps = 100; else if(r & Speed1000) edev->mbps = 1000;}static voidrtl8169transmit(Ether* edev){ D *d; Block *bp; Ctlr *ctlr; int control, x; ctlr = edev->ctlr; ilock(&ctlr->tlock); for(x = ctlr->tdh; ctlr->ntq > 0; x = NEXT(x, ctlr->ntd)){ d = &ctlr->td[x]; if((control = d->control) & Own) break; /* * Check errors and log here. */ USED(control); /* * Free it up. * Need to clean the descriptor here? Not really. * Simple freeb for now (no chain and freeblist). * Use ntq count for now. */ freeb(ctlr->tb[x]); ctlr->tb[x] = nil; d->control &= Eor; ctlr->ntq--; } ctlr->tdh = x; x = ctlr->tdt; while(ctlr->ntq < (ctlr->ntd-1)){ if((bp = etheroq(edev)) == nil) break; d = &ctlr->td[x]; d->addrlo = PCIWADDR(bp->rp); d->addrhi = 0; ctlr->tb[x] = bp; coherence(); d->control |= Own|Fs|Ls|((BLEN(bp)<<TxflSHIFT) & TxflMASK); x = NEXT(x, ctlr->ntd); ctlr->ntq++; } if(x != ctlr->tdt){ ctlr->tdt = x; csr8w(ctlr, Tppoll, Npq); } else if(ctlr->ntq >= (ctlr->ntd-1)) ctlr->txdu++; iunlock(&ctlr->tlock);}static voidrtl8169receive(Ether* edev){ D *d; int rdh; Block *bp; Ctlr *ctlr; u32int control; ctlr = edev->ctlr; rdh = ctlr->rdh; for(;;){ d = &ctlr->rd[rdh]; if(d->control & Own) break; control = d->control; if((control & (Fs|Ls|Res)) == (Fs|Ls)){ bp = ctlr->rb[rdh]; ctlr->rb[rdh] = nil; SETWPCNT(bp, ((control & RxflMASK)>>RxflSHIFT)-4); bp->next = nil;#ifndef FS if(control & Fovf) ctlr->fovf++;#endif switch(control & (Pid1|Pid0)){ default: break; case Pid0: if(control & Tcpf){ ctlr->tcpf++; break; }#ifndef FS bp->flag |= Btcpck;#endif break; case Pid1: if(control & Udpf){ ctlr->udpf++; break; }#ifndef FS bp->flag |= Budpck;#endif break; case Pid1|Pid0: if(control & Ipf){ ctlr->ipf++; break; }#ifndef FS bp->flag |= Bipck;#endif break; } ETHERIQ(edev, bp, 1); } else{ /* * Error stuff here. print("control %#8.8ux\n", control); */ } d->control &= Eor; ctlr->nrdfree--; rdh = NEXT(rdh, ctlr->nrd); if(ctlr->nrdfree < ctlr->nrd/2) rtl8169replenish(ctlr); } ctlr->rdh = rdh;}static voidrtl8169interrupt(Ureg*, void* arg){ Ctlr *ctlr; Ether *edev; u32int isr; edev = arg; ctlr = edev->ctlr; while((isr = csr16r(ctlr, Isr)) != 0 && isr != 0xFFFF){ csr16w(ctlr, Isr, isr); if((isr & ctlr->imr) == 0) break; if(isr & (Fovw|Punlc|Rdu|Rer|Rok)){ rtl8169receive(edev); if(!(isr & (Punlc|Rok))) ctlr->ierrs++; if(isr & Rer) ctlr->rer++; if(isr & Rdu) ctlr->rdu++; if(isr & Punlc) ctlr->punlc++; if(isr & Fovw) ctlr->fovw++; isr &= ~(Fovw|Rdu|Rer|Rok); } if(isr & (Tdu|Ter|Tok)){ rtl8169transmit(edev); isr &= ~(Tdu|Ter|Tok); } if(isr & Punlc){ rtl8169link(edev); isr &= ~Punlc; } /* * Some of the reserved bits get set sometimes... */ if(isr & (Serr|Timeout|Tdu|Fovw|Punlc|Rdu|Ter|Tok|Rer|Rok)) panic("rtl8169interrupt: imr %#4.4ux isr %#4.4ux\n", csr16r(ctlr, Imr), isr); }}static voidrtl8169pci(void){ Pcidev *p; Ctlr *ctlr; int i, port; 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; dprint(" pci: found vid %ux did %ux\n", p->vid, p->did); switch(i = ((p->did<<16)|p->vid)){ default: continue; case Rtl8100e: /* RTL810[01]E ? */ case Rtl8169c: /* RTL8169C */ case Rtl8169sc: /* RTL8169SC */ case Rtl8168b: /* RTL8168B */ case Rtl8169: /* RTL8169 */ break; case (0xC107<<16)|0x1259: /* Corega CG-LAPCIGT */ i = Rtl8169; break; } port = p->mem[0].bar & ~0x01; if(ioalloc(port, p->mem[0].size, 0, "rtl8169") < 0){ print("rtl8169: port %#ux in use\n", port); continue; } ctlr = malloc(sizeof(Ctlr)); ctlr->port = port; ctlr->pcidev = p; ctlr->pciv = i;#ifndef FS if(pcigetpms(p) > 0){ pcisetpms(p, 0); for(i = 0; i < 6; i++) pcicfgw32(p, PciBAR0+i*4, p->mem[i].bar); pcicfgw8(p, PciINTL, p->intl); pcicfgw8(p, PciLTR, p->ltr); pcicfgw8(p, PciCLS, p->cls); pcicfgw16(p, PciPCR, p->pcr); }#endif if(rtl8169reset(ctlr)){ iofree(port); free(ctlr); continue; } /* * Extract the chip hardware version, * needed to configure each properly. */ ctlr->macv = csr32r(ctlr, Tcr) & HwveridMASK; rtl8169mii(ctlr); pcisetbme(p); if(rtl8169ctlrhead != nil) rtl8169ctlrtail->next = ctlr; else rtl8169ctlrhead = ctlr; rtl8169ctlrtail = ctlr; }}intrtl8169pnp(Ether* edev){ u32int r; Ctlr *ctlr; uchar ea[Eaddrlen]; if(rtl8169ctlrhead == nil) rtl8169pci(); /* * Any adapter matches if no edev->port is supplied, * otherwise the ports must match. */ for(ctlr = rtl8169ctlrhead; 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; /* * 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){ r = csr32r(ctlr, Idr0); edev->ea[0] = r; edev->ea[1] = r>>8; edev->ea[2] = r>>16; edev->ea[3] = r>>24; r = csr32r(ctlr, Idr0+4); edev->ea[4] = r; edev->ea[5] = r>>8; } edev->attach = rtl8169attach; edev->transmit = rtl8169transmit; edev->interrupt = rtl8169interrupt;#ifndef FS edev->ifstat = rtl8169ifstat; edev->arg = edev; edev->promiscuous = rtl8169promiscuous;#endif rtl8169link(edev); return 0;}voidether8169link(void){ addethercard("rtl8169", rtl8169pnp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -