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

📄 etherelnk3.c

📁 著名操作系统Plan 9的第三版的部分核心源代码。现在很难找到了。Plan 9是bell实验室开发的Unix后继者。
💻 C
📖 第 1 页 / 共 4 页
字号:
	return bp;}static uchar*startdma(Ether* ether, ulong address){	int port, status, w;	uchar *wp;	port = ether->port;	w = (STATUS(port)>>13) & 0x07;	COMMAND(port, SelectRegisterWindow, Wmaster);	wp = KADDR(inl(port+MasterAddress));	status = ins(port+MasterStatus);	if(status & (masterInProgress|targetAbort|masterAbort))		print("#l%d: BM status 0x%uX\n", ether->ctlrno, status);	outs(port+MasterStatus, masterMask);	outl(port+MasterAddress, address);	outs(port+MasterLen, sizeof(Etherpkt));	COMMAND(port, StartDma, Upload);	COMMAND(port, SelectRegisterWindow, w);	return wp;}static voidpromiscuous(void* arg, int on){	int filter, port;	Ether *ether;	ether = (Ether*)arg;	port = ether->port;	filter = receiveBroadcast|receiveIndividual;	if(ether->nmaddr)		filter |= receiveMulticast;	if(on)		filter |= receiveAllFrames;	COMMAND(port, SetRxFilter, filter);}static voidmulticast(void* arg, uchar *addr, int on){	int filter, port;	Ether *ether;	USED(addr, on);	ether = (Ether*)arg;	port = ether->port;	filter = receiveBroadcast|receiveIndividual;	if(ether->nmaddr)		filter |= receiveMulticast;	if(ether->prom)		filter |= receiveAllFrames;	COMMAND(port, SetRxFilter, filter);}static voidattach(Ether* ether){	int port, x;	Ctlr *ctlr;	ctlr = ether->ctlr;	ilock(&ctlr->wlock);	if(ctlr->attached){		iunlock(&ctlr->wlock);		return;	}	port = ether->port;	/*	 * Set the receiver packet filter for this and broadcast addresses,	 * set the interrupt masks for all interrupts, enable the receiver	 * and transmitter.	 */	promiscuous(ether, ether->prom);	x = interruptMask;	if(ctlr->busmaster == 1)		x &= ~(rxEarly|rxComplete);	else{		if(ctlr->dnenabled)			x &= ~transferInt;		if(ctlr->upenabled)			x &= ~(rxEarly|rxComplete);	}	COMMAND(port, SetIndicationEnable, x);	COMMAND(port, SetInterruptEnable, x);	COMMAND(port, RxEnable, 0);	COMMAND(port, TxEnable, 0);	/*	 * Prime the busmaster channel for receiving directly into a	 * receive packet buffer if necessary.	 */	if(ctlr->busmaster == 1)		startdma(ether, PADDR(ctlr->rbp->rp));	else{		if(ctlr->upenabled)			outl(port+UpListPtr, PADDR(&ctlr->uphead->np));	}	ctlr->attached = 1;	iunlock(&ctlr->wlock);}static voidstatistics(Ether* ether){	int port, i, u, w;	Ctlr *ctlr;	port = ether->port;	ctlr = ether->ctlr;	/*	 * 3C59[27] require a read between a PIO write and	 * reading a statistics register.	 */	w = (STATUS(port)>>13) & 0x07;	COMMAND(port, SelectRegisterWindow, Wstatistics);	STATUS(port);	for(i = 0; i < UpperFramesOk; i++)		ctlr->stats[i] += inb(port+i) & 0xFF;	u = inb(port+UpperFramesOk) & 0xFF;	ctlr->stats[FramesXmittedOk] += (u & 0x30)<<4;	ctlr->stats[FramesRcvdOk] += (u & 0x03)<<8;	ctlr->stats[BytesRcvdOk] += ins(port+BytesRcvdOk) & 0xFFFF;	ctlr->stats[BytesRcvdOk+1] += ins(port+BytesXmittedOk) & 0xFFFF;	switch(ctlr->xcvr){	case xcvrMii:	case xcvr100BaseTX:	case xcvr100BaseFX:		COMMAND(port, SelectRegisterWindow, Wdiagnostic);		STATUS(port);		ctlr->stats[BytesRcvdOk+2] += inb(port+BadSSD);		break;	}	COMMAND(port, SelectRegisterWindow, w);}static voidtxstart(Ether* ether){	int port, len;	Ctlr *ctlr;	Block *bp;	port = ether->port;	ctlr = ether->ctlr;	/*	 * Attempt to top-up the transmit FIFO. If there's room simply	 * stuff in the packet length (unpadded to a dword boundary), the	 * packet data (padded) and remove the packet from the queue.	 * If there's no room post an interrupt for when there is.	 * This routine is called both from the top level and from interrupt	 * level and expects to be called with ctlr->wlock already locked	 * and the correct register window (Wop) in place.	 */	for(;;){		if(ctlr->txbp){			bp = ctlr->txbp;			ctlr->txbp = 0;		}		else{			bp = qget(ether->oq);			if(bp == nil)				break;		}		len = ROUNDUP(BLEN(bp), 4);		if(len+4 <= ins(port+TxFree)){			outl(port+Fifo, BLEN(bp));			outsl(port+Fifo, bp->rp, len/4);			freeb(bp);			ether->outpackets++;		}		else{			ctlr->txbp = bp;			if(ctlr->txbusy == 0){				ctlr->txbusy = 1;				COMMAND(port, SetTxAvailableThresh, len>>ctlr->ts);			}			break;		}	}}static voidtxstart905(Ether* ether){	Ctlr *ctlr;	int port, stalled, timeo;	Block *bp;	Pd *pd;	ctlr = ether->ctlr;	port = ether->port;	/*	 * Free any completed packets.	 */	pd = ctlr->dntail;	while(ctlr->dnq){		if(PADDR(&pd->np) == inl(port+DnListPtr))			break;		if(pd->bp){			freeb(pd->bp);			pd->bp = nil;		}		ctlr->dnq--;		pd = pd->next;	}	ctlr->dntail = pd;	stalled = 0;	while(ctlr->dnq < (ctlr->ndn-1)){		bp = qget(ether->oq);		if(bp == nil)			break;		pd = ctlr->dnhead->next;		pd->np = 0;		pd->control = dnIndicate|BLEN(bp);		pd->addr = PADDR(bp->rp);		pd->len = updnLastFrag|BLEN(bp);		pd->bp = bp;		if(stalled == 0 && ctlr->dnq && inl(port+DnListPtr)){			COMMAND(port, Stall, dnStall);			for(timeo = 100; (STATUS(port) & commandInProgress) && timeo; timeo--)				;			if(timeo == 0)				print("#l%d: dnstall %d\n", ether->ctlrno, timeo);			stalled = 1;		}		coherence();		ctlr->dnhead->np = PADDR(&pd->np);		ctlr->dnhead->control &= ~dnIndicate;		ctlr->dnhead = pd;		if(ctlr->dnq == 0)			ctlr->dntail = pd;		ctlr->dnq++;		ctlr->dnqueued++;	}	if(ctlr->dnq > ctlr->dnqmax)		ctlr->dnqmax = ctlr->dnq;	/*	 * If the adapter is not currently processing anything	 * and there is something on the queue, start it processing.	 */	if(inl(port+DnListPtr) == 0 && ctlr->dnq)		outl(port+DnListPtr, PADDR(&ctlr->dnhead->np));	if(stalled)		COMMAND(port, Stall, dnUnStall);}static voidtransmit(Ether* ether){	Ctlr *ctlr;	int port, w;	port = ether->port;	ctlr = ether->ctlr;	ilock(&ctlr->wlock);	if(ctlr->dnenabled)		txstart905(ether);	else{		w = (STATUS(port)>>13) & 0x07;		COMMAND(port, SelectRegisterWindow, Wop);		txstart(ether);		COMMAND(port, SelectRegisterWindow, w);	}	iunlock(&ctlr->wlock);}static voidreceive905(Ether* ether){	Ctlr *ctlr;	int len, port, q;	Pd *pd;	Block *bp;	ctlr = ether->ctlr;	port = ether->port;	if(inl(port+UpPktStatus) & upStalled)		ctlr->upstalls++;	q = 0;	for(pd = ctlr->uphead; pd->control & upPktComplete; pd = pd->next){		if(pd->control & upError){			if(pd->control & upOverrun)				ether->overflows++;			if(pd->control & (upOversizedFrame|upRuntFrame))				ether->buffs++;			if(pd->control & upAlignmentError)				ether->frames++;			if(pd->control & upCRCError)				ether->crcs++;		}		else if(bp = iallocb(sizeof(Etherpkt)+4)){			len = pd->control & rxBytes;			pd->bp->wp = pd->bp->rp+len;			etheriq(ether, pd->bp, 1);			pd->bp = bp;			pd->addr = PADDR(bp->rp);			coherence();		}		pd->control = 0;		COMMAND(port, Stall, upUnStall);		q++;	}	ctlr->uphead = pd;	ctlr->upqueued += q;	if(q > ctlr->upqmax)		ctlr->upqmax = q;}static voidreceive(Ether* ether){	int len, port, rxerror, rxstatus;	Ctlr *ctlr;	Block *bp;	port = ether->port;	ctlr = ether->ctlr;	while(((rxstatus = ins(port+RxStatus)) & rxIncomplete) == 0){		if(ctlr->busmaster == 1 && (STATUS(port) & busMasterInProgress))			break;		/*		 * If there was an error, log it and continue.		 * Unfortunately the 3C5[078]9 has the error info in the status register		 * and the 3C59[0257] implement a separate RxError register.		 */		if(rxstatus & rxError){			if(ctlr->rxstatus9){				switch(rxstatus & rxError9){				case rxOverrun9:					ether->overflows++;					break;				case oversizedFrame9:				case runtFrame9:					ether->buffs++;					break;				case alignmentError9:					ether->frames++;					break;				case crcError9:					ether->crcs++;					break;				}			}			else{				rxerror = inb(port+RxError);				if(rxerror & rxOverrun)					ether->overflows++;				if(rxerror & (oversizedFrame|runtFrame))					ether->buffs++;				if(rxerror & alignmentError)					ether->frames++;				if(rxerror & crcError)					ether->crcs++;			}		}		/*		 * If there was an error or a new receive buffer can't be		 * allocated, discard the packet and go on to the next.		 */		if((rxstatus & rxError) || (bp = rbpalloc(iallocb)) == 0){			COMMAND(port, RxDiscard, 0);			while(STATUS(port) & commandInProgress)				;			if(ctlr->busmaster == 1)				startdma(ether, PADDR(ctlr->rbp->rp));			continue;		}		/*		 * A valid receive packet awaits:		 *	if using PIO, read it into the buffer;		 *	discard the packet from the FIFO;		 *	if using busmastering, start a new transfer for		 *	  the next packet and as a side-effect get the		 *	  end-pointer of the one just received;		 *	pass the packet on to whoever wants it.		 */		if(ctlr->busmaster == 0 || ctlr->busmaster == 2){			len = (rxstatus & rxBytes9);			ctlr->rbp->wp = ctlr->rbp->rp + len;			insl(port+Fifo, ctlr->rbp->rp, HOWMANY(len, 4));		}		COMMAND(port, RxDiscard, 0);		while(STATUS(port) & commandInProgress)			;		if(ctlr->busmaster == 1)			ctlr->rbp->wp = startdma(ether, PADDR(bp->rp));		etheriq(ether, ctlr->rbp, 1);		ctlr->rbp = bp;	}}static voidinterrupt(Ureg*, void* arg){	Ether *ether;	int port, status, s, w, x;	Ctlr *ctlr;	ether = arg;	port = ether->port;	ctlr = ether->ctlr;	ilock(&ctlr->wlock);	w = (STATUS(port)>>13) & 0x07;	COMMAND(port, SelectRegisterWindow, Wop);	ctlr->interrupts++;	ctlr->timer += inb(port+Timer) & 0xFF;	while((status = STATUS(port)) & (interruptMask|interruptLatch)){		if(status & hostError){			/*			 * Adapter failure, try to find out why, reset if			 * necessary. What happens if Tx is active and a reset			 * occurs, need to retransmit? This probably isn't right.			 */			COMMAND(port, SelectRegisterWindow, Wdiagnostic);			x = ins(port+FifoDiagnostic);			COMMAND(port, SelectRegisterWindow, Wop);			print("#l%d: status 0x%uX, diag 0x%uX\n",			    ether->ctlrno, status, x);			if(x & txOverrun){				if(ctlr->busmaster == 0)					COMMAND(port, TxReset, 0);				else					COMMAND(port, TxReset, (updnReset|dmaReset));				COMMAND(port, TxEnable, 0);			}			if(x & rxUnderrun){				/*				 * This shouldn't happen...				 * Reset the receiver and restore the filter and RxEarly				 * threshold before re-enabling.				 * Need to restart any busmastering?				 */				COMMAND(port, SelectRegisterWindow, Wstate);				s = (port+RxFilter) & 0x000F;				COMMAND(port, SelectRegisterWindow, Wop);				COMMAND(port, RxReset, 0);				while(STATUS(port) & commandInProgress)					;				COMMAND(port, SetRxFilter, s);				COMMAND(port, SetRxEarlyThresh, ctlr->rxearly>>ctlr->ts);				COMMAND(port, RxEnable, 0);			}			status &= ~hostError;		}		if(status & (transferInt|rxComplete)){			receive(ether);			status &= ~(transferInt|rxComplete);		}		if(status & (upComplete)){

⌨️ 快捷键说明

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