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

📄 ether82557.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
			rfd->field = 0;		}		/*		 * The ring tail pointer follows the head with with one		 * unused buffer in between to defeat hardware prefetch;		 * once the tail pointer has been bumped on to the next		 * and the new tail has the Suspend bit set, it can be		 * removed from the old tail buffer.		 * As a replacement for the current head buffer may have		 * been allocated above, ensure that the new tail points		 * to it (next and link).		 */		rfd = (Rfd*)ctlr->rfdtail->rp;		ctlr->rfdtail = ctlr->rfdtail->next;		ctlr->rfdtail->next = bp;		((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp);		((Rfd*)ctlr->rfdtail->rp)->field |= RfdS;		coherence();		rfd->field &= ~RfdS;		/*		 * Finally done with the current (possibly replaced)		 * head, move on to the next and maintain the sentinel		 * between tail and head.		 */		ctlr->rfdhead = bp->next;		bp = ctlr->rfdhead;	}}static voidinterrupt(Ureg*, void* arg){	Cb* cb;	Ctlr *ctlr;	Ether *ether;	int status;	ether = arg;	ctlr = ether->ctlr;	for(;;){		ilock(&ctlr->rlock);		status = csr16r(ctlr, Status);		csr8w(ctlr, Ack, (status>>8) & 0xFF);		iunlock(&ctlr->rlock);		if(!(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)))			break;		/*		 * If the watchdog timer for the receiver lockup errata is running,		 * let it know the receiver is active.		 */		if(status & (StatFR|StatRNR)){			ilock(&ctlr->cblock);			ctlr->tick = 0;			iunlock(&ctlr->cblock);		}		if(status & StatFR){			receive(ether);			status &= ~StatFR;		}		if(status & StatRNR){			command(ctlr, RUresume, 0);			status &= ~StatRNR;		}		if(status & StatCNA){			ilock(&ctlr->cblock);			cb = ctlr->cbtail;			while(ctlr->cbq){				if(!(cb->status & CbC))					break;				if(cb->bp){					freeb(cb->bp);					cb->bp = nil;				}				if((cb->status & CbU) && ctlr->threshold < 0xE0)					ctlr->threshold++;				ctlr->cbq--;				cb = cb->next;			}			ctlr->cbtail = cb;			txstart(ether);			iunlock(&ctlr->cblock);			status &= ~StatCNA;		}		if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI))			panic("#l%d: status %#ux\n", ether->ctlrno, status);	}}static voidctlrinit(Ctlr* ctlr){	int i;	Block *bp;	Rfd *rfd;	ulong link;	/*	 * Create the Receive Frame Area (RFA) as a ring of allocated	 * buffers.	 * A sentinel buffer is maintained between the last buffer in	 * the ring (marked with RfdS) and the head buffer to defeat the	 * hardware prefetch of the next RFD and allow dynamic buffer	 * allocation.	 */	link = NullPointer;	for(i = 0; i < Nrfd; i++){		bp = rfdalloc(link);		if(ctlr->rfdhead == nil)			ctlr->rfdtail = bp;		bp->next = ctlr->rfdhead;		ctlr->rfdhead = bp;		link = PADDR(bp->rp);	}	ctlr->rfdtail->next = ctlr->rfdhead;	rfd = (Rfd*)ctlr->rfdtail->rp;	rfd->link = PADDR(ctlr->rfdhead->rp);	rfd->field |= RfdS;	ctlr->rfdhead = ctlr->rfdhead->next;	/*	 * Create a ring of control blocks for the	 * transmit side.	 */	ilock(&ctlr->cblock);	ctlr->cbr = malloc(ctlr->ncb*sizeof(Cb));	for(i = 0; i < ctlr->ncb; i++){		ctlr->cbr[i].status = CbC|CbOK;		ctlr->cbr[i].command = CbS|CbNOP;		ctlr->cbr[i].link = PADDR(&ctlr->cbr[NEXT(i, ctlr->ncb)].status);		ctlr->cbr[i].next = &ctlr->cbr[NEXT(i, ctlr->ncb)];	}	ctlr->cbhead = ctlr->cbr;	ctlr->cbtail = ctlr->cbr;	ctlr->cbq = 0;	memmove(ctlr->configdata, configdata, sizeof(configdata));	ctlr->threshold = 80;	ctlr->tick = 0;	iunlock(&ctlr->cblock);}static intmiir(Ctlr* ctlr, int phyadd, int regadd){	int mcr, timo;	lock(&ctlr->miilock);	csr32w(ctlr, Mcr, MDIread|(phyadd<<21)|(regadd<<16));	mcr = 0;	for(timo = 64; timo; timo--){		mcr = csr32r(ctlr, Mcr);		if(mcr & MDIready)			break;		microdelay(1);	}	unlock(&ctlr->miilock);	if(mcr & MDIready)		return mcr & 0xFFFF;	return -1;}static intmiiw(Ctlr* ctlr, int phyadd, int regadd, int data){	int mcr, timo;	lock(&ctlr->miilock);	csr32w(ctlr, Mcr, MDIwrite|(phyadd<<21)|(regadd<<16)|(data & 0xFFFF));	mcr = 0;	for(timo = 64; timo; timo--){		mcr = csr32r(ctlr, Mcr);		if(mcr & MDIready)			break;		microdelay(1);	}	unlock(&ctlr->miilock);	if(mcr & MDIready)		return 0;	return -1;}static inthy93c46r(Ctlr* ctlr, int r){	int data, i, op, size;	/*	 * Hyundai HY93C46 or equivalent serial EEPROM.	 * This sequence for reading a 16-bit register 'r'	 * in the EEPROM is taken straight from Section	 * 3.3.4.2 of the Intel 82557 User's Guide.	 */reread:	csr16w(ctlr, Ecr, EEcs);	op = EEstart|EEread;	for(i = 2; i >= 0; i--){		data = (((op>>i) & 0x01)<<2)|EEcs;		csr16w(ctlr, Ecr, data);		csr16w(ctlr, Ecr, data|EEsk);		microdelay(1);		csr16w(ctlr, Ecr, data);		microdelay(1);	}	/*	 * First time through must work out the EEPROM size.	 */	if((size = ctlr->eepromsz) == 0)		size = 8;	for(size = size-1; size >= 0; size--){		data = (((r>>size) & 0x01)<<2)|EEcs;		csr16w(ctlr, Ecr, data);		csr16w(ctlr, Ecr, data|EEsk);		delay(1);		csr16w(ctlr, Ecr, data);		microdelay(1);		if(!(csr16r(ctlr, Ecr) & EEdo))			break;	}	data = 0;	for(i = 15; i >= 0; i--){		csr16w(ctlr, Ecr, EEcs|EEsk);		microdelay(1);		if(csr16r(ctlr, Ecr) & EEdo)			data |= (1<<i);		csr16w(ctlr, Ecr, EEcs);		microdelay(1);	}	csr16w(ctlr, Ecr, 0);	if(ctlr->eepromsz == 0){		ctlr->eepromsz = 8-size;		ctlr->eeprom = malloc((1<<ctlr->eepromsz)*sizeof(ushort));		goto reread;	}	return data;}static voidi82557pci(void){	Pcidev *p;	Ctlr *ctlr;	int nop, port;	p = nil;	nop = 0;	while(p = pcimatch(p, 0x8086, 0)){		switch(p->did){		default:			continue;		case 0x1031:		/* Intel 82562EM */		case 0x1050:		/* Intel 82562EZ */		case 0x1039:		/* Intel 82801BD PRO/100 VE */		case 0x103A:		/* Intel 82562 PRO/100 VE */		case 0x103D:		/* Intel 82562 PRO/100 VE */		case 0x1064:		/* Intel 82562 PRO/100 VE */		case 0x2449:		/* Intel 82562ET */			nop = 1;			/*FALLTHROUGH*/		case 0x1209:		/* Intel 82559ER */		case 0x1229:		/* Intel 8255[789] */		case 0x1030:		/* Intel 82559 InBusiness 10/100  */			break;		}#ifndef FS		if(pcigetpms(p) > 0){			int i;			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		/*		 * bar[0] is the memory-mapped register address (4KB),		 * bar[1] is the I/O port register address (32 bytes) and		 * bar[2] is for the flash ROM (1MB).		 */		port = p->mem[1].bar & ~0x01;		if(ioalloc(port, p->mem[1].size, 0, "i82557") < 0){			print("i82557: port %#ux in use\n", port);			continue;		}		ctlr = malloc(sizeof(Ctlr));		ctlr->port = port;		ctlr->pcidev = p;		ctlr->nop = nop;		if(ctlrhead != nil)			ctlrtail->next = ctlr;		else			ctlrhead = ctlr;		ctlrtail = ctlr;		pcisetbme(p);	}}static char* mediatable[9] = {	"10BASE-T",				/* TP */	"10BASE-2",				/* BNC */	"10BASE-5",				/* AUI */	"100BASE-TX",	"10BASE-TFD",	"100BASE-TXFD",	"100BASE-T4",	"100BASE-FX",	"100BASE-FXFD",};static intscanphy(Ctlr* ctlr){	int i, oui, x;	for(i = 0; i < 32; i++){		if((oui = miir(ctlr, i, 2)) == -1 || oui == 0 || oui == 0xFFFF)			continue;		oui <<= 6;		x = miir(ctlr, i, 3);		oui |= x>>10;		//print("phy%d: oui %#ux reg1 %#ux\n", i, oui, miir(ctlr, i, 1));		ctlr->eeprom[6] = i;		if(oui == 0xAA00)			ctlr->eeprom[6] |= 0x07<<8;		else if(oui == 0x80017){			if(x & 0x01)				ctlr->eeprom[6] |= 0x0A<<8;			else				ctlr->eeprom[6] |= 0x04<<8;		}		return i;	}	return -1;}static voidshutdown(Ether* ether){	Ctlr *ctlr = ether->ctlr;print("ether82557 shutting down\n");	csr32w(ctlr, Port, 0);	delay(1);	csr8w(ctlr, Interrupt, InterruptM);}intetheri82557reset(Ether* ether){	int anar, anlpar, bmcr, bmsr, i, k, medium, phyaddr, x;	unsigned short sum;	uchar ea[Eaddrlen];	Ctlr *ctlr;	if(ctlrhead == nil)		i82557pci();	/*	 * Any adapter matches if no ether->port is supplied,	 * otherwise the ports must match.	 */	for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){		if(ctlr->active)			continue;		if(ether->port == 0 || ether->port == ctlr->port){			ctlr->active = 1;			break;		}	}	if(ctlr == nil)		return -1;	/*	 * Initialise the Ctlr structure.	 * Perform a software reset after which should ensure busmastering	 * is still enabled. The EtherExpress PRO/100B appears to leave	 * the PCI configuration alone (see the 'To do' list above) so punt	 * for now.	 * Load the RUB and CUB registers for linear addressing (0).	 */	ether->ctlr = ctlr;	ether->port = ctlr->port;	ether->irq = ctlr->pcidev->intl;	ether->tbdf = ctlr->pcidev->tbdf;	ilock(&ctlr->rlock);	csr32w(ctlr, Port, 0);	delay(1);	csr8w(ctlr, Interrupt, InterruptM);	iunlock(&ctlr->rlock);	command(ctlr, LoadRUB, 0);	command(ctlr, LoadCUB, 0);	command(ctlr, LoadDCA, PADDR(ctlr->dump));	/*	 * Initialise the receive frame, transmit ring and configuration areas.	 */	ctlr->ncb = Ncb;	ctlrinit(ctlr);	/*	 * Read the EEPROM.	 * Do a dummy read first to get the size	 * and allocate ctlr->eeprom.	 */	hy93c46r(ctlr, 0);	sum = 0;	for(i = 0; i < (1<<ctlr->eepromsz); i++){		x = hy93c46r(ctlr, i);		ctlr->eeprom[i] = x;		sum += x;	}	if(sum != 0xBABA)		print("#l%d: EEPROM checksum - %#4.4ux\n", ether->ctlrno, sum);	/*	 * Eeprom[6] indicates whether there is a PHY and whether	 * it's not 10Mb-only, in which case use the given PHY address	 * to set any PHY specific options and determine the speed.	 * Unfortunately, sometimes the EEPROM is blank except for	 * the ether address and checksum; in this case look at the	 * controller type and if it's am 82558 or 82559 it has an	 * embedded PHY so scan for that.	 * If no PHY, assume 82503 (serial) operation.	 */	if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000))		phyaddr = ctlr->eeprom[6] & 0x00FF;	else	switch(ctlr->pcidev->rid){	case 0x01:			/* 82557 A-step */	case 0x02:			/* 82557 B-step */	case 0x03:			/* 82557 C-step */	default:		phyaddr = -1;		break;	case 0x04:			/* 82558 A-step */	case 0x05:			/* 82558 B-step */	case 0x06:			/* 82559 A-step */	case 0x07:			/* 82559 B-step */	case 0x08:			/* 82559 C-step */	case 0x09:			/* 82559ER A-step */		phyaddr = scanphy(ctlr);		break;	}	if(phyaddr >= 0){		/*		 * Resolve the highest common ability of the two		 * link partners. In descending order:		 *	0x0100		100BASE-TX Full Duplex		 *	0x0200		100BASE-T4		 *	0x0080		100BASE-TX		 *	0x0040		10BASE-T Full Duplex		 *	0x0020		10BASE-T		 */		anar = miir(ctlr, phyaddr, 0x04);		anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0;		anar &= anlpar;		bmcr = 0;		if(anar & 0x380)			bmcr = 0x2000;		if(anar & 0x0140)			bmcr |= 0x0100;		switch((ctlr->eeprom[6]>>8) & 0x001F){		case 0x04:				/* DP83840 */		case 0x0A:				/* DP83840A */			/*			 * The DP83840[A] requires some tweaking for			 * reliable operation.			 * The manual says bit 10 should be unconditionally			 * set although it supposedly only affects full-duplex			 * operation (an & 0x0140).			 */			x = miir(ctlr, phyaddr, 0x17) & ~0x0520;			x |= 0x0420;			for(i = 0; i < ether->nopt; i++){				if(cistrcmp(ether->opt[i], "congestioncontrol"))					continue;				x |= 0x0100;				break;			}			miiw(ctlr, phyaddr, 0x17, x);			/*			 * If the link partner can't autonegotiate, determine			 * the speed from elsewhere.			 */			if(anlpar == 0){				miir(ctlr, phyaddr, 0x01);				bmsr = miir(ctlr, phyaddr, 0x01);				x = miir(ctlr, phyaddr, 0x19);				if((bmsr & 0x0004) && !(x & 0x0040))					bmcr = 0x2000;			}			break;		case 0x07:				/* Intel 82555 */			/*			 * Auto-negotiation may fail if the other end is			 * a DP83840A and the cable is short.			 */			miir(ctlr, phyaddr, 0x01);			bmsr = miir(ctlr, phyaddr, 0x01);			if((miir(ctlr, phyaddr, 0) & 0x1000) && !(bmsr & 0x0020)){				miiw(ctlr, phyaddr, 0x1A, 0x2010);				x = miir(ctlr, phyaddr, 0);				miiw(ctlr, phyaddr, 0, 0x0200|x);				for(i = 0; i < 3000; i++){					delay(1);					if(miir(ctlr, phyaddr, 0x01) & 0x0020)						break;				}				miiw(ctlr, phyaddr, 0x1A, 0x2000);									anar = miir(ctlr, phyaddr, 0x04);				anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0;				anar &= anlpar;				bmcr = 0;				if(anar & 0x380)					bmcr = 0x2000;				if(anar & 0x0140)					bmcr |= 0x0100;			}			break;		}		/*		 * Force speed and duplex if no auto-negotiation.		 */		if(anlpar == 0){			medium = -1;			for(i = 0; i < ether->nopt; i++){				for(k = 0; k < nelem(mediatable); k++){					if(cistrcmp(mediatable[k], ether->opt[i]))						continue;					medium = k;					break;				}						switch(medium){				default:					break;				case 0x00:			/* 10BASE-T */				case 0x01:			/* 10BASE-2 */				case 0x02:			/* 10BASE-5 */					bmcr &= ~(0x2000|0x0100);					ctlr->configdata[19] &= ~0x40;					break;				case 0x03:			/* 100BASE-TX */				case 0x06:			/* 100BASE-T4 */				case 0x07:			/* 100BASE-FX */					ctlr->configdata[19] &= ~0x40;					bmcr |= 0x2000;					break;				case 0x04:			/* 10BASE-TFD */					bmcr = (bmcr & ~0x2000)|0x0100;					ctlr->configdata[19] |= 0x40;					break;				case 0x05:			/* 100BASE-TXFD */				case 0x08:			/* 100BASE-FXFD */					bmcr |= 0x2000|0x0100;					ctlr->configdata[19] |= 0x40;					break;				}			}			if(medium != -1)				miiw(ctlr, phyaddr, 0x00, bmcr);		}		if(bmcr & 0x2000)			ether->mbps = 100;		ctlr->configdata[8] = 1;		ctlr->configdata[15] &= ~0x80;	}	else{		ctlr->configdata[8] = 0;		ctlr->configdata[15] |= 0x80;	}	/*	 * Workaround for some broken HUB chips when connected at 10Mb/s	 * half-duplex.	 * This is a band-aid, but as there's no dynamic auto-negotiation	 * code at the moment, only deactivate the workaround code in txstart	 * if the link is 100Mb/s.	 */	if(ether->mbps != 10)		ctlr->nop = 0;	/*	 * Load the chip configuration and start it off.	 */#ifndef FS	if(ether->oq == 0)		ether->oq = qopen(256*1024, Qmsg, 0, 0);#endif	configure(ether, 0);	command(ctlr, CUstart, PADDR(&ctlr->cbr->status));	/*	 * Check if the adapter's station address is to be overridden.	 * If not, read it from the EEPROM and set in ether->ea prior to loading	 * the station address with the Individual Address Setup command.	 */	memset(ea, 0, Eaddrlen);	if(memcmp(ea, ether->ea, Eaddrlen) == 0){		for(i = 0; i < Eaddrlen/2; i++){			x = ctlr->eeprom[i];			ether->ea[2*i] = x;			ether->ea[2*i+1] = x>>8;		}	}	ilock(&ctlr->cblock);	ctlr->action = CbIAS;	txstart(ether);	iunlock(&ctlr->cblock);	/*	 * Linkage to the generic ethernet driver.	 */	ether->attach = attach;	ether->transmit = transmit;	ether->interrupt = interrupt;#ifndef FS	ether->ifstat = ifstat;	ether->arg = ether;	ether->promiscuous = promiscuous;	ether->shutdown = shutdown;	ether->multicast = multicast;#endif	return 0;}#ifndef FSvoidether82557bothlink(void){	addethercard("i82557",  etheri82557reset);}#endif

⌨️ 快捷键说明

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