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

📄 etherga620.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
	}}static voidga620interrupt(Ureg*, void* arg){	int csr, ie, work;	Ctlr *ctlr;	Ether *edev;	uvlong tsc0, tsc1;	edev = arg;	ctlr = edev->ctlr;	if(!(csr32r(ctlr, Mhc) & Is))		return;	cycles(&tsc0);	ctlr->interrupts++;	csr32w(ctlr, Hi, 1);	ie = 0;	work = 0;	while(ie < 2){		if(ctlr->rrrci != ctlr->rrrpi[0]){			ga620receive(edev);			work = 1;		}		if(_ga620transmit(edev) != 0)			work = 1;		csr = csr32r(ctlr, Eci);		if(csr != ctlr->epi[0]){			ga620event(ctlr, csr, ctlr->epi[0]);			work = 1;		}		if(ctlr->nrsr <= NrsrLO)			ga620replenish(ctlr);		if(work == 0){			if(ie == 0)				csr32w(ctlr, Hi, 0);			ie++;		}		work = 0;	}	cycles(&tsc1);	ctlr->ticks += tsc1-tsc0;}static voidga620lmw(Ctlr* ctlr, int addr, int* data, int len){	int i, l, lmw, v;	/*	 * Write to or clear ('data' == nil) 'len' bytes of the NIC	 * local memory at address 'addr'.	 * The destination address and count should be 32-bit aligned.	 */	v = 0;	while(len > 0){		/*		 * 1) Set the window. The (Lmwsz-1) bits are ignored		 *    in Wba when accessing through the local memory window;		 * 2) Find the minimum of how many bytes still to		 *    transfer and how many left in this window;		 * 3) Create the offset into the local memory window in the		 *    shared memory space then copy (or zero) the data;		 * 4) Bump the counts.		 */		csr32w(ctlr, Wba, addr);		l = ROUNDUP(addr+1, Lmwsz) - addr;		if(l > len)			l = len;		lmw = Lmw + (addr & (Lmwsz-1));		for(i = 0; i < l; i += 4){			if(data != nil)				v = *data++;			csr32w(ctlr, lmw+i, v);		}		len -= l;		addr += l;	}}static intga620init(Ether* edev){	Ctlr *ctlr;	Host64 host64;	int csr, ea, i, flags;	ctlr = edev->ctlr;	/*	 * Load the MAC address.	 */	ea = (edev->ea[0]<<8)|edev->ea[1];	csr32w(ctlr, Mac, ea);	ea = (edev->ea[2]<<24)|(edev->ea[3]<<16)|(edev->ea[4]<<8)|edev->ea[5];	csr32w(ctlr, Mac+4, ea);	/*	 * General Information Block.	 */	ctlr->gib = malloc(sizeof(Gib));	sethost64(&host64, ctlr->gib);	csr32w(ctlr, Gip, host64.hi);	csr32w(ctlr, Gip+4, host64.lo);	/*	 * Event Ring.	 * This is located in host memory. Allocate the ring,	 * tell the NIC where it is and initialise the indices.	 */	ctlr->er = malign(sizeof(Ere)*Ner);	sethost64(&ctlr->gib->ercb.addr, ctlr->er);	sethost64(&ctlr->gib->epp, ctlr->epi);	csr32w(ctlr, Eci, 0);	/*	 * Command Ring.	 * This is located in the General Communications Region	 * and so the value placed in the Rcb is unused, the NIC	 * knows where it is. Stick in the value according to	 * the datasheet anyway.	 * Initialise the ring and indices.	 */	ctlr->gib->crcb.addr.lo = Cr-0x400;	for(i = 0; i < Ncr*4; i += 4)		csr32w(ctlr, Cr+i, 0);	csr32w(ctlr, Cpi, 0);	csr32w(ctlr, Cci, 0);	/*	 * Send Ring.	 * This ring is either in NIC memory at a fixed location depending	 * on how big the ring is or it is in host memory. If in NIC	 * memory it is accessed via the Local Memory Window; with a send	 * ring size of 128 the window covers the whole ring and then need	 * only be set once:	 *	ctlr->sr = (uchar*)ctlr->nic+Lmw;	 *	ga620lmw(ctlr, Sr, nil, sizeof(Sbd)*Nsr);	 *	ctlr->gib->srcb.addr.lo = Sr;	 * There is nowhere in the Sbd to hold the Block* associated	 * with this entry so an external array must be kept.	 */	ctlr->sr = malign(sizeof(Sbd)*Nsr);	sethost64(&ctlr->gib->srcb.addr, ctlr->sr);	if(ctlr->hardwarecksum)		flags = TcpUdpCksum|NoPseudoHdrCksum|HostRing;	else 		flags = HostRing;	if(ctlr->coalupdateonly) 		flags |= CoalUpdateOnly;	ctlr->gib->srcb.control = (Nsr<<16)|flags;	sethost64(&ctlr->gib->scp, ctlr->sci);	csr32w(ctlr, Spi, 0);	ctlr->srb = malloc(sizeof(Block*)*Nsr);	/*	 * Receive Standard Ring.	 */	ctlr->rsr = malign(sizeof(Rbd)*Nrsr);	sethost64(&ctlr->gib->rsrcb.addr, ctlr->rsr);	if(ctlr->hardwarecksum)		flags = TcpUdpCksum|NoPseudoHdrCksum;	else		flags = 0;	ctlr->gib->rsrcb.control = ((ETHERMAXTU+4)<<16)|flags;	csr32w(ctlr, Rspi, 0);	/*	 * Jumbo and Mini Rings. Unused for now.	 */	ctlr->gib->rjrcb.control = RingDisabled;	ctlr->gib->rmrcb.control = RingDisabled;	/*	 * Receive Return Ring.	 * This is located in host memory. Allocate the ring,	 * tell the NIC where it is and initialise the indices.	 */	ctlr->rrr = malign(sizeof(Rbd)*Nrrr);	sethost64(&ctlr->gib->rrrcb.addr, ctlr->rrr);	ctlr->gib->rrrcb.control = (Nrrr<<16)|0;	sethost64(&ctlr->gib->rrrpp, ctlr->rrrpi);	ctlr->rrrci = 0;	/*	 * Refresh Stats Pointer.	 * For now just point it at the existing statistics block.	 */	sethost64(&ctlr->gib->rsp, ctlr->gib->statistics);	/*	 * DMA configuration.	 * Use the recommended values.	 */	csr32w(ctlr, DMArc, 0x80);	csr32w(ctlr, DMAwc, 0x80);	/*	 * Transmit Buffer Ratio.	 * Set to 1/3 of available buffer space (units are 1/64ths)	 * if using Jumbo packets, ~64KB otherwise (assume 1MB on NIC).	 */	if(NrjrHI > 0 || Nsr > 128)		csr32w(ctlr, Tbr, 64/3);	else		csr32w(ctlr, Tbr, 4);	/*	 * Tuneable parameters.	 * These defaults are based on the tuning hints in the Alteon	 * Host/NIC Software Interface Definition and example software.	 */	ctlr->rct = 1/*100*/;	csr32w(ctlr, Rct, ctlr->rct);	ctlr->sct = 0;	csr32w(ctlr, Sct, ctlr->sct);	ctlr->st = 1000000;	csr32w(ctlr, St, ctlr->st);	ctlr->smcbd = Nsr/4;	csr32w(ctlr, SmcBD, ctlr->smcbd);	ctlr->rmcbd = 4/*6*/;	csr32w(ctlr, RmcBD, ctlr->rmcbd);	/*	 * Enable DMA Assist Logic.	 */	csr = csr32r(ctlr, DMAas) & ~0x03;	csr32w(ctlr, DMAas, csr|0x01);	/*	 * Link negotiation.	 * The bits are set here but the NIC must be given a command	 * once it is running to set negotiation in motion.	 */	csr32w(ctlr, Gln, Le|Lean|Lofc|Lfd|L1000MB|Lpref);	csr32w(ctlr, Fln, Le|Lean|Lhd|Lfd|L100MB|L10MB);	/*	 * A unique index for this controller and the maximum packet	 * length expected.	 * For now only standard packets are expected.	 */	csr32w(ctlr, Ifx, 1);	csr32w(ctlr, IfMTU, ETHERMAXTU+4);	/*	 * Enable Interrupts.	 * There are 3 ways to mask interrupts - a bit in the Mhc (which	 * is already cleared), the Mi register and the Hi mailbox.	 * Writing to the Hi mailbox has the side-effect of clearing the	 * PCI interrupt.	 */	csr32w(ctlr, Mi, 0);	csr32w(ctlr, Hi, 0);	/*	 * Start the firmware.	 */	csr32w(ctlr, CPUApc, tigon2FwStartAddr);	csr = csr32r(ctlr, CPUAstate) & ~CPUhalt;	csr32w(ctlr, CPUAstate, csr);	return 0;}static intat24c32io(Ctlr* ctlr, char* op, int data){	char *lp, *p;	int i, loop, mlc, r;	mlc = csr32r(ctlr, Mlc);	r = 0;	loop = -1;	lp = nil;	for(p = op; *p != '\0'; p++){		switch(*p){		default:			return -1;		case ' ':			continue;		case ':':			/* start of 8-bit loop */			if(lp != nil)				return -1;			lp = p;			loop = 7;			continue;		case ';':			/* end of 8-bit loop */			if(lp == nil)				return -1;			loop--;			if(loop >= 0)				p = lp;			else				lp = nil;			continue;		case 'C':			/* assert clock */			mlc |= EEclk;			break;		case 'c':			/* deassert clock */			mlc &= ~EEclk;			break;		case 'D':			/* next bit in 'data' byte */			if(loop < 0)				return -1;			if(data & (1<<loop))				mlc |= EEdo;			else				mlc &= ~EEdo;			break;		case 'E':			/* enable data output */			mlc |= EEdoe;			break;		case 'e':			/* disable data output */			mlc &= ~EEdoe;			break;		case 'I':			/* input bit */			i = (csr32r(ctlr, Mlc) & EEdi) != 0;			if(loop >= 0)				r |= (i<<loop);			else				r = i;			continue;		case 'O':			/* assert data output */			mlc |= EEdo;			break;		case 'o':			/* deassert data output */			mlc &= ~EEdo;			break;		}		csr32w(ctlr, Mlc, mlc);		microdelay(1);	}	if(loop >= 0)		return -1;	return r;}static intat24c32r(Ctlr* ctlr, int addr){	int data;	/*	 * Read a byte at address 'addr' from the Atmel AT24C32	 * Serial EEPROM. The 2-wire EEPROM access is controlled	 * by 4 bits in Mlc. See the AT24C32 datasheet for	 * protocol details.	 */	/*	 * Start condition - a high to low transition of data	 * with the clock high must precede any other command.	 */	at24c32io(ctlr, "OECoc", 0);	/*	 * Perform a random read at 'addr'. A dummy byte	 * write sequence is performed to clock in the device	 * and data word addresses (0 and 'addr' respectively).	 */	data = -1;	if(at24c32io(ctlr, "oE :DCc; oeCIc", 0xA0) != 0)		goto stop;	if(at24c32io(ctlr, "oE :DCc; oeCIc", addr>>8) != 0)		goto stop;	if(at24c32io(ctlr, "oE :DCc; oeCIc", addr) != 0)		goto stop;	/*	 * Now send another start condition followed by a	 * request to read the device. The EEPROM responds	 * by clocking out the data.	 */	at24c32io(ctlr, "OECoc", 0);	if(at24c32io(ctlr, "oE :DCc; oeCIc", 0xA1) != 0)		goto stop;	data = at24c32io(ctlr, ":CIc;", 0xA1);stop:	/*	 * Stop condition - a low to high transition of data	 * with the clock high is a stop condition. After a read	 * sequence, the stop command will place the EEPROM in	 * a standby power mode.	 */	at24c32io(ctlr, "oECOc", 0);	return data;}static intga620detach(Ctlr* ctlr){	int timeo;	/*	 * Hard reset (don't know which endian so catch both);	 * enable for little-endian mode;	 * wait for code to be loaded from serial EEPROM or flash;	 * make sure CPU A is halted.	 */	csr32w(ctlr, Mhc, (Hr<<24)|Hr);	csr32w(ctlr, Mhc, ((Eews|Ci)<<24)|(Eews|Ci));	microdelay(1);	for(timeo = 0; timeo < 500000; timeo++){		if((csr32r(ctlr, CPUAstate) & (CPUhie|CPUrf)) == CPUhie)			break;		microdelay(1);	}	if((csr32r(ctlr, CPUAstate) & (CPUhie|CPUrf)) != CPUhie)		return -1;	csr32w(ctlr, CPUAstate, CPUhalt);	/*	 * After reset, CPU B seems to be stuck in 'CPUrf'.	 * Worry about it later.	 */	csr32w(ctlr, CPUBstate, CPUhalt);	return 0;}static voidga620shutdown(Ether* ether){print("ga620shutdown\n");	ga620detach(ether->ctlr);}static intga620reset(Ctlr* ctlr){	int cls, csr, i, r;	if(ga620detach(ctlr) < 0)		return -1;	/*	 * Tigon 2 PCI NICs have 512KB SRAM per bank.	 * Clear out any lingering serial EEPROM state	 * bits.	 */	csr = csr32r(ctlr, Mlc) & ~(EEdi|EEdo|EEdoe|EEclk|SRAMmask);	csr32w(ctlr, Mlc, SRAM512|csr);	csr = csr32r(ctlr, Mc);	csr32w(ctlr, Mc, SyncSRAM|csr);	/*	 * Initialise PCI State register.	 * If PCI Write-and-Invalidate is enabled set the max write DMA	 * value to the host cache-line size (32 on Pentium or later).	 */	csr = csr32r(ctlr, Ps) & (PCI32|PCI66);	csr |= PCIwcmd|PCIrcmd|PCImrm;	if(ctlr->pcidev->pcr & 0x0010){		cls = pcicfgr8(ctlr->pcidev, PciCLS) * 4;		if(cls != 32)			pcicfgw8(ctlr->pcidev, PciCLS, 32/4);		csr |= PCIwm32;	}	csr32w(ctlr, Ps, csr);	/*	 * Operating Mode.	 */	csr32w(ctlr, Om, Fatal|NoJFrag|BswapDMA|WswapBD);	/*	 * Snarf the MAC address from the serial EEPROM.	 */	for(i = 0; i < Eaddrlen; i++){		if((r = at24c32r(ctlr, 0x8E+i)) == -1)			return -1;		ctlr->ea[i] = r;	}	/*	 * Load the firmware.	 */	ga620lmw(ctlr, tigon2FwTextAddr, tigon2FwText, tigon2FwTextLen);	ga620lmw(ctlr, tigon2FwRodataAddr, tigon2FwRodata, tigon2FwRodataLen);	ga620lmw(ctlr, tigon2FwDataAddr, tigon2FwData, tigon2FwDataLen);	ga620lmw(ctlr, tigon2FwSbssAddr, nil, tigon2FwSbssLen);	ga620lmw(ctlr, tigon2FwBssAddr, nil, tigon2FwBssLen);	return 0;}static voidga620pci(void){	void *mem;	Pcidev *p;	Ctlr *ctlr;	p = nil;	while(p = pcimatch(p, 0, 0)){		if(p->ccrb != 0x02 || p->ccru != 0)			continue;		switch((p->did<<16)|p->vid){		default:			continue;		case (0x620A<<16)|0x1385:	/* Netgear GA620 */		case (0x630A<<16)|0x1385:	/* Netgear GA620T */		case (0x0001<<16)|0x12AE:	/* Alteon Acenic fiber						 * and DEC DEGPA-SA */		case (0x0002<<16)|0x12AE:	/* Alteon Acenic copper */		case (0x0009<<16)|0x10A9:	/* SGI Acenic */			break;		}		mem = vmap(p->mem[0].bar & ~0x0F, p->mem[0].size);		if(mem == 0){			print("ga620: can't map %8.8luX\n", p->mem[0].bar);			continue;		}		ctlr = malloc(sizeof(Ctlr));		ctlr->port = p->mem[0].bar & ~0x0F;		ctlr->pcidev = p;		ctlr->id = (p->did<<16)|p->vid;		ctlr->nic = mem;		if(ga620reset(ctlr)){			free(ctlr);			continue;		}		if(ctlrhead != nil)			ctlrtail->next = ctlr;		else			ctlrhead = ctlr;		ctlrtail = ctlr;	}}static intga620pnp(Ether* edev){	Ctlr *ctlr;	uchar ea[Eaddrlen];	if(ctlrhead == nil)		ga620pci();	/*	 * 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;		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 = 1000;	/*	 * 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 in the hardware.	 */	memset(ea, 0, Eaddrlen);	if(memcmp(ea, edev->ea, Eaddrlen) == 0)		memmove(edev->ea, ctlr->ea, Eaddrlen);	ga620init(edev);	/*	 * Linkage to the generic ethernet driver.	 */	edev->attach = ga620attach;	edev->transmit = ga620transmit;	edev->interrupt = ga620interrupt;	edev->ifstat = ga620ifstat;	edev->ctl = ga620ctl;	edev->shutdown = ga620shutdown;	edev->arg = edev;	edev->promiscuous = nil;	return 0;}voidetherga620link(void){	addethercard("GA620", ga620pnp);}

⌨️ 快捷键说明

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