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

📄 if_ex.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Excelan Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)if_ex.c	7.5 (Berkeley) 12/16/90 */#include "ex.h"#if	NEX > 0 /* * Excelan EXOS 202(VME) & 203(QBUS) Link Level Ethernet Interface Drivers */#include "sys/param.h"#include "sys/systm.h"#include "sys/mbuf.h"#include "sys/buf.h"#include "sys/protosw.h"#include "sys/socket.h"#include "sys/vmmac.h"#include "sys/ioctl.h"#include "sys/errno.h"#include "sys/vmparam.h"#include "sys/syslog.h"#include "sys/uio.h"#include "net/if.h"#include "net/netisr.h"#include "net/route.h"#ifdef INET#include "netinet/in.h"#include "netinet/in_systm.h"#include "netinet/in_var.h"#include "netinet/ip.h"#include "netinet/if_ether.h"#endif#ifdef NS#include "netns/ns.h"#include "netns/ns_if.h"#endif#ifdef ISO#include "netiso/iso.h"#include "netiso/iso_var.h"extern char all_es_snpa[], all_is_snpa[];#endif #include "../include/cpu.h"#include "../include/pte.h"#include "../include/mtpr.h"#include "../vba/vbavar.h"#include "if_exreg.h"#include "if_vba.h"#define	NH2X 32			/* Host to eXcelan request buffers */#define	NX2H 16			/* eXcelan to Host reply buffers */#define	NREC	16		/* Number of RECeive buffers */#define	NTRB	4		/* Number of TRansmit Buffers */#define NVBI	(NREC + NTRB)#define EXWATCHINTVL	10	/* call exwatch every x secs */int	exprobe(), exslave(), exattach(), exintr(), exstart();struct	vba_device *exinfo[NEX];long	exstd[] = { 0 };struct	vba_driver exdriver =	{ exprobe, 0, exattach, exstart, exstd, "ex", exinfo };int	exinit(),ether_output(),exioctl(),exreset(),exwatch();struct	ex_msg *exgetcbuf();int	ex_ncall = 0;			/* counts calls to exprobe */u_long	busoff;/* * Ethernet software status per interface. * * Each interface is referenced by a network interface structure, xs_if, which  * the routing code uses to locate the interface.  This structure contains the  * output queue for the interface, its address, ... NOTE: To configure multiple * controllers, the sizeof this structure must be a multiple of 16 (xs_h2xhdr). */struct	ex_softc {	struct		arpcom xs_ac;	/* Ethernet common part */#define	xs_if		xs_ac.ac_if	/* network-visible interface */#define	xs_addr		xs_ac.ac_enaddr	/* hardware Ethernet address */	int		xs_flags;	/* private flags */#define	EX_XPENDING	1		/* xmit rqst pending on EXOS */#define	EX_STATPENDING	(1<<1)		/* stats rqst pending on EXOS */#define	EX_RUNNING	(1<<2)		/* board is running */#define EX_SETADDR	(1<<3)		/* physaddr has been changed */	int		xs_cvec;	/* probe stores cvec here */	short		xs_enetunit;	/* unit number for enet filtering */	short		xs_enetinit;	/* enet inetrface is initialized */	struct	ex_msg	*xs_h2xnext;	/* host pointer to request queue */	struct	ex_msg 	*xs_x2hnext;	/* host pointer to reply queue */	u_long		xs_qbaddr;	/* map info for structs below */	struct	ex_shm	{	/* the following structures are always mapped in */	u_short		sm_h2xhdr;	/* EXOS's request queue header */	u_short		sm_x2hhdr;	/* EXOS's reply queue header */	struct ex_msg 	sm_h2xent[NH2X];/* request msg buffers */	struct ex_msg 	sm_x2hent[NX2H];/* reply msg buffers */	struct ex_conf	sm_cm;		/* configuration message */	struct ex_stat	sm_xsa;	/* EXOS writes stats here */	/* end mapped area */	} 		*xs_shm;	/* host pointer to shared area */#define	xs_h2xhdr	xs_shm->sm_h2xhdr#define	xs_x2hhdr	xs_shm->sm_x2hhdr#define	xs_h2xent	xs_shm->sm_h2xent#define	xs_x2hent	xs_shm->sm_x2hent#define	xs_cm		xs_shm->sm_cm#define	xs_xsa		xs_shm->sm_xsa#define	BUSADDR(x)	(0x3D000000 | (((u_long)kvtophys(x))&0xFFFFFF))#define	P_BUSADDR(x)	(0x3D000000 | (((u_long)kvtophys(x))&0xFFFFF0))#define	INCORE_BASE(p)	(((u_long)(p)->xs_shm) & 0xFFFFFFF0)/* we will arrange that the shared memory begins on a 16 byte boundary */#define	RVAL_OFF(n)	(((char *)&(((struct ex_shm *)0)->n))-(char *)0)#define	LVAL_OFF(n)	(((char *)(((struct ex_shm *)0)->n))-(char *)0)#define	H2XHDR_OFFSET	RVAL_OFF(sm_h2xhdr)#define	X2HHDR_OFFSET	RVAL_OFF(sm_x2hhdr)#define	H2XENT_OFFSET	LVAL_OFF(sm_h2xent)#define	X2HENT_OFFSET	LVAL_OFF(sm_x2hent)#define	CM_OFFSET	RVAL_OFF(sm_cm)#define	SA_OFFSET	RVAL_OFF(sm_xsa)	struct		ifvba xs_vbinfo[NVBI];/* Bus Resources (low core) */	struct		ifvba *xs_pkblist; /* free list of above */#define GetPkBuf(b, v)  ((v = (b)->mb_pkb = xs->xs_pkblist),\		      (xs->xs_pkblist = (struct ifvba *)(v)->iff_mbuf))#define FreePkBuf(v) (((v)->iff_mbuf = (struct mbuf *)xs->xs_pkblist),\							(xs->xs_pkblist = v))	char		xs_nrec;	/* number of pending receive buffers */	char		xs_ntrb;	/* number of pending transmit buffers */} ex_softc[NEX];int ex_padcheck = sizeof (struct ex_softc);exprobe(reg, vi)	caddr_t reg;	struct vba_device *vi;{	register br, cvec;		/* r12, r11 value-result */	register struct exdevice *exaddr = (struct exdevice *)reg;	int	i;	if (badaddr((caddr_t)exaddr, 2))		return 0;	/*	 * Reset EXOS and run self-test (should complete within 2 seconds).	 */	movow(&exaddr->ex_porta, EX_RESET);	for (i = 1000000; i; i--) {		uncache(&(exaddr->ex_portb));		if (exaddr->ex_portb & EX_TESTOK)			break;	}	if ((exaddr->ex_portb & EX_TESTOK) == 0)		return 0;	br = 0x15;	cvec = --vi->ui_hd->vh_lastiv;	ex_softc[vi->ui_unit].xs_cvec = cvec;	ex_ncall++;	return (sizeof(struct exdevice));}/* * Interface exists: make available by filling in network interface record.   * System will initialize the interface when it is ready to accept packets.   * A NET_ADDRS command is done to get the ethernet address. */exattach(ui)	register struct vba_device	*ui;{	register struct ex_softc *xs = &ex_softc[ui->ui_unit];	register struct ifnet *ifp = &xs->xs_if;	register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;	register struct ex_msg *bp;	ifp->if_unit = ui->ui_unit;	ifp->if_name = "ex";	ifp->if_mtu = ETHERMTU;	ifp->if_init = exinit;	ifp->if_ioctl = exioctl;	ifp->if_output = ether_output;	ifp->if_reset = exreset;	ifp->if_start = exstart;	ifp->if_flags = IFF_BROADCAST;	/*	 * Note: extra memory gets returned by if_vbareserve()	 * first, so, being page alligned, it is also 16-byte alligned.	 */	if (if_vbareserve(xs->xs_vbinfo, NVBI, EXMAXRBUF,			(caddr_t *)&xs->xs_shm, sizeof(*xs->xs_shm)) == 0)		return;	/*	 * Temporarily map queues in order to configure EXOS	 */	xs->xs_qbaddr = INCORE_BASE(xs);	exconfig(ui, 0);			/* without interrupts */	if (xs->xs_cm.cm_cc)		return;				/* bad conf */	/*	 * Get Ethernet address.	 */	if ((bp = exgetcbuf(xs, LLNET_ADDRS)) == (struct ex_msg *)0)		panic("exattach");	bp->mb_na.na_mask = READ_OBJ;	bp->mb_na.na_slot = PHYSSLOT;	bp->mb_status |= MH_EXOS;	movow(&exaddr->ex_portb, EX_NTRUPT);	bp = xs->xs_x2hnext;	while ((bp->mb_status & MH_OWNER) == MH_EXOS);/* poll for reply */	printf("ex%d: HW %c.%c NX %c.%c, hardware address %s\n",		ui->ui_unit, xs->xs_cm.cm_vc[2], xs->xs_cm.cm_vc[3],		xs->xs_cm.cm_vc[0], xs->xs_cm.cm_vc[1],		ether_sprintf(bp->mb_na.na_addrs));	bcopy((caddr_t)bp->mb_na.na_addrs, (caddr_t)xs->xs_addr,		sizeof(xs->xs_addr));	if_attach(ifp);}/* * Reset of interface after BUS reset. * If interface is on specified vba, reset its state. */exreset(unit)int unit;{	register struct vba_device *ui;	if (unit >= NEX || (ui = exinfo[unit]) == 0 || ui->ui_alive == 0)		return;	printf(" ex%d", unit);	ex_softc[unit].xs_if.if_flags &= ~IFF_RUNNING;	ex_softc[unit].xs_flags &= ~EX_RUNNING;	exinit(unit);}/* * Initialization of interface; clear recorded pending operations, and  * reinitialize BUS usage. Called at boot time, and at ifconfig time via  * exioctl, with interrupts disabled. */exinit(unit)int unit;{	register struct ex_softc *xs = &ex_softc[unit];	register struct vba_device *ui = exinfo[unit];	register struct exdevice *exaddr = (struct exdevice *)ui->ui_addr;	register struct ifnet *ifp = &xs->xs_if;	register struct sockaddr_in *sin;	register struct ex_msg 	*bp;	int s;	/* not yet, if address still unknown */	if (ifp->if_addrlist == (struct ifaddr *)0)		return;	if (xs->xs_flags & EX_RUNNING)		return;	xs->xs_qbaddr = INCORE_BASE(xs);	exconfig(ui, 4);		/* with vectored interrupts*/	/*	 * Put EXOS on the Ethernet, using NET_MODE command	 */	if ((bp = exgetcbuf(xs, LLNET_MODE)) == (struct ex_msg *)0)		panic("exinit");	bp->mb_nm.nm_mask = WRITE_OBJ;	bp->mb_nm.nm_optn = 0;	bp->mb_nm.nm_mode = MODE_PERF;	bp->mb_status |= MH_EXOS;	movow(&exaddr->ex_portb, EX_NTRUPT);	bp = xs->xs_x2hnext;	while ((bp->mb_status & MH_OWNER) == MH_EXOS) /* poll for reply */		;	bp->mb_length = MBDATALEN;	bp->mb_status |= MH_EXOS;		/* free up buffer */	movow(&exaddr->ex_portb, EX_NTRUPT);	xs->xs_x2hnext = xs->xs_x2hnext->mb_next;	ifp->if_watchdog = exwatch;	ifp->if_timer = EXWATCHINTVL;	s = splimp();		/* are interrupts disabled here, anyway? */	exhangrcv(unit);	xs->xs_if.if_flags |= IFF_RUNNING;	xs->xs_flags |= EX_RUNNING;	if (xs->xs_flags & EX_SETADDR)		ex_setaddr((u_char *)0, unit);#ifdef ISO	ex_setmulti(all_es_snpa, unit, 1);	ex_setmulti(all_is_snpa, unit, 2);#endif	exstart(&ex_softc[unit].xs_if);		/* start transmits */	splx(s);		/* are interrupts disabled here, anyway? */}/* * Reset, test, and configure EXOS.  It is called by exinit, and exattach. * Returns 0 if successful, 1 if self-test failed. */exconfig(ui, itype)struct	vba_device *ui;int itype;{	register int unit = ui->ui_unit;	register struct ex_softc *xs = &ex_softc[unit];	register struct exdevice *exaddr = (struct exdevice *) ui->ui_addr;	register struct ex_conf *cm = &xs->xs_cm;	register struct ex_msg 	*bp;	register struct ifvba *pkb;	int 	i;	u_long 	shiftreg;	static	u_char	cmaddr[8] = {0xFF, 0xFF, 0, 0};	xs->xs_flags = 0;	/*	 * Reset EXOS, wait for self-test to complete	 */	movow(&exaddr->ex_porta, EX_RESET);	do {		uncache(&exaddr->ex_portb);	} while ((exaddr->ex_portb & EX_TESTOK) == 0) ;	/*	 * Set up configuration message.	 */	cm->cm_1rsrv = 1;	cm->cm_cc = 0xFF;	cm->cm_opmode = 0;		/* link-level controller mode */	cm->cm_dfo = 0x0101;		/* enable host data order conversion */	cm->cm_dcn1 = 1;	cm->cm_2rsrv[0] = cm->cm_2rsrv[1] = 0;	cm->cm_ham = 3;			/* absolute address mode */	cm->cm_3rsrv = 0;	cm->cm_mapsiz = 0;	cm->cm_byteptrn[0] = 0x01;	/* EXOS deduces data order of host */	cm->cm_byteptrn[1] = 0x03;	/*  by looking at this pattern */	cm->cm_byteptrn[2] = 0x07;	cm->cm_byteptrn[3] = 0x0F;	cm->cm_wordptrn[0] = 0x0103;	cm->cm_wordptrn[1] = 0x070F;	cm->cm_lwordptrn = 0x0103070F;	for (i=0; i<20; i++) cm->cm_rsrvd[i] = 0;	cm->cm_mba = 0xFFFFFFFF;	cm->cm_nproc = 0xFF;	cm->cm_nmbox = 0xFF;	cm->cm_nmcast = 0xFF;	cm->cm_nhost = 1;	cm->cm_h2xba = P_BUSADDR(xs->xs_qbaddr);	cm->cm_h2xhdr = H2XHDR_OFFSET;	cm->cm_h2xtyp = 0;		/* should never wait for rqst buffer */	cm->cm_x2hba = cm->cm_h2xba;	cm->cm_x2hhdr = X2HHDR_OFFSET;	cm->cm_x2htyp = itype;		/* 0 for none, 4 for vectored */	cm->cm_x2haddr = xs->xs_cvec;	/* ivec allocated in exprobe */	/*	 * Set up message queues and headers.	 * First the request queue	 */	for (bp = &xs->xs_h2xent[0]; bp < &xs->xs_h2xent[NH2X]; bp++) {		bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));		bp->mb_rsrv = 0;		bp->mb_length = MBDATALEN;		bp->mb_status = MH_HOST;		bp->mb_next = bp+1;	}	xs->xs_h2xhdr = xs->xs_h2xent[NH2X-1].mb_link = (u_short)H2XENT_OFFSET;	xs->xs_h2xnext = xs->xs_h2xent[NH2X-1].mb_next = xs->xs_h2xent;	/* Now the reply queue. */	for (bp = &xs->xs_x2hent[0]; bp < &xs->xs_x2hent[NX2H]; bp++) {		bp->mb_link = (u_short)((char *)(bp+1)-INCORE_BASE(xs));		bp->mb_rsrv = 0;		bp->mb_length = MBDATALEN;		bp->mb_status = MH_EXOS;		bp->mb_next = bp+1;	}	xs->xs_x2hhdr = xs->xs_x2hent[NX2H-1].mb_link = (u_short)X2HENT_OFFSET;	xs->xs_x2hnext = xs->xs_x2hent[NX2H-1].mb_next = xs->xs_x2hent;	xs->xs_nrec = 0;	xs->xs_ntrb = 0;	xs->xs_pkblist =  xs->xs_vbinfo + NVBI - 1;	for (pkb = xs->xs_pkblist; pkb > xs->xs_vbinfo; pkb--)		pkb->iff_mbuf = (struct mbuf *)(pkb - 1);	xs->xs_vbinfo[0].iff_mbuf = 0;	/*	 * Write config msg address to EXOS and wait for configuration to 	 * complete (guaranteed response within 2 seconds).	 */	shiftreg = P_BUSADDR(xs->xs_qbaddr) + CM_OFFSET;	for (i = 4; i < 8; i++) {		cmaddr[i] = (u_char)(shiftreg & 0xFF);		shiftreg >>= 8;	}	for (i = 0; i < 8; i++) {		do {			uncache(&exaddr->ex_portb);		} while (exaddr->ex_portb & EX_UNREADY) ;		DELAY(500);		movow(&exaddr->ex_portb, cmaddr[i]);	}	for (i = 500000; i; --i) {		DELAY(10);		uncache(&cm->cm_cc);		if (cm->cm_cc != 0xFF)			break;	}	if (cm->cm_cc)		printf("ex%d: configuration failed; cc=%x\n", unit, cm->cm_cc);}/* * Start or re-start output on interface. Get another datagram to send off of  * the interface queue, and map it to the interface before starting the output. * This routine is called by exinit(), exoutput(), and excdint().  In all cases,

⌨️ 快捷键说明

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