⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ether8169.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
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 + -