xref: /csrg-svn/sys/luna68k/dev/if_le.c (revision 58694)
154000Sfujita /*
255582Sfujita  * Copyright (c) 1982, 1990 The Regents of the University of California.
354000Sfujita  * All rights reserved.
454000Sfujita  *
554000Sfujita  * %sccs.include.redist.c%
654000Sfujita  *
7*58694Sakito  * from: hp300/dev/if_le.c	7.16 (Berkeley) 3/11/93
855582Sfujita  *
9*58694Sakito  *	@(#)if_le.c	7.5 (Berkeley) 03/17/93
1054000Sfujita  */
1154000Sfujita 
1254000Sfujita #include "le.h"
1354000Sfujita #if NLE > 0
1454000Sfujita 
1554000Sfujita #include "bpfilter.h"
1654000Sfujita 
1754000Sfujita /*
1854000Sfujita  * AMD 7990 LANCE
1954000Sfujita  *
2055582Sfujita  * This driver will accept tailer encapsulated packets even
2154000Sfujita  * though it buys us nothing.  The motivation was to avoid incompatibilities
2254000Sfujita  * with VAXen, SUNs, and others that handle and benefit from them.
2354000Sfujita  * This reasoning is dubious.
2454000Sfujita  */
2556519Sbostic #include <sys/param.h>
2656519Sbostic #include <sys/proc.h>
2756519Sbostic #include <sys/systm.h>
2856519Sbostic #include <sys/mbuf.h>
2956519Sbostic #include <sys/buf.h>
3056519Sbostic #include <sys/protosw.h>
3156519Sbostic #include <sys/socket.h>
3256519Sbostic #include <sys/syslog.h>
3356519Sbostic #include <sys/ioctl.h>
3456519Sbostic #include <sys/errno.h>
3554000Sfujita 
3656519Sbostic #include <net/if.h>
3756519Sbostic #include <net/netisr.h>
3856519Sbostic #include <net/route.h>
3954000Sfujita 
4054000Sfujita #ifdef INET
4156519Sbostic #include <netinet/in.h>
4256519Sbostic #include <netinet/in_systm.h>
4356519Sbostic #include <netinet/in_var.h>
4456519Sbostic #include <netinet/ip.h>
4556519Sbostic #include <netinet/if_ether.h>
4654000Sfujita #endif
4754000Sfujita 
4854000Sfujita #ifdef NS
4956519Sbostic #include <netns/ns.h>
5056519Sbostic #include <netns/ns_if.h>
5154000Sfujita #endif
5254000Sfujita 
5357525Sakito #if defined (CCITT) && defined (LLC)
5457525Sakito #include <sys/socketvar.h>
5557525Sakito #include <netccitt/x25.h>
5657525Sakito extern llc_ctlinput(), cons_rtrequest();
5757525Sakito #endif
5857525Sakito 
5956519Sbostic #include <machine/cpu.h>
6056519Sbostic #include <machine/mtpr.h>
6156519Sbostic #include <luna68k/dev/device.h>
6256519Sbostic #include <luna68k/dev/if_lereg.h>
6354000Sfujita 
6454000Sfujita #if NBPFILTER > 0
6556519Sbostic #include <net/bpf.h>
6656519Sbostic #include <net/bpfdesc.h>
6754000Sfujita #endif
6854000Sfujita 
6954000Sfujita int	leattach();
7054000Sfujita struct	driver ledriver = {
7154000Sfujita 	leattach, "le",
7254000Sfujita };
7354000Sfujita 
7454000Sfujita int	ledebug = 0;		/* console error messages */
7554000Sfujita 
7657525Sakito int	leintr(), leinit(), leioctl(), lestart(), ether_output(), lereset();
7754000Sfujita struct	mbuf *m_devget();
7854000Sfujita extern	struct ifnet loif;
7954000Sfujita 
8054000Sfujita /*
8154000Sfujita  * Ethernet software status per interface.
8254000Sfujita  *
8354000Sfujita  * Each interface is referenced by a network interface structure,
8454000Sfujita  * le_if, which the routing code uses to locate the interface.
8554000Sfujita  * This structure contains the output queue for the interface, its address, ...
8654000Sfujita  */
8754000Sfujita struct	le_softc {
8854000Sfujita 	struct	arpcom sc_ac;	/* common Ethernet structures */
8954000Sfujita #define	sc_if	sc_ac.ac_if	/* network-visible interface */
9054000Sfujita #define	sc_addr	sc_ac.ac_enaddr	/* hardware Ethernet address */
9154000Sfujita 	struct	lereg1 *sc_r1;	/* LANCE registers */
9254000Sfujita 	struct	lereg2 *sc_r2;	/* dual-port RAM */
9354000Sfujita 	int	sc_rmd;		/* predicted next rmd to process */
9455582Sfujita 	int	sc_tmd;		/* next available tmd */
9555582Sfujita 	int	sc_txcnt;	/* # of transmit buffers in use */
9655582Sfujita 	/* stats */
9754000Sfujita 	int	sc_runt;
9854000Sfujita 	int	sc_jab;
9954000Sfujita 	int	sc_merr;
10054000Sfujita 	int	sc_babl;
10154000Sfujita 	int	sc_cerr;
10254000Sfujita 	int	sc_miss;
10355582Sfujita 	int	sc_rown;
10454000Sfujita 	int	sc_xown;
10555582Sfujita 	int	sc_xown2;
10654000Sfujita 	int	sc_uflo;
10754000Sfujita 	int	sc_rxlen;
10854000Sfujita 	int	sc_rxoff;
10954000Sfujita 	int	sc_txoff;
11054000Sfujita 	int	sc_busy;
11154000Sfujita 	short	sc_iflags;
11254000Sfujita } le_softc[NLE];
11354000Sfujita 
11454000Sfujita /* access LANCE registers */
11554000Sfujita #define	LERDWR(cntl, src, dst)	(dst) = (src)
11654000Sfujita 
11754000Sfujita #define LE_IPL		3
11854000Sfujita 
11954000Sfujita /*
12054000Sfujita  * Interface exists: make available by filling in network interface
12154000Sfujita  * record.  System will initialize the interface when it is ready
12254000Sfujita  * to accept packets.
12354000Sfujita  */
12454000Sfujita leattach(hd)
12554000Sfujita 	struct hp_device *hd;
12654000Sfujita {
12754000Sfujita 	register struct lereg2 *ler2;
12854000Sfujita 	struct lereg2 *lemem = (struct lereg2 *) 0;
12954000Sfujita 	struct le_softc *le = &le_softc[hd->hp_unit];
13054000Sfujita 	struct ifnet *ifp = &le->sc_if;
13154000Sfujita 	char *cp;
13254000Sfujita 	int i;
13354000Sfujita 
13454000Sfujita 	le->sc_r1 = (struct lereg1 *) hd->hp_addr;
13554000Sfujita 	ler2 = le->sc_r2 = (struct lereg2 *) 0x71000000;
13654000Sfujita 
13754000Sfujita 	hd->hp_ipl = LE_IPL;
13854000Sfujita 
13954000Sfujita 	/*
14054000Sfujita 	 * Read the ethernet address off the board, one nibble at a time.
14154000Sfujita 	 */
14254000Sfujita #ifdef NOROM
14354000Sfujita 	cp = "00000a02456c";
14454000Sfujita #else
14554000Sfujita 	cp = (char *) 0x4101FFE0;
14654000Sfujita #endif
14754000Sfujita 	for (i = 0; i < sizeof(le->sc_addr); i++) {
14854000Sfujita 		le->sc_addr[i]  = (*cp < 'A' ? (*cp & 0xF) : (*cp & 0xF) + 9) << 4;
14954000Sfujita 		cp++;
15054000Sfujita 		le->sc_addr[i] |= (*cp < 'A' ? (*cp & 0xF) : (*cp & 0xF) + 9);
15154000Sfujita 		cp++;
15254000Sfujita 	}
15354000Sfujita 	printf("le%d: hardware address %s\n", hd->hp_unit,
15454000Sfujita 		ether_sprintf(le->sc_addr));
15554000Sfujita 
15654000Sfujita 	/*
15754000Sfujita 	 * Setup for transmit/receive
15854000Sfujita 	 */
15954000Sfujita 	ler2->ler2_mode = LE_MODE;
16055582Sfujita 	ler2->ler2_ladrf[0] = 0;
16155582Sfujita 	ler2->ler2_ladrf[1] = 0;
16254000Sfujita 	ler2->ler2_rlen = LE_RLEN;
16354000Sfujita 	ler2->ler2_rdra = (int)lemem->ler2_rmd;
16454000Sfujita 	ler2->ler2_tlen = LE_TLEN;
16554000Sfujita 	ler2->ler2_tdra = (int)lemem->ler2_tmd;
16654000Sfujita 
16754000Sfujita 	ifp->if_unit = hd->hp_unit;
16854000Sfujita 	ifp->if_name = "le";
16954000Sfujita 	ifp->if_mtu = ETHERMTU;
17054000Sfujita 	ifp->if_init = leinit;
17157525Sakito 	ifp->if_reset = lereset;
17254000Sfujita 	ifp->if_ioctl = leioctl;
17354000Sfujita 	ifp->if_output = ether_output;
17454000Sfujita 	ifp->if_start = lestart;
17555582Sfujita #ifdef MULTICAST
17655582Sfujita 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
17755582Sfujita #else
17854000Sfujita 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
17955582Sfujita #endif
18054000Sfujita #if NBPFILTER > 0
18155582Sfujita 	bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
18254000Sfujita #endif
18354000Sfujita 	if_attach(ifp);
18454000Sfujita 	return (1);
18554000Sfujita }
18654000Sfujita 
18755582Sfujita #ifdef MULTICAST
18855582Sfujita /*
18955582Sfujita  * Setup the logical address filter
19055582Sfujita  */
19155582Sfujita void
19255582Sfujita lesetladrf(sc)
19355582Sfujita 	register struct le_softc *sc;
19455582Sfujita {
19555582Sfujita 	register volatile struct lereg2 *ler2 = sc->sc_r2;
19655582Sfujita 	register struct ifnet *ifp = &sc->sc_if;
19755582Sfujita 	register struct ether_multi *enm;
19855582Sfujita 	register u_char *cp;
19955582Sfujita 	register u_long crc;
20055582Sfujita 	register u_long c;
20155582Sfujita 	register int i, len;
20255582Sfujita 	struct ether_multistep step;
20355582Sfujita 
20455582Sfujita 	/*
20555582Sfujita 	 * Set up multicast address filter by passing all multicast
20655582Sfujita 	 * addresses through a crc generator, and then using the high
20755582Sfujita 	 * order 6 bits as a index into the 64 bit logical address
20855582Sfujita 	 * filter. The high order two bits select the word, while the
20955582Sfujita 	 * rest of the bits select the bit within the word.
21055582Sfujita 	 */
21155582Sfujita 
21255582Sfujita 	ler2->ler2_ladrf[0] = 0;
21355582Sfujita 	ler2->ler2_ladrf[1] = 0;
21455582Sfujita 	ifp->if_flags &= ~IFF_ALLMULTI;
21555582Sfujita 	ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);
21655582Sfujita 	while (enm != NULL) {
21755582Sfujita 		if (bcmp((caddr_t)&enm->enm_addrlo,
21855582Sfujita 		    (caddr_t)&enm->enm_addrhi, sizeof(enm->enm_addrlo)) == 0) {
21955582Sfujita 			/*
22055582Sfujita 			 * We must listen to a range of multicast
22155582Sfujita 			 * addresses. For now, just accept all
22255582Sfujita 			 * multicasts, rather than trying to set only
22355582Sfujita 			 * those filter bits needed to match the range.
22455582Sfujita 			 * (At this time, the only use of address
22555582Sfujita 			 * ranges is for IP multicast routing, for
22655582Sfujita 			 * which the range is big enough to require all
22755582Sfujita 			 * bits set.)
22855582Sfujita 			 */
22955582Sfujita 			ler2->ler2_ladrf[0] = 0xffffffff;
23055582Sfujita 			ler2->ler2_ladrf[1] = 0xffffffff;
23155582Sfujita 			ifp->if_flags |= IFF_ALLMULTI;
23255582Sfujita 			return;
23355582Sfujita 		}
23455582Sfujita 
23555582Sfujita 		cp = (unsigned char *)&enm->enm_addrlo;
23655582Sfujita 		c = *cp;
23755582Sfujita 		crc = 0xffffffff;
23855582Sfujita 		len = 6;
23955582Sfujita 		while (len-- > 0) {
24055582Sfujita 			c = *cp;
24155582Sfujita 			for (i = 0; i < 8; i++) {
24255582Sfujita 				if ((c & 0x01) ^ (crc & 0x01)) {
24355582Sfujita 					crc >>= 1;
24455582Sfujita 					crc = crc ^ 0xedb88320;
24555582Sfujita 				}
24655582Sfujita 				else
24755582Sfujita 					crc >>= 1;
24855582Sfujita 				c >>= 1;
24955582Sfujita 			}
25055582Sfujita 			cp++;
25155582Sfujita 		}
25255582Sfujita 		/* Just want the 6 most significant bits. */
25355582Sfujita 		crc = crc >> 26;
25455582Sfujita 
25555582Sfujita 		/* Turn on the corresponding bit in the filter. */
25655582Sfujita 		ler2->ler2_ladrf[crc >> 5] |= 1 << (crc & 0x1f);
25755582Sfujita 
25855582Sfujita 		ETHER_NEXT_MULTI(step, enm);
25955582Sfujita 	}
26055582Sfujita }
26155582Sfujita #endif
26255582Sfujita 
26354000Sfujita ledrinit(ler2, le)
26454000Sfujita 	register struct lereg2 *ler2;
26554000Sfujita 	register struct le_softc *le;
26654000Sfujita {
26754000Sfujita 	register struct lereg2 *lemem = (struct lereg2 *) 0;
26854000Sfujita 	register int i;
26954000Sfujita 
27054000Sfujita 	ler2->ler2_padr[0] = le->sc_addr[1];
27154000Sfujita 	ler2->ler2_padr[1] = le->sc_addr[0];
27254000Sfujita 	ler2->ler2_padr[2] = le->sc_addr[3];
27354000Sfujita 	ler2->ler2_padr[3] = le->sc_addr[2];
27454000Sfujita 	ler2->ler2_padr[4] = le->sc_addr[5];
27554000Sfujita 	ler2->ler2_padr[5] = le->sc_addr[4];
27654000Sfujita 	for (i = 0; i < LERBUF; i++) {
27754000Sfujita 		ler2->ler2_rmd[i].rmd0 = (int)lemem->ler2_rbuf[i];
27854000Sfujita 		ler2->ler2_rmd[i].rmd1 = LE_OWN;
27954000Sfujita 		ler2->ler2_rmd[i].rmd2 = -LEMTU;
28054000Sfujita 		ler2->ler2_rmd[i].rmd3 = 0;
28154000Sfujita 	}
28254000Sfujita 	for (i = 0; i < LETBUF; i++) {
28354000Sfujita 		ler2->ler2_tmd[i].tmd0 = (int)lemem->ler2_tbuf[i];
28454000Sfujita 		ler2->ler2_tmd[i].tmd1 = 0;
28554000Sfujita 		ler2->ler2_tmd[i].tmd2 = 0;
28654000Sfujita 		ler2->ler2_tmd[i].tmd3 = 0;
28754000Sfujita 	}
28855582Sfujita 	/* Setup the logical address filter */
28955582Sfujita #ifdef MULTICAST
29055582Sfujita 	lesetladrf(le);
29155582Sfujita #else
29255582Sfujita 	ler2->ler2_ladrf[0] = 0;
29355582Sfujita 	ler2->ler2_ladrf[1] = 0;
29455582Sfujita #endif
29554000Sfujita }
29654000Sfujita 
29754000Sfujita lereset(unit)
29854000Sfujita 	register int unit;
29954000Sfujita {
30054000Sfujita 	register struct le_softc *le = &le_softc[unit];
30154000Sfujita 	register struct lereg1 *ler1 = le->sc_r1;
30254000Sfujita 	register struct lereg2 *lemem = (struct lereg2 *) 0;
30354000Sfujita 	register int timo = 100000;
30454000Sfujita 	register int stat;
30554000Sfujita 
30654000Sfujita #ifdef lint
30754000Sfujita 	stat = unit;
30854000Sfujita #endif
30954000Sfujita #if NBPFILTER > 0
31054000Sfujita 	if (le->sc_if.if_flags & IFF_PROMISC)
31154000Sfujita 		/* set the promiscuous bit */
31254000Sfujita 		le->sc_r2->ler2_mode = LE_MODE|0x8000;
31354000Sfujita 	else
31454000Sfujita 		le->sc_r2->ler2_mode = LE_MODE;
31554000Sfujita #endif
31654000Sfujita 	LERDWR(ler0, LE_CSR0, ler1->ler1_rap);
31754000Sfujita 	LERDWR(ler0, LE_STOP, ler1->ler1_rdp);
31854000Sfujita 	ledrinit(le->sc_r2, le);
31955582Sfujita 	le->sc_rmd = le->sc_tmd = 0;
32054000Sfujita 	LERDWR(ler0, LE_CSR1, ler1->ler1_rap);
32154000Sfujita 	LERDWR(ler0, (int)&lemem->ler2_mode, ler1->ler1_rdp);
32254000Sfujita 	LERDWR(ler0, LE_CSR2, ler1->ler1_rap);
32354000Sfujita 	LERDWR(ler0, 0, ler1->ler1_rdp);
32454000Sfujita 	LERDWR(ler0, LE_CSR0, ler1->ler1_rap);
32554000Sfujita 	LERDWR(ler0, LE_INIT, ler1->ler1_rdp);
32654000Sfujita 	do {
32754000Sfujita 		if (--timo == 0) {
32854000Sfujita 			printf("le%d: init timeout, stat = 0x%x\n",
32954000Sfujita 			       unit, stat);
33054000Sfujita 			break;
33154000Sfujita 		}
33254000Sfujita 		LERDWR(ler0, ler1->ler1_rdp, stat);
33354000Sfujita 	} while ((stat & LE_IDON) == 0);
33454000Sfujita 	LERDWR(ler0, LE_STOP, ler1->ler1_rdp);
33554000Sfujita 	LERDWR(ler0, LE_CSR3, ler1->ler1_rap);
33654000Sfujita 	LERDWR(ler0, LE_BSWP, ler1->ler1_rdp);
33754000Sfujita 	LERDWR(ler0, LE_CSR0, ler1->ler1_rap);
33854000Sfujita 	LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp);
33954000Sfujita 	le->sc_if.if_flags &= ~IFF_OACTIVE;
34055582Sfujita 	le->sc_txcnt = 0;
34154000Sfujita }
34254000Sfujita 
34354000Sfujita /*
34454000Sfujita  * Initialization of interface
34554000Sfujita  */
34654000Sfujita leinit(unit)
34754000Sfujita 	int unit;
34854000Sfujita {
34954000Sfujita 	register struct ifnet *ifp = &le_softc[unit].sc_if;
35054000Sfujita 	register struct ifaddr *ifa;
35154000Sfujita 	int s;
35254000Sfujita 
35354000Sfujita 	/* not yet, if address still unknown */
35454000Sfujita 	for (ifa = ifp->if_addrlist;; ifa = ifa->ifa_next)
35554000Sfujita 		if (ifa == 0)
35654000Sfujita 			return;
35754000Sfujita 		else if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK)
35854000Sfujita 			break;
35954000Sfujita 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
36054000Sfujita 		s = splimp();
36154000Sfujita 		ifp->if_flags |= IFF_RUNNING;
36254000Sfujita 		lereset(unit);
36354000Sfujita 	        (void) lestart(ifp);
36454000Sfujita 		splx(s);
36554000Sfujita 	}
36654000Sfujita }
36754000Sfujita 
36854000Sfujita /*
36954000Sfujita  * Start output on interface.  Get another datagram to send
37054000Sfujita  * off of the interface queue, and copy it to the interface
37154000Sfujita  * before starting the output.
37254000Sfujita  */
37354000Sfujita lestart(ifp)
37454000Sfujita 	struct ifnet *ifp;
37554000Sfujita {
37654000Sfujita 	register struct le_softc *le = &le_softc[ifp->if_unit];
37754000Sfujita 	register struct letmd *tmd;
37854000Sfujita 	register struct mbuf *m;
37954000Sfujita 	int len;
38054000Sfujita 
38154000Sfujita 	if ((le->sc_if.if_flags & IFF_RUNNING) == 0)
38254000Sfujita 		return (0);
38355582Sfujita 	tmd = &le->sc_r2->ler2_tmd[le->sc_tmd];
38455582Sfujita 	do {
38555582Sfujita 		if (tmd->tmd1 & LE_OWN) {
38655582Sfujita 			le->sc_xown2++;
38755582Sfujita 			return (0);
38855582Sfujita 		}
38955582Sfujita 		IF_DEQUEUE(&le->sc_if.if_snd, m);
39055582Sfujita 		if (m == 0)
39155582Sfujita 			return (0);
39255582Sfujita 		len = leput(le->sc_r2->ler2_tbuf[le->sc_tmd], m);
39354000Sfujita #if NBPFILTER > 0
39455582Sfujita 		/*
39555582Sfujita 		 * If bpf is listening on this interface, let it
39655582Sfujita 		 * see the packet before we commit it to the wire.
39755582Sfujita 		 */
39855582Sfujita 		if (ifp->if_bpf)
39955582Sfujita 			bpf_tap(ifp->if_bpf, le->sc_r2->ler2_tbuf[le->sc_tmd],
40055582Sfujita 				len);
40154000Sfujita #endif
40255582Sfujita 
40355582Sfujita 		tmd->tmd3 = 0;
40455582Sfujita 		tmd->tmd2 = -len;
40554000Sfujita 		tmd->tmd1 = LE_OWN | LE_STP | LE_ENP;
40655582Sfujita 		if (++le->sc_tmd == LETBUF) {
40755582Sfujita 			le->sc_tmd = 0;
40855582Sfujita 			tmd = le->sc_r2->ler2_tmd;
40955582Sfujita 		} else
41055582Sfujita 			tmd++;
41155582Sfujita 	} while (++le->sc_txcnt < LETBUF);
41255582Sfujita 	le->sc_if.if_flags |= IFF_OACTIVE;
41354000Sfujita 	return (0);
41454000Sfujita }
41554000Sfujita 
41654000Sfujita void
41754000Sfujita _leintr()
41854000Sfujita {
41954000Sfujita 	register int i;
42054000Sfujita 
42154000Sfujita 	for (i = 0; i < NLE; i++) {
42254000Sfujita 		leintr(i);
42354000Sfujita 	}
42454000Sfujita }
42554000Sfujita 
42654000Sfujita int
42754000Sfujita leintr(unit)
42854000Sfujita 	register int unit;
42954000Sfujita {
43054000Sfujita 	register struct le_softc *le = &le_softc[unit];
43154000Sfujita 	register struct lereg1 *ler1;
43254000Sfujita 	register int stat;
43354000Sfujita 
43454000Sfujita 	ler1 = le->sc_r1;
43554000Sfujita 	LERDWR(ler0, ler1->ler1_rdp, stat);
43654000Sfujita 	if (stat & LE_SERR) {
43754000Sfujita 		leerror(unit, stat);
43854000Sfujita 		if (stat & LE_MERR) {
43954000Sfujita 			le->sc_merr++;
44054000Sfujita 			lereset(unit);
44154000Sfujita 			return(1);
44254000Sfujita 		}
44354000Sfujita 		if (stat & LE_BABL)
44454000Sfujita 			le->sc_babl++;
44554000Sfujita 		if (stat & LE_CERR)
44654000Sfujita 			le->sc_cerr++;
44754000Sfujita 		if (stat & LE_MISS)
44854000Sfujita 			le->sc_miss++;
44954000Sfujita 		LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp);
45054000Sfujita 	}
45154000Sfujita 	if ((stat & LE_RXON) == 0) {
45254000Sfujita 		le->sc_rxoff++;
45354000Sfujita 		lereset(unit);
45454000Sfujita 		return(1);
45554000Sfujita 	}
45654000Sfujita 	if ((stat & LE_TXON) == 0) {
45754000Sfujita 		le->sc_txoff++;
45854000Sfujita 		lereset(unit);
45954000Sfujita 		return(1);
46054000Sfujita 	}
46155582Sfujita 	if (stat & LE_RINT)
46254000Sfujita 		lerint(unit);
46355582Sfujita 	if (stat & LE_TINT)
46454000Sfujita 		lexint(unit);
46554000Sfujita 	return(1);
46654000Sfujita }
46754000Sfujita 
46854000Sfujita /*
46954000Sfujita  * Ethernet interface transmitter interrupt.
47054000Sfujita  * Start another output if more data to send.
47154000Sfujita  */
47254000Sfujita lexint(unit)
47354000Sfujita 	register int unit;
47454000Sfujita {
47554000Sfujita 	register struct le_softc *le = &le_softc[unit];
47654000Sfujita 	register struct letmd *tmd;
47755582Sfujita 	int i, gotone = 0;
47854000Sfujita 
47955582Sfujita 	do {
48055582Sfujita 		if ((i = le->sc_tmd - le->sc_txcnt) < 0)
48155582Sfujita 			i += LETBUF;
48255582Sfujita 		tmd = &le->sc_r2->ler2_tmd[i];
48355582Sfujita 		if (tmd->tmd1 & LE_OWN) {
48455582Sfujita 			if (gotone)
48555582Sfujita 				break;
48655582Sfujita 			le->sc_xown++;
48755582Sfujita 			return;
48854000Sfujita 		}
48955582Sfujita 
49055582Sfujita 		/* clear interrupt */
49155582Sfujita 		LERDWR(le->sc_r0, LE_TINT|LE_INEA, le->sc_r1->ler1_rdp);
49255582Sfujita 
49355582Sfujita 		/* XXX documentation says BUFF not included in ERR */
49455582Sfujita 		if ((tmd->tmd1 & LE_ERR) || (tmd->tmd3 & LE_TBUFF)) {
49555582Sfujita 			lexerror(unit);
49655582Sfujita 			le->sc_if.if_oerrors++;
49755582Sfujita 			if (tmd->tmd3 & (LE_TBUFF|LE_UFLO)) {
49855582Sfujita 				le->sc_uflo++;
49955582Sfujita 				lereset(unit);
50055582Sfujita 			} else if (tmd->tmd3 & LE_LCOL)
50155582Sfujita 				le->sc_if.if_collisions++;
50255582Sfujita 			else if (tmd->tmd3 & LE_RTRY)
50355582Sfujita 				le->sc_if.if_collisions += 16;
50455582Sfujita 		} else if (tmd->tmd1 & LE_ONE)
50554000Sfujita 			le->sc_if.if_collisions++;
50655582Sfujita 		else if (tmd->tmd1 & LE_MORE)
50755582Sfujita 			/* what is the real number? */
50855582Sfujita 			le->sc_if.if_collisions += 2;
50955582Sfujita 		else
51055582Sfujita 			le->sc_if.if_opackets++;
51155582Sfujita 		gotone++;
51255582Sfujita 	} while (--le->sc_txcnt > 0);
51354000Sfujita 	le->sc_if.if_flags &= ~IFF_OACTIVE;
51454000Sfujita 	(void) lestart(&le->sc_if);
51554000Sfujita }
51654000Sfujita 
51754000Sfujita #define	LENEXTRMP \
51854000Sfujita 	if (++bix == LERBUF) bix = 0, rmd = le->sc_r2->ler2_rmd; else ++rmd
51954000Sfujita 
52054000Sfujita /*
52154000Sfujita  * Ethernet interface receiver interrupt.
52254000Sfujita  * If input error just drop packet.
52354000Sfujita  * Decapsulate packet based on type and pass to type specific
52454000Sfujita  * higher-level input routine.
52554000Sfujita  */
52654000Sfujita lerint(unit)
52754000Sfujita 	int unit;
52854000Sfujita {
52954000Sfujita 	register struct le_softc *le = &le_softc[unit];
53054000Sfujita 	register int bix = le->sc_rmd;
53154000Sfujita 	register struct lermd *rmd = &le->sc_r2->ler2_rmd[bix];
53254000Sfujita 
53354000Sfujita 	/*
53454000Sfujita 	 * Out of sync with hardware, should never happen?
53554000Sfujita 	 */
53654000Sfujita 	if (rmd->rmd1 & LE_OWN) {
53755582Sfujita 		le->sc_rown++;
53854000Sfujita 		LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
53954000Sfujita 		return;
54054000Sfujita 	}
54154000Sfujita 
54254000Sfujita 	/*
54354000Sfujita 	 * Process all buffers with valid data
54454000Sfujita 	 */
54554000Sfujita 	while ((rmd->rmd1 & LE_OWN) == 0) {
54654000Sfujita 		int len = rmd->rmd3;
54754000Sfujita 
54854000Sfujita 		/* Clear interrupt to avoid race condition */
54954000Sfujita 		LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
55054000Sfujita 
55154000Sfujita 		if (rmd->rmd1 & LE_ERR) {
55254000Sfujita 			le->sc_rmd = bix;
55354000Sfujita 			lererror(unit, "bad packet");
55454000Sfujita 			le->sc_if.if_ierrors++;
55554000Sfujita 		} else if ((rmd->rmd1 & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) {
55654000Sfujita 			/*
55754000Sfujita 			 * Find the end of the packet so we can see how long
55854000Sfujita 			 * it was.  We still throw it away.
55954000Sfujita 			 */
56054000Sfujita 			do {
56154000Sfujita 				LERDWR(le->sc_r0, LE_RINT|LE_INEA,
56254000Sfujita 				       le->sc_r1->ler1_rdp);
56354000Sfujita 				rmd->rmd3 = 0;
56454000Sfujita 				rmd->rmd1 = LE_OWN;
56554000Sfujita 				LENEXTRMP;
56654000Sfujita 			} while (!(rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)));
56754000Sfujita 			le->sc_rmd = bix;
56854000Sfujita 			lererror(unit, "chained buffer");
56954000Sfujita 			le->sc_rxlen++;
57054000Sfujita 			/*
57154000Sfujita 			 * If search terminated without successful completion
57254000Sfujita 			 * we reset the hardware (conservative).
57354000Sfujita 			 */
57454000Sfujita 			if ((rmd->rmd1 & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) !=
57554000Sfujita 			    LE_ENP) {
57654000Sfujita 				lereset(unit);
57754000Sfujita 				return;
57854000Sfujita 			}
57954000Sfujita 		} else
58054000Sfujita 			leread(unit, le->sc_r2->ler2_rbuf[bix], len);
58154000Sfujita 		rmd->rmd3 = 0;
58254000Sfujita 		rmd->rmd1 = LE_OWN;
58354000Sfujita 		LENEXTRMP;
58454000Sfujita 	}
58554000Sfujita 	le->sc_rmd = bix;
58654000Sfujita }
58754000Sfujita 
58854000Sfujita leread(unit, buf, len)
58954000Sfujita 	int unit;
59054000Sfujita 	char *buf;
59154000Sfujita 	int len;
59254000Sfujita {
59354000Sfujita 	register struct le_softc *le = &le_softc[unit];
59454000Sfujita 	register struct ether_header *et;
59554000Sfujita     	struct mbuf *m;
59655582Sfujita 	int off, resid, flags;
59754000Sfujita 
59854000Sfujita 	le->sc_if.if_ipackets++;
59954000Sfujita 	et = (struct ether_header *)buf;
60054000Sfujita 	et->ether_type = ntohs((u_short)et->ether_type);
60154000Sfujita 	/* adjust input length to account for header and CRC */
60254000Sfujita 	len = len - sizeof(struct ether_header) - 4;
60354000Sfujita 
60454000Sfujita #define	ledataaddr(et, off, type)	((type)(((caddr_t)((et)+1)+(off))))
60554000Sfujita 	if (et->ether_type >= ETHERTYPE_TRAIL &&
60654000Sfujita 	    et->ether_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
60754000Sfujita 		off = (et->ether_type - ETHERTYPE_TRAIL) * 512;
60854000Sfujita 		if (off >= ETHERMTU)
60954000Sfujita 			return;		/* sanity */
61054000Sfujita 		et->ether_type = ntohs(*ledataaddr(et, off, u_short *));
61154000Sfujita 		resid = ntohs(*(ledataaddr(et, off+2, u_short *)));
61254000Sfujita 		if (off + resid > len)
61354000Sfujita 			return;		/* sanity */
61454000Sfujita 		len = off + resid;
61554000Sfujita 	} else
61654000Sfujita 		off = 0;
61754000Sfujita 
61854000Sfujita 	if (len <= 0) {
61954000Sfujita 		if (ledebug)
62054000Sfujita 			log(LOG_WARNING,
62154000Sfujita 			    "le%d: ierror(runt packet): from %s: len=%d\n",
62254000Sfujita 			    unit, ether_sprintf(et->ether_shost), len);
62354000Sfujita 		le->sc_runt++;
62454000Sfujita 		le->sc_if.if_ierrors++;
62554000Sfujita 		return;
62654000Sfujita 	}
62755582Sfujita 	flags = 0;
62855582Sfujita 	if (bcmp((caddr_t)etherbroadcastaddr,
62955582Sfujita 	    (caddr_t)et->ether_dhost, sizeof(etherbroadcastaddr)) == 0)
63055582Sfujita 		flags |= M_BCAST;
63155582Sfujita 	if (et->ether_dhost[0] & 1)
63255582Sfujita 		flags |= M_MCAST;
63355582Sfujita 
63454000Sfujita #if NBPFILTER > 0
63554000Sfujita 	/*
63654000Sfujita 	 * Check if there's a bpf filter listening on this interface.
63755582Sfujita 	 * If so, hand off the raw packet to enet.
63854000Sfujita 	 */
63955582Sfujita 	if (le->sc_if.if_bpf) {
64055582Sfujita 		bpf_tap(le->sc_if.if_bpf, buf, len + sizeof(struct ether_header));
64155582Sfujita 
64255582Sfujita 		/*
64355582Sfujita 		 * Keep the packet if it's a broadcast or has our
64455582Sfujita 		 * physical ethernet address (or if we support
64555582Sfujita 		 * multicast and it's one).
64655582Sfujita 		 */
64755582Sfujita 		if (
64855582Sfujita #ifdef MULTICAST
64955582Sfujita 		    (flags & (M_BCAST | M_MCAST)) == 0 &&
65055582Sfujita #else
65155582Sfujita 		    (flags & M_BCAST) == 0 &&
65254000Sfujita #endif
65355582Sfujita 		    bcmp(et->ether_dhost, le->sc_addr,
65455582Sfujita 			sizeof(et->ether_dhost)) != 0)
65555582Sfujita 			return;
65655582Sfujita 	}
65754000Sfujita #endif
65854000Sfujita 	/*
65954000Sfujita 	 * Pull packet off interface.  Off is nonzero if packet
66054000Sfujita 	 * has trailing header; m_devget will then force this header
66154000Sfujita 	 * information to be at the front, but we still have to drop
66254000Sfujita 	 * the type and length which are at the front of any trailer data.
66354000Sfujita 	 */
66454000Sfujita 	m = m_devget((char *)(et + 1), len, off, &le->sc_if, 0);
66554000Sfujita 	if (m == 0)
66654000Sfujita 		return;
667*58694Sakito 	m->m_flags |= flags;
66854000Sfujita 	ether_input(&le->sc_if, et, m);
66954000Sfujita }
67054000Sfujita 
67154000Sfujita /*
67254000Sfujita  * Routine to copy from mbuf chain to transmit
67354000Sfujita  * buffer in board local memory.
67454000Sfujita  */
67554000Sfujita leput(lebuf, m)
67654000Sfujita 	register char *lebuf;
67754000Sfujita 	register struct mbuf *m;
67854000Sfujita {
67954000Sfujita 	register struct mbuf *mp;
68054000Sfujita 	register int len, tlen = 0;
68154000Sfujita 
68254000Sfujita 	for (mp = m; mp; mp = mp->m_next) {
68354000Sfujita 		len = mp->m_len;
68454000Sfujita 		if (len == 0)
68554000Sfujita 			continue;
68654000Sfujita 		tlen += len;
68754000Sfujita 		bcopy(mtod(mp, char *), lebuf, len);
68854000Sfujita 		lebuf += len;
68954000Sfujita 	}
69054000Sfujita 	m_freem(m);
69154000Sfujita 	if (tlen < LEMINSIZE) {
69254000Sfujita 		bzero(lebuf, LEMINSIZE - tlen);
69354000Sfujita 		tlen = LEMINSIZE;
69454000Sfujita 	}
69554000Sfujita 	return(tlen);
69654000Sfujita }
69754000Sfujita 
69854000Sfujita /*
69954000Sfujita  * Process an ioctl request.
70054000Sfujita  */
70154000Sfujita leioctl(ifp, cmd, data)
70254000Sfujita 	register struct ifnet *ifp;
70354000Sfujita 	int cmd;
70454000Sfujita 	caddr_t data;
70554000Sfujita {
70654000Sfujita 	register struct ifaddr *ifa = (struct ifaddr *)data;
70754000Sfujita 	struct le_softc *le = &le_softc[ifp->if_unit];
70854000Sfujita 	struct lereg1 *ler1 = le->sc_r1;
70954000Sfujita 	int s = splimp(), error = 0;
71054000Sfujita 
71154000Sfujita 	switch (cmd) {
71254000Sfujita 
71354000Sfujita 	case SIOCSIFADDR:
71454000Sfujita 		ifp->if_flags |= IFF_UP;
71554000Sfujita 		switch (ifa->ifa_addr->sa_family) {
71654000Sfujita #ifdef INET
71754000Sfujita 		case AF_INET:
71854000Sfujita 			leinit(ifp->if_unit);	/* before arpwhohas */
71954000Sfujita 			((struct arpcom *)ifp)->ac_ipaddr =
72054000Sfujita 				IA_SIN(ifa)->sin_addr;
72154000Sfujita 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
72254000Sfujita 			break;
72354000Sfujita #endif
72454000Sfujita #ifdef NS
72554000Sfujita 		case AF_NS:
72654000Sfujita 		    {
72754000Sfujita 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
72854000Sfujita 
72954000Sfujita 			if (ns_nullhost(*ina))
73054000Sfujita 				ina->x_host = *(union ns_host *)(le->sc_addr);
73154000Sfujita 			else {
73254000Sfujita 				/*
73354000Sfujita 				 * The manual says we can't change the address
73454000Sfujita 				 * while the receiver is armed,
73554000Sfujita 				 * so reset everything
73654000Sfujita 				 */
73754000Sfujita 				ifp->if_flags &= ~IFF_RUNNING;
73854000Sfujita 				LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp);
73954000Sfujita 				bcopy((caddr_t)ina->x_host.c_host,
74054000Sfujita 				    (caddr_t)le->sc_addr, sizeof(le->sc_addr));
74154000Sfujita 			}
74254000Sfujita 			leinit(ifp->if_unit); /* does le_setaddr() */
74354000Sfujita 			break;
74454000Sfujita 		    }
74554000Sfujita #endif
74654000Sfujita 		default:
74754000Sfujita 			leinit(ifp->if_unit);
74854000Sfujita 			break;
74954000Sfujita 		}
75054000Sfujita 		break;
75154000Sfujita 
75257525Sakito #if defined (CCITT) && defined (LLC)
75357525Sakito 	case SIOCSIFCONF_X25:
75457525Sakito 		ifp -> if_flags |= IFF_UP;
75557525Sakito 		ifa -> ifa_rtrequest = cons_rtrequest;
75657525Sakito 		error = x25_llcglue(PRC_IFUP, ifa -> ifa_addr);
75757525Sakito 		if (error == 0)
75857525Sakito 			leinit(ifp -> if_unit);
75957525Sakito 		break;
76057525Sakito #endif /* CCITT && LLC */
76157525Sakito 
76257525Sakito 
76354000Sfujita 	case SIOCSIFFLAGS:
76454000Sfujita 		if ((ifp->if_flags & IFF_UP) == 0 &&
76554000Sfujita 		    ifp->if_flags & IFF_RUNNING) {
76654000Sfujita 			LERDWR(le->sc_r0, LE_STOP, ler1->ler1_rdp);
76754000Sfujita 			ifp->if_flags &= ~IFF_RUNNING;
76854000Sfujita 		} else if (ifp->if_flags & IFF_UP &&
76954000Sfujita 		    (ifp->if_flags & IFF_RUNNING) == 0)
77054000Sfujita 			leinit(ifp->if_unit);
77154000Sfujita 		/*
77254000Sfujita 		 * If the state of the promiscuous bit changes, the interface
77354000Sfujita 		 * must be reset to effect the change.
77454000Sfujita 		 */
77554000Sfujita 		if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) &&
77654000Sfujita 		    (ifp->if_flags & IFF_RUNNING)) {
77754000Sfujita 			le->sc_iflags = ifp->if_flags;
77854000Sfujita 			lereset(ifp->if_unit);
77954000Sfujita 			lestart(ifp);
78054000Sfujita 		}
78154000Sfujita 		break;
78254000Sfujita 
78355582Sfujita #ifdef MULTICAST
78455582Sfujita 	case SIOCADDMULTI:
78555582Sfujita 	case SIOCDELMULTI:
78655582Sfujita 		/* Update our multicast list  */
78755582Sfujita 		error = (cmd == SIOCADDMULTI) ?
78855582Sfujita 		    ether_addmulti((struct ifreq *)data, &le->sc_ac) :
78955582Sfujita 		    ether_delmulti((struct ifreq *)data, &le->sc_ac);
79055582Sfujita 
79155582Sfujita 		if (error == ENETRESET) {
79255582Sfujita 			/*
79355582Sfujita 			 * Multicast list has changed; set the hardware
79455582Sfujita 			 * filter accordingly.
79555582Sfujita 			 */
79655582Sfujita 			lereset(ifp->if_unit);
79755582Sfujita 			error = 0;
79855582Sfujita 		}
79955582Sfujita 		break;
80055582Sfujita #endif
80154000Sfujita 	default:
80254000Sfujita 		error = EINVAL;
80354000Sfujita 	}
80454000Sfujita 	splx(s);
80554000Sfujita 	return (error);
80654000Sfujita }
80754000Sfujita 
80854000Sfujita leerror(unit, stat)
80954000Sfujita 	int unit;
81054000Sfujita 	int stat;
81154000Sfujita {
81254000Sfujita 	if (!ledebug)
81354000Sfujita 		return;
81454000Sfujita 
81554000Sfujita 	/*
81654000Sfujita 	 * Not all transceivers implement heartbeat
81754000Sfujita 	 * so we only log CERR once.
81854000Sfujita 	 */
81954000Sfujita 	if ((stat & LE_CERR) && le_softc[unit].sc_cerr)
82054000Sfujita 		return;
82154000Sfujita 	log(LOG_WARNING,
82254000Sfujita 	    "le%d: error: stat=%b\n", unit,
82354000Sfujita 	    stat,
82454000Sfujita 	    "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT");
82554000Sfujita }
82654000Sfujita 
82754000Sfujita lererror(unit, msg)
82854000Sfujita 	int unit;
82954000Sfujita 	char *msg;
83054000Sfujita {
83154000Sfujita 	register struct le_softc *le = &le_softc[unit];
83254000Sfujita 	register struct lermd *rmd;
83354000Sfujita 	int len;
83454000Sfujita 
83554000Sfujita 	if (!ledebug)
83654000Sfujita 		return;
83754000Sfujita 
83854000Sfujita 	rmd = &le->sc_r2->ler2_rmd[le->sc_rmd];
83954000Sfujita 	len = rmd->rmd3;
84054000Sfujita 	log(LOG_WARNING,
84154000Sfujita 	    "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n",
84254000Sfujita 	    unit, msg,
84354000Sfujita 	    len > 11 ?
84454000Sfujita 		ether_sprintf((u_char *)&le->sc_r2->ler2_rbuf[le->sc_rmd][6]) :
84554000Sfujita 		"unknown",
84654000Sfujita 	    le->sc_rmd, len,
84754000Sfujita 	    rmd->rmd1,
84854000Sfujita 	    "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP");
84954000Sfujita }
85054000Sfujita 
85154000Sfujita lexerror(unit)
85254000Sfujita 	int unit;
85354000Sfujita {
85454000Sfujita 	register struct le_softc *le = &le_softc[unit];
85554000Sfujita 	register struct letmd *tmd;
85654000Sfujita 	int len;
85754000Sfujita 
85854000Sfujita 	if (!ledebug)
85954000Sfujita 		return;
86054000Sfujita 
86154000Sfujita 	tmd = le->sc_r2->ler2_tmd;
86254000Sfujita 	len = -tmd->tmd2;
86354000Sfujita 	log(LOG_WARNING,
86454000Sfujita 	    "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n",
86554000Sfujita 	    unit,
86654000Sfujita 	    len > 5 ?
86754000Sfujita 		ether_sprintf((u_char *)&le->sc_r2->ler2_tbuf[0][0]) :
86854000Sfujita 		"unknown",
86954000Sfujita 	    0, len,
87054000Sfujita 	    tmd->tmd1,
87154000Sfujita 	    "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP",
87254000Sfujita 	    tmd->tmd3,
87354000Sfujita 	    "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY");
87454000Sfujita }
87554000Sfujita #endif
876