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

📄 if_le.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
字号:
#ifndef LEBOOT#ifndef lintstatic        char sccsid[] = "@(#)if_le.c 1.1 92/07/30 SMI";#endif#endif#ifndef sun2/* * For Sun-3/25 debugging we want DEBUG on.  For production, turn it off. *//* #define DEBUG *//* #define DEBUG1 */#define LANCEBUG 1	/* Rev C Lance chip bug *//*  * Parameters controlling TIMEBOMB action: times out if chip hangs. * */#define	TIMEBOMB	1000000	/* One million times around is all... *//* * Sun Lance Ethernet Controller interface */#include <stand/saio.h>#include <stand/param.h>#include <sys/socket.h>#include <sunif/if_lereg.h>#include <net/if.h>#include <netinet/in.h>#include <netinet/if_ether.h>#include <mon/idprom.h>#include <mon/cpu.map.h>#ifdef sun3x#include <mon/cpu.addrs.h>#endif/* Determine whether we are PROM or not. */#ifdef LEBOOT#define PROM#endif LEBOOTint	lancexmit(), lancepoll(), lancereset(), myetheraddr(), lancestats();struct saif leif = {	lancexmit,	lancepoll,	lancereset,	myetheraddr,	lancestats};#define	LANCERBUFSIZ	1600#define	LANCETBUFSIZ	1600#define	LANCERBUFFS	8	/* how many receive buffs */struct lance_softc {	char		es_scrat[PROTOSCRATCH];	/* work space for nd */	struct le_device    	*es_lance;	/* Device register address */	struct ether_addr	es_enaddr;	/* Our Ethernet address */	struct le_init_block	es_ib;		/* Initialization block */	struct le_md		*es_rmdp[LANCERBUFFS];	/* Receive Desc Ring					 		ptrs */	struct le_md		*es_tmdp;	/* Transmit Desc Ring ptr */	u_char			es_rbuf[LANCERBUFFS][LANCERBUFSIZ]; /* Receive							 Buffers */#ifndef PROM	u_char			es_tbuf[LANCETBUFSIZ];	/* Transmit Buffer */#endif	PROM	int			es_next_rmd;	/* Next descriptor in ring */	/*	 * The transmit and receive ring descriptors.  The es_{r,t}mdp	 * entries point into these arrays.  We allocate an extra one of	 * each so that we can guarantee 8-byte alignment.  (That is, we	 * don't necessarily point locations an integral number of le_mds	 * from the start of the arrays.	 */	struct le_md		es_rmd[LANCERBUFFS+1],				es_tmd[2];};/* * Need to initialize the Ethernet control reg to: *	Reset is active *	Loopback is NOT active *	Interrupt enable is not active. */#ifdef sun3xu_long lancestd[] = {pa_AMD_ETHER};#elseu_long lancestd[] = {VIOPG_AMD_ETHER << BYTES_PG_SHIFT};#endifstruct devinfo lanceinfo = {	sizeof (struct le_device),	sizeof (struct lance_softc),	0,				/* Local bytes (we use dma) */	1,				/* Standard addr count */	lancestd,			/* Standard addrs */	MAP_OBIO,			/* Device type */	0,				/* transfer size handled by ND */};int lanceprobe(), xxboot(), lanceopen(), lanceclose(), etherstrategy();int nullsys();struct boottab ledriver = {	"le", lanceprobe, xxboot, lanceopen, lanceclose,	etherstrategy, "le: Sun/Lance Ethernet", &lanceinfo,};extern struct ether_addr etherbroadcastaddr;/* Statistics counters for lancestats() */static struct {	int	ipackets;	int	opackets;	int	collis;	int	defer;	int	crcerrs;	int	framerrs;	int	missed;	int	ofloerrs;	int	ufloerrs;} stats;/* * Probe for device. * Must return -1 for failure for monitor probe *//*ARGSUSED*/intlanceprobe(sip)	struct saioreq *sip;{	struct idprom id;	if (IDFORM_1 == idprom(IDFORM_1, &id) &&	       (id.id_machine == IDM_SUN3_M25 || 		id.id_machine == IDM_SUN3_F ||		id.id_machine == IDM_SUN3X_HYDRA ||		id.id_machine == IDM_SUN4_STINGRAY))		return (0);	else		return (-1);}/* * Open Lance Ethernet nd connection, return -1 for errors. */lanceopen(sip)	struct saioreq *sip;{	register int result;#ifdef DEBUG1	printf("le: lanceopen[\n");#endif	sip->si_sif = &leif;	if ( lanceinit(sip) || (result = etheropen(sip)) < 0 ) {		lanceclose(sip);		/* Make sure we kill chip */#ifdef DEBUG1		printf("le: lanceopen --> -1\n");#endif		return (-1);	}#ifdef DEBUG1	printf("le: lanceopen --> %x\n", result);#endif	return (result);}/* * Set up memory maps and Ethernet chip. * Returns 1 for error (after printing message), 0 for ok. *//*ARGSUSED*/intlanceinit(sip)	struct saioreq *sip;{	register struct lance_softc *es;	struct idprom id;		/* 	 * Our locals were obtined from DMA space, now put the locals	 * pointer in the standard place.  This is OK since close()	 * will only deallocate from devdata if its size in devinfo is >0.	 */	es = (struct lance_softc *)sip->si_dmaaddr;	sip->si_devdata = (caddr_t)es;	es->es_lance = (struct le_device *) sip->si_devaddr;	if (IDFORM_1 != idprom(IDFORM_1, &id)) {		printf("le: No ID PROM\n");		return 1;	}	return lancereset(es, sip);}/* * Basic Lance initialization * Returns 1 for error (after printing message), 0 for ok. *//*ARGSUSED*/intlancereset(es, sip)	register struct lance_softc *es;	struct saioreq *sip;{	register struct le_device *le = es->es_lance;	register struct le_init_block *ib = &es->es_ib;	struct idprom id;	int timeout = TIMEBOMB;	int	i;#ifdef DEBUG1	printf("le: lancereset(%x, %x)\n", es, sip);#endif	/* Reset the chip */	le->le_rap = LE_CSR0;	le->le_csr = LE_STOP;	/* Perform the basic initialization */		/* Construct the initialization block */	bzero((caddr_t)&es->es_ib, sizeof (struct le_init_block));	/* Leave the mode word 0 for normal operating mode */	myetheraddr(&es->es_enaddr);	/* Oh, for a consistent byte ordering among processors */	ib->ib_padr[0] = es->es_enaddr.ether_addr_octet[1];	ib->ib_padr[1] = es->es_enaddr.ether_addr_octet[0];	ib->ib_padr[2] = es->es_enaddr.ether_addr_octet[3];	ib->ib_padr[3] = es->es_enaddr.ether_addr_octet[2];	ib->ib_padr[4] = es->es_enaddr.ether_addr_octet[5];	ib->ib_padr[5] = es->es_enaddr.ether_addr_octet[4];	/* Leave address filter 0 -- we don't want Multicast packets */	/*	 * Set up transmit and receive ring pointers,	 * taking the 8-byte alignment requirement into account.	 */	es->es_rmdp[0] = (struct le_md *) ((u_long)(&es->es_rmd[0]) & ~07) + 1;	for (i = 1; i < LANCERBUFFS; i++)		es->es_rmdp[i] = es->es_rmdp[i-1] + 1;	es->es_tmdp    = (struct le_md *) ((u_long)(&es->es_tmd[0]) & ~07) + 1;	ib->ib_rdrp.drp_laddr = (long)es->es_rmdp[0];	ib->ib_rdrp.drp_haddr = (long)es->es_rmdp[0] >> 16;	ib->ib_rdrp.drp_len  = 3;   /* 2 to the 1 power = 2 */		ib->ib_tdrp.drp_laddr = (long)es->es_tmdp;	ib->ib_tdrp.drp_haddr = (long)es->es_tmdp >> 16;	ib->ib_tdrp.drp_len  = 0;   /* 2 to the 0 power = 1 */	/* Clear all the descriptors */	bzero((caddr_t)es->es_rmdp[0], LANCERBUFFS * sizeof (struct le_md));	bzero((caddr_t)es->es_tmdp, sizeof (struct le_md));	/* Give the init block to the chip */	le->le_rap = LE_CSR1;	/* select the low address register */	le->le_rdp = (long)ib & 0xffff;	le->le_rap = LE_CSR2;	/* select the high address register */	le->le_rdp = ((long)ib >> 16) & 0xff;	if (IDFORM_1 != idprom(IDFORM_1, &id)) {		printf("le: No ID PROM\n");		return 1;	}	le->le_rap = LE_CSR3;	/* Bus Master control register */	if (id.id_machine == IDM_SUN4_STINGRAY || id.id_machine == IDM_SUN3X_HYDRA )		le->le_rdp = LE_BSWP+LE_ACON+LE_BCON;	else		le->le_rdp = LE_BSWP;	le->le_rap = LE_CSR0;	/* main control/status register */	le->le_csr = LE_INIT;	while( ! (le->le_csr & LE_IDON) ) {		if (timeout-- <= 0) {		    printf("le: cannot initialize\n");		    return (1);		}	}	le->le_csr = LE_IDON;	/* Clear the indication */	/* Hang out the receive buffers */	es->es_next_rmd = 0;	for (i = 0; i < LANCERBUFFS; i++)		install_buf_in_rmd(es->es_rbuf[i], es->es_rmdp[i]);	le->le_csr = LE_STRT;#ifdef DEBUG1	printf("le: lancereset returns OK\n");#endif	return 0;		/* It all worked! */}install_buf_in_rmd(buffer, rmd)	u_char *buffer;	register struct le_md *rmd;{	rmd->lmd_ladr = (u_short)buffer;	rmd->lmd_hadr = (long)buffer >> 16;	rmd->lmd_bcnt = -LANCERBUFSIZ;	rmd->lmd_mcnt = 0;	rmd->lmd_flags = LMD_OWN;}/* * Transmit a packet. * If possible, just points to the packet without copying it anywhere. */lancexmit(es, buf, count)	register struct lance_softc *es;	char *buf;	int count;{	register struct le_device *le = es->es_lance;	struct le_md *tmd = es->es_tmdp; /* Transmit Msg. Descriptor */	caddr_t tbuf;	int timeout = TIMEBOMB;#ifdef DEBUG2	printf( "xmit np_blkno %x\n",		((struct ndpack *)(buf+14))->np_blkno);#endif	/*	 * We assume the buffer is in an area accessible by the chip.	 * The caller of xmit is currently ndxmit(), which only sends	 * an nd structure, which we happen to know is allocated in the	 * right area (in fact, it's part of the struct nd which	 * is the first thing in our own es structure).  If we wish to	 * use xmit for some other purpose, the buffer might not be	 * accessible by the chip, so to be general we ought to copy	 * into some accessible place.  HOWEVER, PROM space is really tight,	 * so this generality is not free.	 */#ifdef PROM	tbuf = buf;#else  PROM/* FIXME, constant address masks here! */#ifdef sun3x        if ( ((int)buf & 0xFF000000) == 0xFF000000) { /* we can point to it*/#else	if ( ((int)buf & 0x0F000000) == 0x0F000000) { /* we can point to it */#endif sun3x	    tbuf = buf;	} else {	    tbuf = (caddr_t)es->es_tbuf;	    bcopy((caddr_t)buf, tbuf, count);	}#endif PROM		tmd->lmd_hadr = (int)tbuf >> 16;	tmd->lmd_ladr = (u_short) tbuf;	tmd->lmd_bcnt = -count;	#ifdef notdef	if (tmd->lmd_bcnt < -MINPACKET)	    tmd->lmd_bcnt = -MINPACKET;#endif	tmd->lmd_flags3 = 0;	tmd->lmd_flags = LMD_STP | LMD_ENP | LMD_OWN;		le->le_rap = LE_CSR0;	le->le_csr = LE_TDMD;	do {	    if ( le->le_csr & LE_TINT ) {		le->le_csr = LE_TINT; /* Clear interrupt */		break;	    }	} while ( --timeout > 0);	if (tmd->lmd_flags & TMD_DEF)		stats.defer++;	if (tmd->lmd_flags & TMD_ONE)		stats.collis++;	else if (tmd->lmd_flags & TMD_MORE)		stats.collis += 2;	if (tmd->lmd_flags3 & TMD_UFLO)		stats.ufloerrs++;	if (tmd->lmd_flags3 & TMD_LCAR)		printf("le: Ethernet cable problem\n");	if ( (tmd->lmd_flags & LMD_ERR)	||   (tmd->lmd_flags3 & TMD_BUFF)	||   (timeout <= 0) ) {#ifdef DEBUG		printf("le: xmit failed - tmd1 flags %x tmd3 %x\n",	       		tmd->lmd_flags, tmd->lmd_flags3);#endif		return (1);	}	stats.opackets++;	return (0);}intlancepoll(es, buf)	register struct lance_softc *es;	char *buf;{	register struct le_device *le = es->es_lance;	register struct le_md *rmd;	register struct ether_header *header;	int length;#ifdef never	register struct le_md *next_rmd;#endif never#ifdef DEBUG1	printf("le: poll\n");#endif	le->le_rap = LE_CSR0;	if ( ! (le->le_csr & LE_RINT)  ) {		rmd = es->es_rmdp[es->es_next_rmd];		if ((rmd->lmd_flags & LMD_OWN) == 0) {#ifdef never			printf ("le: one waiting 0x%x\n",			    rmd->lmd_mcnt - 4);#endif never			goto cheat;		}		return (0);		/* No packet yet */	}cheat:	stats.ipackets++;	if (le->le_csr & LE_MISS) {#ifdef DEBUG1		printf ("le: missed packet\n");#endif DEBUG		stats.missed++;		le->le_csr |= LE_MISS;	}#ifdef DEBUG1	printf("le: received packet\n");#endif	le->le_csr = LE_RINT; 		/* Clear interrupt */	rmd = es->es_rmdp[es->es_next_rmd];	if (rmd->lmd_flags & RMD_OFLO)		stats.ofloerrs++;	else {		if ((rmd->lmd_flags & RMD_FRAM) && (rmd->lmd_flags & LMD_ENP))			stats.framerrs++;		if ((rmd->lmd_flags & RMD_CRC) && (rmd->lmd_flags & LMD_ENP))			stats.crcerrs++;	}	if ( (rmd->lmd_flags & ~RMD_OFLO) != (LMD_STP|LMD_ENP) ) {#ifdef DEBUG		printf("Receive packet error - rmd flags %x\n",rmd->lmd_flags);#endif		length = 0;		goto restorebuf;	}	/* Get input data length and a pointer to the ethernet header */	length = rmd->lmd_mcnt - 4;	/* don't count the 4 CRC bytes */	header = (struct ether_header *)es->es_rbuf[es->es_next_rmd];#ifdef LANCEBUG	/*	 * Check for unreported packet errors.  Rev C of the LANCE chip	 * has a bug which can cause "random" bytes to be prepended to	 * the start of the packet.  The work-around is to make sure that	 * the Ethernet destination address in the packet matches our	 * address.	 */#define ether_addr_not_equal(a,b)	\	(  ( *(short *)(&a.ether_addr_octet[0]) != \	     *(short *)(&b.ether_addr_octet[0]) )  \	|| ( *(short *)(&a.ether_addr_octet[2]) != \	     *(short *)(&b.ether_addr_octet[2]) )  \	|| ( *(short *)(&a.ether_addr_octet[4]) != \	     *(short *)(&b.ether_addr_octet[4]) )  \	)    	if( ether_addr_not_equal(header->ether_dhost, es->es_enaddr)	&&  ether_addr_not_equal(header->ether_dhost, etherbroadcastaddr) ) {		printf("le: LANCE Rev C Extra Byte(s) bug; Packet punted\n");		length = 0;		/* Don't return directly; restore the buffer first */	}#endif LANCEBUG#ifdef DEBUG2    	if( header->ether_dhost.ether_addr_octet[0] == 0xff )		printf("Broadcast packet\n");	else	printf("recv np_blkno %x\n",	        	((struct ndpack *)(buf+14))->np_blkno);#endif		/* Copy packet to user's buffer */	if ( length > 0 )		bcopy((caddr_t)header, buf, length);restorebuf:	rmd->lmd_mcnt = 0;	rmd->lmd_flags = LMD_OWN;	/* Get ready to use the other buffer next time */	/* What about errors ? */	es->es_next_rmd =	    (es->es_next_rmd == (LANCERBUFFS - 1)) ? 0 : es->es_next_rmd + 1;#ifdef never	next_rmd = es->es_rmdp[es->es_next_rmd];	if ((next_rmd->lmd_flags & LMD_OWN) == 0)		printf ("le: one waiting\n");#endif never	return (length);}/* * Close down Lance Ethernet device. * On the Model 25, we reset the chip and take it off the wire, since * it is sharing main memory with us (occasionally reading and writing), * and most programs don't know how to deal with that -- they just assume * that main memory is theirs to play with. */lanceclose(sip)	struct saioreq *sip;{	struct lance_softc *es = (struct lance_softc *) sip->si_devdata;	struct le_device *le = es->es_lance;	/* Reset the chip */	le->le_rap = LE_CSR0;	le->le_csr = LE_STOP;}lancestats(){	printf("le:  ipackets %d opackets %d collis %d defer %d crcerrs %d framerrs %d missed %d ofloerrs %d ufloerrs %d\n",		stats.ipackets,		stats.opackets,		stats.collis,		stats.defer,		stats.crcerrs,		stats.framerrs,		stats.missed,		stats.ofloerrs,		stats.ufloerrs);}#endif !sun2

⌨️ 快捷键说明

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