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

📄 ether8139.c

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