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

📄 if_le.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1982, 1992, 1993 *	The Regents of the University of California.  All rights reserved. * * 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_le.c	8.2 (Berkeley) 10/30/93 * * from: $Header: if_le.c,v 1.25 93/10/31 04:47:50 leres Locked $ */#include "bpfilter.h"/* * AMD 7990 LANCE */#include <sys/param.h>#include <sys/device.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/mbuf.h>#include <sys/buf.h>#include <sys/socket.h>#include <sys/syslog.h>#include <sys/ioctl.h>#include <sys/malloc.h>#include <sys/errno.h>#include <net/if.h>#include <net/netisr.h>#include <net/route.h>#if NBPFILTER > 0#include <sys/select.h>#include <net/bpf.h>#include <net/bpfdesc.h>#endif#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 APPLETALK#include <netddp/atalk.h>#endif#include <machine/autoconf.h>#include <machine/cpu.h>#include <machine/pmap.h>#include <sparc/sbus/if_lereg.h>#include <sparc/sbus/sbusvar.h>/* DVMA address to LANCE address -- the Sbus/MMU will resupply the 0xff */#define	LANCE_ADDR(x)	((int)(x) & ~0xff000000)int	ledebug = 0;		/* console error messages */#ifdef PACKETSTATSlong	lexpacketsizes[LEMTU+1];long	lerpacketsizes[LEMTU+1];#endif/* Per interface statistics *//* XXX this should go in something like if_levar.h */struct	lestats {	long	lexints;	/* transmitter interrupts */	long	lerints;	/* receiver interrupts */	long	lerbufs;	/* total buffers received during interrupts */	long	lerhits;	/* times current rbuf was full */	long	lerscans;	/* rbufs scanned before finding first full */};/* * Ethernet software status per interface. * * Each interface is referenced by a network interface structure, * le_if, which the routing code uses to locate the interface. * This structure contains the output queue for the interface, its address, ... */struct le_softc {	struct	device sc_dev;		/* base device */	struct	sbusdev sc_sd;		/* sbus device */	struct	intrhand sc_ih;		/* interrupt vectoring */	struct	evcnt sc_intrcnt;	/* # of interrupts, per le */	struct	evcnt sc_errcnt;	/* # of errors, per le */	struct	arpcom sc_ac;		/* common Ethernet structures */#define	sc_if	sc_ac.ac_if		/* network-visible interface */#define	sc_addr	sc_ac.ac_enaddr		/* hardware Ethernet address */	volatile struct	lereg1 *sc_r1;	/* LANCE registers */	volatile struct	lereg2 *sc_r2;	/* dual-port RAM */	int	sc_rmd;			/* predicted next rmd to process */	int	sc_runt;	int	sc_jab;	int	sc_merr;	int	sc_babl;	int	sc_cerr;	int	sc_miss;	int	sc_xint;	int	sc_xown;	int	sc_uflo;	int	sc_rxlen;	int	sc_rxoff;	int	sc_txoff;	int	sc_busy;	short	sc_iflags;	struct	lestats sc_lestats;	/* per interface statistics */#if NBPFILTER > 0	caddr_t	sc_bpf;#endif};/* autoconfiguration driver */void	leattach(struct device *, struct device *, void *);struct	cfdriver lecd =    { NULL, "le", matchbyname, leattach, DV_IFNET, sizeof(struct le_softc) };/* Forwards */void	leattach(struct device *, struct device *, void *);void	lesetladrf(struct le_softc *);void	lereset(struct device *);int	leinit(int);int	lestart(struct ifnet *);int	leintr(void *);void	lexint(struct le_softc *);void	lerint(struct le_softc *);void	leread(struct le_softc *, char *, int);int	leput(char *, struct mbuf *);struct mbuf *leget(char *, int, int, struct ifnet *);int	leioctl(struct ifnet *, int, caddr_t);void	leerror(struct le_softc *, int);void	lererror(struct le_softc *, char *);void	lexerror(struct le_softc *);/* * Interface exists: make available by filling in network interface * record.  System will initialize the interface when it is ready * to accept packets. */voidleattach(parent, self, args)	struct device *parent;	struct device *self;	void *args;{	register struct le_softc *sc = (struct le_softc *)self;	register struct sbus_attach_args *sa = args;	register volatile struct lereg2 *ler2;	struct ifnet *ifp = &sc->sc_if;	register struct bootpath *bp;	register int a, pri;	/* XXX the following declarations should be elsewhere */	extern void myetheraddr(u_char *);	extern caddr_t dvma_malloc(size_t);	if (sa->sa_ra.ra_nintr != 1) {		printf(": expected 1 interrupt, got %d\n", sa->sa_ra.ra_nintr);		return;	}	pri = sa->sa_ra.ra_intr[0].int_pri;	printf(" pri %d", pri);	sc->sc_r1 = (volatile struct lereg1 *)	    mapiodev(sa->sa_ra.ra_paddr, sizeof(struct lereg1));	ler2 = sc->sc_r2 = (volatile struct lereg2 *)	    dvma_malloc(sizeof(struct lereg2));	myetheraddr(sc->sc_addr);	printf(": hardware address %s\n", ether_sprintf(sc->sc_addr));	/*	 * Setup for transmit/receive	 *	 * According to Van, some versions of the Lance only use this	 * address to receive packets; it doesn't put them in	 * output packets. We'll want to make sure that lestart()	 * installs the address.	 */	ler2->ler2_padr[0] = sc->sc_addr[1];	ler2->ler2_padr[1] = sc->sc_addr[0];	ler2->ler2_padr[2] = sc->sc_addr[3];	ler2->ler2_padr[3] = sc->sc_addr[2];	ler2->ler2_padr[4] = sc->sc_addr[5];	ler2->ler2_padr[5] = sc->sc_addr[4];	a = LANCE_ADDR(&ler2->ler2_rmd);	ler2->ler2_rlen = LE_RLEN | (a >> 16);	ler2->ler2_rdra = a;	a = LANCE_ADDR(&ler2->ler2_tmd);	ler2->ler2_tlen = LE_TLEN | (a >> 16);	ler2->ler2_tdra = a;	/*	 * Link into sbus, and establish interrupt handler.	 */	sc->sc_sd.sd_reset = lereset;	sbus_establish(&sc->sc_sd, &sc->sc_dev);	sc->sc_ih.ih_fun = leintr;	sc->sc_ih.ih_arg = sc;	intr_establish(pri, &sc->sc_ih);	/*	 * Set up event counters.	 */	evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt);	evcnt_attach(&sc->sc_dev, "errs", &sc->sc_errcnt);	ifp->if_unit = sc->sc_dev.dv_unit;	ifp->if_name = "le";	ifp->if_mtu = ETHERMTU;	ifp->if_init = leinit;	ifp->if_ioctl = leioctl;	ifp->if_output = ether_output;	ifp->if_start = lestart;	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;#ifdef IFF_NOTRAILERS	/* XXX still compile when the blasted things are gone... */	ifp->if_flags |= IFF_NOTRAILERS;#endif#if NBPFILTER > 0	bpfattach(&sc->sc_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));#endif	if_attach(ifp);#define SAME_LANCE(bp, sa) \	((bp->val[0] == sa->sa_slot && bp->val[1] == sa->sa_offset) || \	 (bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit))	bp = sa->sa_ra.ra_bp;	if (bp != NULL && strcmp(bp->name, "le") == 0 && SAME_LANCE(bp, sa))		bootdv = &sc->sc_dev;}/* * Setup the logical address filter */voidlesetladrf(sc)	register struct le_softc *sc;{	register volatile struct lereg2 *ler2 = sc->sc_r2;	register struct ifnet *ifp = &sc->sc_if;	register struct ether_multi *enm;	register u_char *cp, c;	register u_long crc;	register int i, len;	struct ether_multistep step;	/*	 * Set up multicast address filter by passing all multicast	 * addresses through a crc generator, and then using the high	 * order 6 bits as a index into the 64 bit logical address	 * filter. The high order two bits select the word, while the	 * rest of the bits select the bit within the word.	 */	ler2->ler2_ladrf[0] = 0;	ler2->ler2_ladrf[1] = 0;	ler2->ler2_ladrf[2] = 0;	ler2->ler2_ladrf[3] = 0;	ifp->if_flags &= ~IFF_ALLMULTI;	ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);	while (enm != NULL) {		if (bcmp((caddr_t)&enm->enm_addrlo,		    (caddr_t)&enm->enm_addrhi, sizeof(enm->enm_addrlo)) != 0) {			/*			 * We must listen to a range of multicast			 * addresses. For now, just accept all			 * multicasts, rather than trying to set only			 * those filter bits needed to match the range.			 * (At this time, the only use of address			 * ranges is for IP multicast routing, for			 * which the range is big enough to require all			 * bits set.)			 */			ler2->ler2_ladrf[0] = 0xffff;			ler2->ler2_ladrf[1] = 0xffff;			ler2->ler2_ladrf[2] = 0xffff;			ler2->ler2_ladrf[3] = 0xffff;			ifp->if_flags |= IFF_ALLMULTI;			return;		}		/*		 * One would think, given the AM7990 document's polynomial		 * of 0x04c11db6, that this should be 0x6db88320 (the bit		 * reversal of the AMD value), but that is not right.  See		 * the BASIC listing: bit 0 (our bit 31) must then be set.		 */		cp = (unsigned char *)&enm->enm_addrlo;		crc = 0xffffffff;		for (len = 6; --len >= 0;) {			c = *cp++;			for (i = 0; i < 8; i++) {				if ((c & 0x01) ^ (crc & 0x01)) {					crc >>= 1;					crc = crc ^ 0xedb88320;				} else					crc >>= 1;				c >>= 1;			}		}		/* Just want the 6 most significant bits. */		crc = crc >> 26;		/* Turn on the corresponding bit in the filter. */		ler2->ler2_ladrf[crc >> 4] |= 1 << (crc & 0xf);		ETHER_NEXT_MULTI(step, enm);	}}voidlereset(dev)	struct device *dev;{	register struct le_softc *sc = (struct le_softc *)dev;	register volatile struct lereg1 *ler1 = sc->sc_r1;	register volatile struct lereg2 *ler2 = sc->sc_r2;	register int i, a, timo, stat;#if NBPFILTER > 0	if (sc->sc_if.if_flags & IFF_PROMISC)		ler2->ler2_mode = LE_MODE_NORMAL | LE_MODE_PROM;	else#endif		ler2->ler2_mode = LE_MODE_NORMAL;	ler1->ler1_rap = LE_CSR0;	ler1->ler1_rdp = LE_C0_STOP;	/* Setup the logical address filter */	lesetladrf(sc);	/* init receive and transmit rings */	for (i = 0; i < LERBUF; i++) {		a = LANCE_ADDR(&ler2->ler2_rbuf[i][0]);		ler2->ler2_rmd[i].rmd0 = a;		ler2->ler2_rmd[i].rmd1_hadr = a >> 16;		ler2->ler2_rmd[i].rmd1_bits = LE_R1_OWN;		ler2->ler2_rmd[i].rmd2 = -LEMTU;		ler2->ler2_rmd[i].rmd3 = 0;	}	for (i = 0; i < LETBUF; i++) {		a = LANCE_ADDR(&ler2->ler2_tbuf[i][0]);		ler2->ler2_tmd[i].tmd0 = a;		ler2->ler2_tmd[i].tmd1_hadr = a >> 16;		ler2->ler2_tmd[i].tmd1_bits = 0;		ler2->ler2_tmd[i].tmd2 = 0;		ler2->ler2_tmd[i].tmd3 = 0;	}bzero(&ler2->ler2_rbuf[0][0], (LERBUF + LETBUF) * LEMTU);	/* lance will stuff packet into receive buffer 0 next */	sc->sc_rmd = 0;	/* tell the chip where to find the initialization block */	a = LANCE_ADDR(&ler2->ler2_mode);	ler1->ler1_rap = LE_CSR1;	ler1->ler1_rdp = a;	ler1->ler1_rap = LE_CSR2;	ler1->ler1_rdp = a >> 16;	ler1->ler1_rap = LE_CSR3;	ler1->ler1_rdp = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON;	ler1->ler1_rap = LE_CSR0;	ler1->ler1_rdp = LE_C0_INIT;	timo = 100000;	while (((stat = ler1->ler1_rdp) & (LE_C0_ERR | LE_C0_IDON)) == 0) {		if (--timo == 0) {			printf("%s: init timeout, stat=%b\n",			    sc->sc_dev.dv_xname, stat, LE_C0_BITS);			break;		}	}	if (stat & LE_C0_ERR)		printf("%s: init failed, stat=%b\n",		    sc->sc_dev.dv_xname, stat, LE_C0_BITS);	else		ler1->ler1_rdp = LE_C0_IDON;	/* clear IDON */	ler1->ler1_rdp = LE_C0_STRT | LE_C0_INEA;	sc->sc_if.if_flags &= ~IFF_OACTIVE;}/* * Initialization of interface */intleinit(unit)	int unit;{	register struct le_softc *sc = lecd.cd_devs[unit];	register struct ifnet *ifp = &sc->sc_if;	register int s;	/* not yet, if address still unknown */	if (ifp->if_addrlist == (struct ifaddr *)0)		return (0);	if ((ifp->if_flags & IFF_RUNNING) == 0) {		s = splimp();		ifp->if_flags |= IFF_RUNNING;		lereset(&sc->sc_dev);	        lestart(ifp);		splx(s);	}	return (0);}/* * Start output on interface.  Get another datagram to send * off of the interface queue, and copy it to the interface * before starting the output. */intlestart(ifp)	register struct ifnet *ifp;{	register struct le_softc *sc = lecd.cd_devs[ifp->if_unit];	register volatile struct letmd *tmd;	register struct mbuf *m;	register int len;	if ((sc->sc_if.if_flags & IFF_RUNNING) == 0)		return (0);	IF_DEQUEUE(&sc->sc_if.if_snd, m);	if (m == 0)		return (0);	len = leput(sc->sc_r2->ler2_tbuf[0], m);#if NBPFILTER > 0	/*	 * If bpf is listening on this interface, let it	 * see the packet before we commit it to the wire.	 */	if (sc->sc_bpf)		bpf_tap(sc->sc_bpf, sc->sc_r2->ler2_tbuf[0], len);#endif#ifdef PACKETSTATS	if (len <= LEMTU)		lexpacketsizes[len]++;#endif	tmd = sc->sc_r2->ler2_tmd;	tmd->tmd3 = 0;	tmd->tmd2 = -len;	tmd->tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP;	sc->sc_if.if_flags |= IFF_OACTIVE;	return (0);}intleintr(dev)	register void *dev;{	register struct le_softc *sc = dev;	register volatile struct lereg1 *ler1 = sc->sc_r1;	register int csr0;	csr0 = ler1->ler1_rdp;	if ((csr0 & LE_C0_INTR) == 0)		return (0);	sc->sc_intrcnt.ev_count++;	if (csr0 & LE_C0_ERR) {		sc->sc_errcnt.ev_count++;		leerror(sc, csr0);		if (csr0 & LE_C0_MERR) {			sc->sc_merr++;			lereset(&sc->sc_dev);			return (1);		}		if (csr0 & LE_C0_BABL)			sc->sc_babl++;		if (csr0 & LE_C0_CERR)			sc->sc_cerr++;		if (csr0 & LE_C0_MISS)			sc->sc_miss++;		ler1->ler1_rdp = LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_INEA;	}	if ((csr0 & LE_C0_RXON) == 0) {		sc->sc_rxoff++;		lereset(&sc->sc_dev);		return (1);

⌨️ 快捷键说明

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