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

📄 etherigbe.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
			len = BLEN(bp);			print("txstart: extended short pkt %d -> %d bytes\n",				olen, len);		}		/* set up a descriptor for it */		tdesc = &ctlr->tdba[tdt];		tdesc->addr[0] = PCIWADDR(bp->rp);		tdesc->addr[1] = 0;		tdesc->control = /* Ide| */ Rs|Dext|Ifcs|Teop|DtypeDD|len;		tdesc->status = 0;		ctlr->tb[tdt] = bp;	}	ctlr->tdt = tdt;	csr32w(ctlr, Tdt, tdt);	igbeim(ctlr, Txdw);}static Block *fromringbuf(Ether *ether){	RingBuf *tb = &ether->tb[ether->ti];	Block *bp = allocb(tb->len);	memmove(bp->wp, tb->pkt, tb->len);	memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen);	bp->wp += tb->len;	return bp;}static voidigbetransmit(Ether* edev){	Block *bp;	Ctlr *ctlr;	Tdesc *tdesc;	RingBuf *tb;	int tdh;	/*	 * For now there are no smarts here. Tuning comes later.	 */	ctlr = edev->ctlr;	ilock(&ctlr->tdlock);	/*	 * Free any completed packets	 * - try to get the soft tdh to catch the tdt;	 * - if the packet had an underrun bump the threshold	 *   - the Tu bit doesn't seem to ever be set, perhaps	 *     because Rs mode is used?	 */	tdh = ctlr->tdh;	for(;;){		tdesc = &ctlr->tdba[tdh];		if(!(tdesc->status & Tdd))			break;		if(tdesc->status & Tu){			ctlr->ett++;			csr32w(ctlr, Ett, ctlr->ett);		}		tdesc->status = 0;		if(ctlr->tb[tdh] != nil){			freeb(ctlr->tb[tdh]);			ctlr->tb[tdh] = nil;		}		tdh = NEXT(tdh, Ntdesc);	}	ctlr->tdh = tdh;	/* copy packets from the software RingBuf to the transmission q */	/* from boot ether83815.c */	while((tb = &edev->tb[edev->ti])->owner == Interface){		bp = fromringbuf(edev);		/* put the buffer on the transmit queue */		if(ctlr->bqhead)			ctlr->bqtail->next = bp;		else			ctlr->bqhead = bp;		ctlr->bqtail = bp;		txstart(edev);		/* kick transmitter */		tb->owner = Host;	/* give descriptor back */		edev->ti = NEXT(edev->ti, edev->ntb);	}	iunlock(&ctlr->tdlock);}static voidigbereplenish(Ctlr* ctlr){	int rdt;	Block *bp;	Rdesc *rdesc;	rdt = ctlr->rdt;	while(NEXT(rdt, Nrdesc) != ctlr->rdh){		rdesc = &ctlr->rdba[rdt];		if(ctlr->rb[rdt] != nil){			/* nothing to do */		}		else if((bp = iallocb(2048)) != nil){			ctlr->rb[rdt] = bp;			rdesc->addr[0] = PCIWADDR(bp->rp);			rdesc->addr[1] = 0;		}		else			break;		rdesc->status = 0;		rdt = NEXT(rdt, Nrdesc);	}	ctlr->rdt = rdt;	csr32w(ctlr, Rdt, rdt);}static voidtoringbuf(Ether *ether, Block *bp){	RingBuf *rb = &ether->rb[ether->ri];	if (rb->owner == Interface) {		rb->len = BLEN(bp);		memmove(rb->pkt, bp->rp, rb->len);		rb->owner = Host;		ether->ri = NEXT(ether->ri, ether->nrb);	}	/* else no one is expecting packets from the network */}static voidigbeinterrupt(Ureg*, void* arg){	Block *bp;	Ctlr *ctlr;	Ether *edev;	Rdesc *rdesc;	int icr, im, rdh, txdw = 0;	edev = arg;	ctlr = edev->ctlr;	ilock(&ctlr->imlock);	csr32w(ctlr, Imc, ~0);	im = ctlr->im;	for(icr = csr32r(ctlr, Icr); icr & ctlr->im; icr = csr32r(ctlr, Icr)){		/*		 * Link status changed.		 */		if(icr & (Rxseq|Lsc)){			/*			 * More here...			 */		}		/*		 * Process any received packets.		 */		rdh = ctlr->rdh;		for(;;){			rdesc = &ctlr->rdba[rdh];			if(!(rdesc->status & Rdd))				break;			if ((rdesc->status & Reop) && rdesc->errors == 0) {				bp = ctlr->rb[rdh];				ctlr->rb[rdh] = nil;				/*				 * it appears that the original 82543 needed				 * to have the Ethernet CRC excluded, but that				 * the newer chips do not?				 */				bp->wp += rdesc->length /* -4 */;				toringbuf(edev, bp);				freeb(bp);			} else if ((rdesc->status & Reop) && rdesc->errors)				print("igbe: input packet error 0x%ux\n",					rdesc->errors);			rdesc->status = 0;			rdh = NEXT(rdh, Nrdesc);		}		ctlr->rdh = rdh;		if(icr & Rxdmt0)			igbereplenish(ctlr);		if(icr & Txdw){			im &= ~Txdw;			txdw++;		}	}	ctlr->im = im;	csr32w(ctlr, Ims, im);	iunlock(&ctlr->imlock);	if(txdw)		igbetransmit(edev);}static intigbeinit(Ether* edev){	int csr, i, r, ctrl;	MiiPhy *phy;	Ctlr *ctlr;	ctlr = edev->ctlr;	/*	 * Set up the receive addresses.	 * There are 16 addresses. The first should be the MAC address.	 * The others are cleared and not marked valid (MS bit of Rah).	 */	csr = (edev->ea[3]<<24)|(edev->ea[2]<<16)|(edev->ea[1]<<8)|edev->ea[0];	csr32w(ctlr, Ral, csr);	csr = 0x80000000|(edev->ea[5]<<8)|edev->ea[4];	csr32w(ctlr, Rah, csr);	for(i = 1; i < 16; i++){		csr32w(ctlr, Ral+i*8, 0);		csr32w(ctlr, Rah+i*8, 0);	}	/*	 * Clear the Multicast Table Array.	 * It's a 4096 bit vector accessed as 128 32-bit registers.	 */	for(i = 0; i < 128; i++)		csr32w(ctlr, Mta+i*4, 0);	/*	 * Receive initialisation.	 * Mostly defaults from the datasheet, will	 * need some tuning for performance:	 *	Rctl	descriptor mimimum threshold size	 *		discard pause frames	 *		strip CRC	 * 	Rdtr	interrupt delay	 * 	Rxdctl	all the thresholds	 */	csr32w(ctlr, Rctl, 0);	/*	 * Allocate the descriptor ring and load its	 * address and length into the NIC.	 */	ctlr->rdba = xspanalloc(Nrdesc*sizeof(Rdesc), 128 /* was 16 */, 0);	csr32w(ctlr, Rdbal, PCIWADDR(ctlr->rdba));	csr32w(ctlr, Rdbah, 0);	csr32w(ctlr, Rdlen, Nrdesc*sizeof(Rdesc));	/*	 * Initialise the ring head and tail pointers and	 * populate the ring with Blocks.	 * The datasheet says the tail pointer is set to beyond the last	 * descriptor hardware can process, which implies the initial	 * condition is Rdh == Rdt. However, experience shows Rdt must	 * always be 'behind' Rdh; the replenish routine ensures this.	 */	ctlr->rdh = 0;	csr32w(ctlr, Rdh, ctlr->rdh);	ctlr->rdt = 0;	csr32w(ctlr, Rdt, ctlr->rdt);	ctlr->rb = malloc(sizeof(Block*)*Nrdesc);	igbereplenish(ctlr);	/*	 * Set up Rctl but don't enable receiver (yet).	 */	csr32w(ctlr, Rdtr, 0);	switch(ctlr->id){	case i82540em:	case i82540eplp:	case i82541gi:	case i82541pi:	case i82546gb:	case i82546eb:	case i82547gi:		csr32w(ctlr, Radv, 64);		break;	}	csr32w(ctlr, Rxdctl, (8<<WthreshSHIFT)|(8<<HthreshSHIFT)|4);	/*	 * Enable checksum offload.	 */	csr32w(ctlr, Rxcsum, Tuofl|Ipofl|(ETHERHDRSIZE<<PcssSHIFT));	csr32w(ctlr, Rctl, Dpf|Bsize2048|Bam|RdtmsHALF);	igbeim(ctlr, Rxt0|Rxo|Rxdmt0|Rxseq);	/*	 * Transmit initialisation.	 * Mostly defaults from the datasheet, will	 * need some tuning for performance. The normal mode will	 * be full-duplex and things to tune for half-duplex are	 *	Tctl	re-transmit on late collision	 *	Tipg	all IPG times	 *	Tbt	burst timer	 *	Ait	adaptive IFS throttle	 * and in general	 *	Txdmac	packet prefetching	 *	Ett	transmit early threshold	 *	Tidv	interrupt delay value	 *	Txdctl	all the thresholds	 */	csr32w(ctlr, Tctl, (0x0F<<CtSHIFT)|Psp|(66<<ColdSHIFT));	/* Fd */	switch(ctlr->id){	default:		r = 6;		break;	case i82543gc:	case i82544ei:	case i82547ei:	case i82540em:	case i82540eplp:	case i82541gi:	case i82541pi:	case i82546gb:	case i82546eb:	case i82547gi:		r = 8;		break;	}	csr32w(ctlr, Tipg, (6<<20)|(8<<10)|r);	csr32w(ctlr, Ait, 0);	csr32w(ctlr, Txdmac, 0);	csr32w(ctlr, Tidv, 128);	/*	 * Allocate the descriptor ring and load its	 * address and length into the NIC.	 */	ctlr->tdba = xspanalloc(Ntdesc*sizeof(Tdesc), 128 /* was 16 */, 0);	csr32w(ctlr, Tdbal, PCIWADDR(ctlr->tdba));	csr32w(ctlr, Tdbah, 0);	csr32w(ctlr, Tdlen, Ntdesc*sizeof(Tdesc));	/*	 * Initialise the ring head and tail pointers.	 */	ctlr->tdh = 0;	csr32w(ctlr, Tdh, ctlr->tdh);	ctlr->tdt = 0;	csr32w(ctlr, Tdt, ctlr->tdt);	ctlr->tb = malloc(sizeof(Block*)*Ntdesc);//	ctlr->im |= Txqe|Txdw;	r = (4<<WthreshSHIFT)|(4<<HthreshSHIFT)|(8<<PthreshSHIFT);	switch(ctlr->id){	default:		break;	case i82540em:	case i82540eplp:	case i82547gi:	case i82541pi:	case i82546gb:	case i82546eb:	case i82541gi:		r = csr32r(ctlr, Txdctl);		r &= ~WthreshMASK;		r |= Gran|(4<<WthreshSHIFT);		csr32w(ctlr, Tadv, 64);		break;	}	csr32w(ctlr, Txdctl, r);	r = csr32r(ctlr, Tctl);	r |= Ten;	csr32w(ctlr, Tctl, r);	if(ctlr->mii == nil || ctlr->mii->curphy == nil) {		print("igbe: no mii (yet)\n");		return 0;	}	/* wait for the link to come up */	if (miistatus(ctlr->mii) < 0)		return -1;	print("igbe: phy: ");	phy = ctlr->mii->curphy;	if (phy->fd)		print("full duplex");	else		print("half duplex");	print(", %d Mb/s\n", phy->speed);	/*	 * Flow control.	 */	ctrl = csr32r(ctlr, Ctrl);	if(phy->rfc)		ctrl |= Rfce;	if(phy->tfc)		ctrl |= Tfce;	csr32w(ctlr, Ctrl, ctrl);	return 0;}static inti82543mdior(Ctlr* ctlr, int n){	int ctrl, data, i, r;	/*	 * Read n bits from the Management Data I/O Interface.	 */	ctrl = csr32r(ctlr, Ctrl);	r = (ctrl & ~Mddo)|Mdco;	data = 0;	for(i = n-1; i >= 0; i--){		if(csr32r(ctlr, Ctrl) & Mdd)			data |= (1<<i);		csr32w(ctlr, Ctrl, Mdc|r);		csr32w(ctlr, Ctrl, r);	}	csr32w(ctlr, Ctrl, ctrl);	return data;}static inti82543mdiow(Ctlr* ctlr, int bits, int n){	int ctrl, i, r;	/*	 * Write n bits to the Management Data I/O Interface.	 */	ctrl = csr32r(ctlr, Ctrl);	r = Mdco|Mddo|ctrl;	for(i = n-1; i >= 0; i--){		if(bits & (1<<i))			r |= Mdd;		else			r &= ~Mdd;		csr32w(ctlr, Ctrl, Mdc|r);		csr32w(ctlr, Ctrl, r);	}	csr32w(ctlr, Ctrl, ctrl);	return 0;}static inti82543miimir(Mii* mii, int pa, int ra){	int data;	Ctlr *ctlr;	ctlr = mii->ctlr;	/*	 * MII Management Interface Read.	 *	 * Preamble;	 * ST+OP+PHYAD+REGAD;	 * TA + 16 data bits.	 */	i82543mdiow(ctlr, 0xFFFFFFFF, 32);	i82543mdiow(ctlr, 0x1800|(pa<<5)|ra, 14);	data = i82543mdior(ctlr, 18);	if(data & 0x10000)		return -1;	return data & 0xFFFF;}static inti82543miimiw(Mii* mii, int pa, int ra, int data){	Ctlr *ctlr;	ctlr = mii->ctlr;	/*	 * MII Management Interface Write.	 *	 * Preamble;	 * ST+OP+PHYAD+REGAD+TA + 16 data bits;	 * Z.	 */	i82543mdiow(ctlr, 0xFFFFFFFF, 32);	data &= 0xFFFF;	data |= (0x05<<(5+5+2+16))|(pa<<(5+2+16))|(ra<<(2+16))|(0x02<<16);	i82543mdiow(ctlr, data, 32);	return 0;}static intigbemiimir(Mii* mii, int pa, int ra){	Ctlr *ctlr;	int mdic, timo;	ctlr = mii->ctlr;	csr32w(ctlr, Mdic, MDIrop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT));	mdic = 0;	for(timo = 64; timo; timo--){		mdic = csr32r(ctlr, Mdic);		if(mdic & (MDIe|MDIready))			break;		microdelay(1);	}	if((mdic & (MDIe|MDIready)) == MDIready)		return mdic & 0xFFFF;	return -1;}static intigbemiimiw(Mii* mii, int pa, int ra, int data){	Ctlr *ctlr;	int mdic, timo;	ctlr = mii->ctlr;	data &= MDIdMASK;	csr32w(ctlr, Mdic, MDIwop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT)|data);	mdic = 0;	for(timo = 64; timo; timo--){		mdic = csr32r(ctlr, Mdic);		if(mdic & (MDIe|MDIready))			break;		microdelay(1);	}	if((mdic & (MDIe|MDIready)) == MDIready)		return 0;	return -1;}static intigbemii(Ctlr* ctlr){	MiiPhy *phy = (MiiPhy *)1;	int ctrl, p, r;	USED(phy);	r = csr32r(ctlr, Status);	if(r & Tbimode)		return -1;	if((ctlr->mii = malloc(sizeof(Mii))) == nil)		return -1;	ctlr->mii->ctlr = ctlr;	ctrl = csr32r(ctlr, Ctrl);	ctrl |= Slu;	switch(ctlr->id){	case i82543gc:		ctrl |= Frcdplx|Frcspd;		csr32w(ctlr, Ctrl, ctrl);		/*		 * The reset pin direction (Mdro) should already		 * be set from the EEPROM load.		 * If it's not set this configuration is unexpected		 * so bail.		 */		r = csr32r(ctlr, Ctrlext);		if(!(r & Mdro))			return -1;		csr32w(ctlr, Ctrlext, r);		delay(20);		r = csr32r(ctlr, Ctrlext);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -