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

📄 if_ie.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
	bzero(es->es_rfdtab, (IENRBUF * sizeof (struct ierfd)));	bzero(es->es_rbdtab, (IENRBUF * sizeof (struct ierbd)));	/*	 * Walk through the rfd ring and rbd table initializing each.	 */	for (i = 0; i < IENRBUF; i++) {		rfd = &es->es_rfdtab[i];		rbd = &es->es_rbdtab[i];		rbuf = es->es_rbufs[i];		rfd->ierfd_next = to_ieoff(es, (caddr_t) nextrfd(es, rfd));		rfd->ierfd_rbd = to_ieoff(es, (caddr_t) rbd);		rbd->ierbd_next = -1;	/* not used since el is 1 */		rbd->ierbd_el = 1;		rbd->ierbd_buf = to_ieaddr(es, rbuf);		rbd->ierbd_sizehi = IERBUFSIZ >> 8;		rbd->ierbd_sizelo = IERBUFSIZ & 0xFF;	}	rfd = &es->es_rfdtab[IENRBUF-1];	rfd->ierfd_next = to_ieoff(es, (caddr_t) &es->es_rfdtab[0]);	rfd->ierfd_el = 1;	/*	 *	Set the head rfd pointer.	 */	es->es_rfdhd = &es->es_rfdtab[0];}/* * Initialize and start the Receive Unit */intierustart(es)	register struct ie_softc *es;{	register struct iescb *scb = &es->es_scb;	int timebomb = TIMEBOMB;	if (scb->ie_rus == IERUS_READY)	{		return OK;	}	while (scb->ie_cmd != 0)	/* XXX */		if (timebomb-- <= 0) return TIMEOUT;	/*	 * Start the RU.	 */	scb->ie_rfa = to_ieoff(es, (caddr_t) es->es_rfdhd);	scb->ie_cmd = IECMD_RU_START;	ieca(es);	return OK;}ieca(es)	register struct ie_softc *es;{	switch (es->es_type) {	case IE_OB:		es->es_obie->obie_ca = 1;		es->es_obie->obie_ca = 0;		break;	case IE_MB:		{		register struct mie_device *mie;		mie = (struct mie_device *)ie_getval(&es->es_mie);		mie->mie_ca = 1;		mie->mie_ca = 0;		}		break;	case IE_TE:		es->es_tie->tie_ca = 1;		es->es_tie->tie_ca = 0;		break;	default:		break;	}}intiesimple(es, cb)	register struct ie_softc *es;	register struct iecb *cb;{	register struct iescb *scb = &es->es_scb;	register timebomb = TIMEBOMB;#if defined(sun4)	/*	 * Sunray must use IO Cache.  Flush the outgoing ethernet line.	 * This insures that the buffers we are about to add to the queue	 * are not already in the I/O cache.	 * 	 * XXX -- not positive that this is necessary.	 */	if ((id.id_machine == IDM_SUN4_SUNRAY) && (es->es_type == IE_OB)){		ioc_flush(IOC_ETHER_OUT);	}#endif /* sun4 */	*(short *)cb = 0;	/* clear status bits */	cb->iec_el = 1;	cb->iec_next = 0;	/* start CU */	while (scb->ie_cmd != 0)	/* XXX */		if (timebomb-- <= 0) return TIMEOUT;	scb->ie_cbl = to_ieoff(es, (caddr_t)cb);	scb->ie_cmd = IECMD_CU_START;	if (scb->ie_cx)		scb->ie_cmd |= IECMD_ACK_CX;	if (scb->ie_cnr)		scb->ie_cmd |= IECMD_ACK_CNR;	ieca(es);	while (!cb->iec_done)		/* XXX */		if (timebomb-- <= 0) return TIMEOUT;	while (scb->ie_cmd != 0)	/* XXX */		if (timebomb-- <= 0) return TIMEOUT;	if (scb->ie_cx)		scb->ie_cmd |= IECMD_ACK_CX;	if (scb->ie_cnr)		scb->ie_cmd |= IECMD_ACK_CNR;	ieca(es);	return OK;} /* * Transmit a packet. * Always copy the packet for the sake of Multibus * boards and Sun3's.  This is not a performance critical situation */iexmit(es, buf, count)	register struct ie_softc *es;	char *buf;	int count;{	register struct ietbd *tbd = &es->es_tbd;	register struct ietfd *td = &es->es_tfd;	bzero((caddr_t)tbd, sizeof *tbd);	tbd->ietbd_eof = 1;	tbd->ietbd_cntlo = count & 0xFF;	tbd->ietbd_cnthi = count >> 8;	bcopy(buf, es->es_xbuf, count);	if (es->es_type == IE_MB){	/* this is a macro */		put_ieaddr((es->es_xbuf - (caddr_t)es), &(tbd->ietbd_buf));	}else		tbd->ietbd_buf = to_ieaddr(es, es->es_xbuf);	td->ietfd_tbd = to_ieoff(es, (caddr_t)tbd);	td->ietfd_cmd = IE_TRANSMIT;	if (iesimple(es, (struct iecb *)td)) {		printf("ie: xmit hang\n");		return -1;	}	stats.collis += td->ietfd_ncoll;	if (td->ietfd_ok) {		stats.opackets++;		stats.defer += td->ietfd_defer;		return (0);	}	if (td->ietfd_xcoll || td->ietfd_nocarr || td->ietfd_nocts)		printf("ie: Ethernet cable problem\n");	if (td->ietfd_underrun)		stats.urunerrs++;	return (-1);}intiepoll(es, buf)	register struct ie_softc *es;	char *buf;{	register struct ierfd *rfd;	register struct ierbd *rbd;	register char	*rbuf;	register struct iescb *scb = &es->es_scb;	int	i;	int len;	int timebomb = TIMEBOMB;	/*	 * Cheat.  Depend on the fact that rfd-->rbd-->rbuf use same indices.	 */	rfd = es->es_rfdhd;	i = (int) (rfd - es->es_rfdtab);	rbd = &es->es_rbdtab[i];	rbuf = es->es_rbufs[i];		/* update cumulative statistics */	stats.crcerrs = from_ieint(scb->ie_crcerrs);	stats.alnerrs = from_ieint(scb->ie_alnerrs);	stats.rscerrs = from_ieint(scb->ie_rscerrs);	stats.orunerrs = from_ieint(scb->ie_ovrnerrs);	if (!rfd->ierfd_done)		return (0);		/* no packet yet */	/*	 * We got a packet.	 */	stats.ipackets++;	if (rbd->ierbd_eof) {	/* good packet */#ifdef sun4		/*		 * For sunray IO Cache, flush the incoming ethernet		 * line. This insures that the buffer we are about to		 * look at is not still in the I/O cache.		 */#if defined(IOC_RBUF)		if ((id.id_machine == IDM_SUN4_SUNRAY) &&			(es->es_type == IE_OB))		{			ioc_flush(IOC_ETHER_IN);		}#endif IOC_RBUF#endif sun4		len = (rbd->ierbd_cnthi << 8) + rbd->ierbd_cntlo;		bcopy(rbuf, buf, len);	}	/*	 * Reinitialize rfd and increment rfd ring head pointer.	 */	rbd->ierbd_sizehi = IERBUFSIZ >> 8;	rbd->ierbd_sizelo = IERBUFSIZ & 0xFF;	rfd->ierfd_el = 1;	prevrfd(es, es->es_rfdhd)->ierfd_el = 0;	es->es_rfdhd = nextrfd(es, es->es_rfdhd);		/*	 * Acknowledge frame reception and prod the chip for more.	 */	while (scb->ie_cmd != 0)	/* XXX */		if (timebomb-- <= 0) return TIMEOUT;	if (scb->ie_fr)		scb->ie_cmd |= IECMD_ACK_FR;	if (scb->ie_rnr)		scb->ie_cmd |= IECMD_ACK_RNR;	ieca(es);	ierustart(es);	return (len);}/* * Convert a CPU virtual address into an Ethernet virtual address. * * For Multibus, we assume it's in the Ethernet's memory space, and we * just subtract off the start of the memory space (==es).  For Model 50, * the Ethernet chip has full access to supervisor virtual memory. * For Carrera, the chip can access the top 16MB of virtual memory, * but we never give it addresses outside that range, so the high * order bits can be ignored. */ieaddr_tto_ieaddr(es, cp)	struct ie_softc *es;	caddr_t cp;{	union {		int	n;		char	c[4];	} a, b;#ifdef sun3#ifdef DEBUG	if ((es->es_type != IE_TE) &&	    (cp < (char *)0x0F000000 || cp >= (char *)0x10000000)) {		/* printf("Bad ptr to_ieaddr(%x)\n", cp); */		;  asm(" .word 0xFFFF") ; ;	}#endif DEBUG#endif sun3	switch (es->es_type) {	case IE_MB:	case IE_TE:		a.n = cp - (caddr_t)es;		break;	case IE_OB:		a.n = (int)cp;		break;	default:		break;	}	b.c[0] = a.c[3];	b.c[1] = a.c[2];	b.c[2] = a.c[1];	b.c[3] = 0;	return (b.n);}/* * Convert a CPU virtual address into a 16-bit offset for the Ethernet * chip. * * This is the same for Onboard and Multibus, since the offset is based * on the absolute address supplied in the initial system configuration * block -- which we customize for Multibus or Onboard. */ieoff_tto_ieoff(es, addr)	register struct ie_softc *es;	caddr_t addr;{	union {		short	s;		char	c[2];	} a, b;	a.s = (short)(addr - (caddr_t)es);	b.c[0] = a.c[1];	b.c[1] = a.c[0];	return (b.s);}ieint_tfrom_ieint(n)	short n;{	union {		short	s;		char	c[2];	} a, b;	a.s = n;	b.c[0] = a.c[1];	b.c[1] = a.c[0];	return (b.s);}/* * Set default configuration parameters * As spec'd by Intel, except acloc == 1 for header in data */iedefaultconf(ic)	register struct ieconf *ic;{	bzero((caddr_t)ic, sizeof (struct ieconf));	ic->ieconf_cb.iec_cmd = IE_CONFIG;	ic->ieconf_bytes = 12;	ic->ieconf_fifolim = 8;	ic->ieconf_pream = 2;		/* 8 byte preamble */	ic->ieconf_alen = 6;	ic->ieconf_acloc = 1;	ic->ieconf_space = 96;	ic->ieconf_slttmh = 512 >> 8;	ic->ieconf_minfrm = 64;	ic->ieconf_retry = 15;}/* * Close down intel ethernet device. * On the Model 50, 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. */ieclose(sip)	struct saioreq *sip;{	register struct ie_softc *es = (struct ie_softc *) sip->si_devdata;	if (es->es_type == IE_OB) {		*es->es_obie = obie_reset;	}}iestats(){	printf("ie:  ipackets %d opackets %d collis %d defer %d crcerrs %d alnerrs %d rscerrs %d orunerrs %d urunerrs %d\n",		stats.ipackets,		stats.opackets,		stats.collis,		stats.defer,		stats.crcerrs,		stats.alnerrs,		stats.rscerrs,		stats.orunerrs,		stats.urunerrs);}/* * used to store controller address so we only have to pass around * a pointer to ie_softc */ie_putval(val, where){	register u_short *cp;	union {		u_int 	n;		u_short	s[2];	} a;	a.n = (u_int)val;	cp = (u_short *)(where);	cp[0] = a.s[0];	cp[1] = a.s[1];}ie_getval(where){	register u_short *cp;	union {		u_int 	n;		u_short	s[2];	} a;	register int x;	cp = (u_short *)(where);	a.s[0] = cp[0];	a.s[1] = cp[1];	x = a.n;	return (x);}#if defined(sun4)/* * map sunray static RAM to IOC_IEDESCR_ADDR. * set the tags and zero out the descriptor RAM. */sunray_ioc_init(){	register u_long *p;	register u_long tag;	/*	 * map in tags and initialize them	 * we use the flush virtual address temporarily	 * since we normally don't touch the tags or data	 * once the i/o cache is initialized	 */	setpgmap((addr_t)IOC_FLUSH_ADDR,		PG_V | PG_KW | PGT_OBIO | btop(OBIO_IOCDATA_ADDR));	/* zero both data and tag */        for (p = (u_long *)IOC_FLUSH_ADDR;	     (u_long)p != IOC_FLUSH_ADDR+0x2000;	     p++)                *p = 0;	/*	 * Initialize the ram and tags we are going to use	 * to hold the ethernet decriptors.	 */	setpgmap((addr_t)IOC_IEDESCR_ADDR,		PG_V | PG_KW | PGT_OBIO | btop(OBIO_DESCR_DATA_ADDR));	/* zero descriptor data */	for (	p = (u_long *)IOC_IEDESCR_ADDR;		(u_long)p < IOC_IEDESCR_ADDR + 0x1000;		p++ )			*p = 0;	/*	 * Initialize descriptor tags,	 * Bit 0 is the modified bit, bit 1 is the valid bit.	 * Bits 2-4 aren't used and the rest are virtual address bits.	 */	for ( p = (u_long *)(IOC_IEDESCR_ADDR+0x1000), tag = IOC_IEDESCR_ADDR+3;		(u_long)p < IOC_IEDESCR_ADDR + PAGESIZE; ) {			*p = tag;			p++;			if ((p != (u_long *)(IOC_IEDESCR_ADDR+0x1000)) &&			    (((u_long)p%32) == 0))				tag += IOC_LINESIZE;	}	/* map in flush page for i/o cache */	setpgmap((addr_t)IOC_FLUSH_ADDR,		PG_V | PG_KW | PGT_OBIO | btop(OBIO_IOCFLUSH_ADDR));		/* XXX - for debugging only,  remove later */	setpgmap((addr_t)IOC_DATA_ADDR,		PG_V | PG_KW | PGT_OBIO | btop(OBIO_IOCDATA_ADDR));	/* turn on the i/o cache */	sys_enable(ENA_IOCACHE);}#define SUNRAY_IE_DMA	(1<<23 | 1<<15)		/* 0x00808000 *//* * On a Sunray, if the 82586 issues a VA with both these * bits set, and the pg_ioc bit is set in the pte, then * the access will go to the on board descriptor RAM, not * the IO Cached buffer in main memory. * Since rbufs and xbuf don't fit in descriptor RAM * and they must be IO Cached on Sunray, * we must put them in memory address where both * these bits are not simultaneously set. */char *alloc_sunray_page(){        char *addr;	int max;#if defined(IOC_RBUF)	register u_int *p;	struct pte pte;	p = (u_int *)&pte;#endif IOC_RBUF#define MAX_WASTE 4	/* 4 consecutive pages have VA[15] set */	for(max = 0; max <= MAX_WASTE; ++max)	{		addr = resalloc(RES_DMAMEM, PAGESIZE);		if(((u_int)addr & SUNRAY_IE_DMA) != SUNRAY_IE_DMA)			break;	/* address ok */	}	if(max > MAX_WASTE)		panic("ie: can't allocate legal sunray ethernet buffer.");#if defined(IOC_RBUF)	*p = getpgmap(addr);	pte.pg_ioc = 1;	setpgmap(addr, *p);#endif IOC_RBUF	return(addr);}#ifdef DEBUG/* * alloc_sanity() * * Sanity check addresses of xbuf and rbufs * to make sure that 586 can reach them, * and in the case of Sunray, that the VA's are legal */alloc_sanity(es)register struct ie_softc *es;{	u_int death = 0;	int i;	if(id.id_machine == IDM_SUN4_SUNRAY)	{		/* Sanity check Sunray addresses */		if(((u_int)es->es_xbuf & SUNRAY_IE_DMA) == SUNRAY_IE_DMA)		{			printf("alloc_sanity: xbuf = 0x%x\n", es->es_xbuf);			death++;		}		for (i = 0; i < IENRBUF ; ++i)		{			if(((u_int)es->es_rbufs[i] & SUNRAY_IE_DMA) == SUNRAY_IE_DMA)			{				printf("alloc_sanity: es_rbufs[%d]=0x%x\n",							i, es->es_rbufs[i]);				death++;			}		}		if(death)			panic("alloc_sanity: illegal Sunray 85286 buffers");	}	/* sanity check that the 82586 can actually reach the buffers */	if(((u_int)(es->es_xbuf) & IEDMABASE) != IEDMABASE)	{		printf("alloc_sanity: es_xbuf=0x%x\n", es->es_xbuf);		death++;	}	for (i = 0; i < IENRBUF ; ++i)	{		if(((u_int)(es->es_rbufs[i]) & IEDMABASE) != IEDMABASE)		{			printf("alloc_sanity: rbufs[%d]=0x%x\n",					i, es->es_rbufs[i]);			death++;		}	}	if(death)		panic("alloc_sanity: buffers can't be addressed by 82586.");}#endif  DEBUG/* * ieallocbufs() * Allocates xbuf and rbufs, and initializes * es->es_xbuf and es->es_rbufs[] appropriately. * * Knows about Sunray IO Cache requirements. *  * no return value. */voidieallocbufs(es)register struct ie_softc *es;{	int rbuf;	char *addr;	if(es->es_xbuf) /* been here already */	{		return;	}	/* Receive Buffers */#define RBUFPERPAGE	(PAGESIZE / IERBUFSIZ)	for (rbuf = 0;  rbuf < IENRBUF; rbuf += RBUFPERPAGE)	{		int i;		if(id.id_machine == IDM_SUN4_SUNRAY)			addr = alloc_sunray_page();		else			addr = resalloc(RES_DMAMEM, PAGESIZE);		for(i = 0; (i < RBUFPERPAGE) && ((rbuf + i) < IENRBUF); ++i)		{			es->es_rbufs[rbuf + i] = addr + (i * IERBUFSIZ);			if(verbosemode)				printf("  ieallocbufs() es_rbufs[%d]=0x%x\n",					rbuf + i, es->es_rbufs[rbuf + i]);		}	}	/* Transmit Buffer */	if(id.id_machine == IDM_SUN4_SUNRAY)	{#if !defined(IOC_RBUF)		register u_int *p;		struct pte pte;		p = (u_int *)&pte;#endif !IOC_RBUF		es->es_xbuf =  alloc_sunray_page();#if !defined(IOC_RBUF)		*p = getpgmap(es->es_xbuf);		pte.pg_ioc = 1;		setpgmap(es->es_xbuf, *p);#endif !IOC_RBUF	}	else		es->es_xbuf =  resalloc(RES_DMAMEM, PAGESIZE);#if defined(DEBUG)	alloc_sanity(es);#endif DEBUG}#endif sun4#endif !sun4c	/* top of file */

⌨️ 快捷键说明

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