xref: /csrg-svn/sys/pmax/dev/if_le.c (revision 60599)
156819Sralph /*-
256819Sralph  * Copyright (c) 1992 The Regents of the University of California.
352130Smckusick  * All rights reserved.
452130Smckusick  *
552130Smckusick  * This code is derived from software contributed to Berkeley by
656819Sralph  * Ralph Campbell and Rick Macklem.
752130Smckusick  *
852130Smckusick  * %sccs.include.redist.c%
952130Smckusick  *
10*60599Sralph  *	@(#)if_le.c	7.11 (Berkeley) 05/29/93
1152130Smckusick  */
1252130Smckusick 
1356819Sralph #include <le.h>
1452130Smckusick #if NLE > 0
1552130Smckusick 
1656819Sralph #include <bpfilter.h>
1752130Smckusick 
1852130Smckusick /*
1952130Smckusick  * AMD 7990 LANCE
2052130Smckusick  *
2152130Smckusick  * This driver will generate and accept trailer encapsulated packets even
2252130Smckusick  * though it buys us nothing.  The motivation was to avoid incompatibilities
2352130Smckusick  * with VAXen, SUNs, and others that handle and benefit from them.
2452130Smckusick  * This reasoning is dubious.
2552130Smckusick  */
2656522Sbostic #include <sys/param.h>
2759836Sralph #include <sys/proc.h>
2856522Sbostic #include <sys/systm.h>
2956522Sbostic #include <sys/mbuf.h>
3056522Sbostic #include <sys/buf.h>
3156522Sbostic #include <sys/protosw.h>
3256522Sbostic #include <sys/socket.h>
3356522Sbostic #include <sys/syslog.h>
3456522Sbostic #include <sys/ioctl.h>
3556522Sbostic #include <sys/errno.h>
3652130Smckusick 
3756522Sbostic #include <net/if.h>
3856522Sbostic #include <net/netisr.h>
3956522Sbostic #include <net/route.h>
4052130Smckusick 
4152130Smckusick #ifdef INET
4256522Sbostic #include <netinet/in.h>
4356522Sbostic #include <netinet/in_systm.h>
4456522Sbostic #include <netinet/in_var.h>
4556522Sbostic #include <netinet/ip.h>
4656522Sbostic #include <netinet/if_ether.h>
4752130Smckusick #endif
4852130Smckusick 
4952130Smckusick #ifdef NS
5056522Sbostic #include <netns/ns.h>
5156522Sbostic #include <netns/ns_if.h>
5252130Smckusick #endif
5352130Smckusick 
5459836Sralph #if defined (CCITT) && defined (LLC)
5559836Sralph #include <sys/socketvar.h>
5659836Sralph #include <netccitt/x25.h>
5759836Sralph extern llc_ctlinput(), cons_rtrequest();
5852130Smckusick #endif
5952130Smckusick 
6056522Sbostic #include <machine/machConst.h>
6156819Sralph 
6256819Sralph #include <pmax/pmax/pmaxtype.h>
6356819Sralph #include <pmax/pmax/kn01.h>
6456819Sralph #include <pmax/pmax/kmin.h>
6556819Sralph #include <pmax/pmax/asic.h>
6656819Sralph 
6756525Sbostic #include <pmax/dev/device.h>
6856525Sbostic #include <pmax/dev/if_lereg.h>
6952130Smckusick 
7052130Smckusick #if NBPFILTER > 0
7156522Sbostic #include <net/bpf.h>
7256522Sbostic #include <net/bpfdesc.h>
7352130Smckusick #endif
7452130Smckusick 
7552130Smckusick int	leprobe();
7652695Sralph void	leintr();
7752130Smckusick struct	driver ledriver = {
7852695Sralph 	"le", leprobe, 0, 0, leintr,
7952130Smckusick };
8052130Smckusick 
8152130Smckusick int	ledebug = 1;		/* console error messages */
8252130Smckusick 
8352130Smckusick /*
8452130Smckusick  * Ethernet software status per interface.
8552130Smckusick  *
8652130Smckusick  * Each interface is referenced by a network interface structure,
8752130Smckusick  * le_if, which the routing code uses to locate the interface.
8852130Smckusick  * This structure contains the output queue for the interface, its address, ...
8952130Smckusick  */
9052130Smckusick struct	le_softc {
9152130Smckusick 	struct	arpcom sc_ac;	/* common Ethernet structures */
9252130Smckusick #define	sc_if	sc_ac.ac_if	/* network-visible interface */
9352130Smckusick #define	sc_addr	sc_ac.ac_enaddr	/* hardware Ethernet address */
9452130Smckusick 	volatile struct	lereg1 *sc_r1;	/* LANCE registers */
9556819Sralph 	volatile void *sc_r2;	/* dual-port RAM */
9656819Sralph 	int	sc_ler2pad;	/* Do ring descriptors require short pads? */
9756819Sralph 	void	(*sc_copytobuf)(); /* Copy to buffer */
9856819Sralph 	void	(*sc_copyfrombuf)(); /* Copy from buffer */
9956819Sralph 	void	(*sc_zerobuf)(); /* and Zero bytes in buffer */
10052130Smckusick 	int	sc_rmd;		/* predicted next rmd to process */
10152130Smckusick 	int	sc_tmd;		/* last tmd processed */
10252130Smckusick 	int	sc_tmdnext;	/* next tmd to transmit with */
10359836Sralph 	/* stats */
10452130Smckusick 	int	sc_runt;
10552130Smckusick 	int	sc_merr;
10652130Smckusick 	int	sc_babl;
10752130Smckusick 	int	sc_cerr;
10852130Smckusick 	int	sc_miss;
10959836Sralph 	int	sc_rown;
11052130Smckusick 	int	sc_xint;
11152130Smckusick 	int	sc_uflo;
11252130Smckusick 	int	sc_rxlen;
11352130Smckusick 	int	sc_rxoff;
11452130Smckusick 	int	sc_txoff;
11552130Smckusick 	int	sc_busy;
11652130Smckusick 	short	sc_iflags;
11752130Smckusick } le_softc[NLE];
11852130Smckusick 
11952130Smckusick /* access LANCE registers */
12056819Sralph static void lewritereg();
12152130Smckusick #define	LERDWR(cntl, src, dst)	{ (dst) = (src); DELAY(10); }
12256819Sralph #define	LEWREG(src, dst)	lewritereg(&(dst), (src))
12352130Smckusick 
12452130Smckusick #define CPU_TO_CHIP_ADDR(cpu) \
12552695Sralph 	((unsigned)(&(((struct lereg2 *)0)->cpu)))
12652695Sralph 
12752695Sralph #define LE_OFFSET_RAM		0x0
12852695Sralph #define LE_OFFSET_LANCE		0x100000
12952695Sralph #define LE_OFFSET_ROM		0x1c0000
13052695Sralph 
13156819Sralph void copytobuf_contig(), copyfrombuf_contig(), bzerobuf_contig();
13256819Sralph void copytobuf_gap2(), copyfrombuf_gap2(), bzerobuf_gap2();
13356819Sralph void copytobuf_gap16(), copyfrombuf_gap16(), bzerobuf_gap16();
13456819Sralph 
13556819Sralph extern int pmax_boardtype;
13656819Sralph extern u_long le_iomem;
13757234Sralph extern u_long asic_base;
13856819Sralph 
13952130Smckusick /*
14052130Smckusick  * Test to see if device is present.
14152130Smckusick  * Return true if found and initialized ok.
14252130Smckusick  * If interface exists, make available by filling in network interface
14352130Smckusick  * record.  System will initialize the interface when it is ready
14452130Smckusick  * to accept packets.
14552130Smckusick  */
14652130Smckusick leprobe(dp)
14752130Smckusick 	struct pmax_ctlr *dp;
14852130Smckusick {
14952130Smckusick 	volatile struct lereg1 *ler1;
15052130Smckusick 	struct le_softc *le = &le_softc[dp->pmax_unit];
15152130Smckusick 	struct ifnet *ifp = &le->sc_if;
15252130Smckusick 	u_char *cp;
15352130Smckusick 	int i;
15459836Sralph 	extern int leinit(), lereset(), leioctl(), lestart(), ether_output();
15552130Smckusick 
15656819Sralph 	switch (pmax_boardtype) {
15756819Sralph 	case DS_PMAX:
15856819Sralph 		le->sc_r1 = ler1 = (volatile struct lereg1 *)dp->pmax_addr;
15956819Sralph 		le->sc_r2 = (volatile void *)MACH_PHYS_TO_UNCACHED(0x19000000);
16056819Sralph 		cp = (u_char *)(MACH_PHYS_TO_UNCACHED(KN01_SYS_CLOCK) + 1);
16156819Sralph 		le->sc_ler2pad = 1;
16256819Sralph 		le->sc_copytobuf = copytobuf_gap2;
16356819Sralph 		le->sc_copyfrombuf = copyfrombuf_gap2;
16456819Sralph 		le->sc_zerobuf = bzerobuf_gap2;
16556819Sralph 		break;
16656819Sralph 	case DS_3MIN:
16756819Sralph 	case DS_MAXINE:
16857234Sralph 	case DS_3MAXPLUS:
16956819Sralph 		if (dp->pmax_unit == 0) {
17056819Sralph 			volatile u_int *ssr, *ldp;
17152130Smckusick 
17256819Sralph 			le->sc_r1 = ler1 = (volatile struct lereg1 *)
17357234Sralph 				ASIC_SYS_LANCE(asic_base);
17457234Sralph 			cp = (u_char *)ASIC_SYS_ETHER_ADDRESS(asic_base);
17556819Sralph 			le->sc_r2 = (volatile void *)
17656819Sralph 				MACH_PHYS_TO_UNCACHED(le_iomem);
17756819Sralph 			le->sc_ler2pad = 1;
17856819Sralph 			le->sc_copytobuf = copytobuf_gap16;
17956819Sralph 			le->sc_copyfrombuf = copyfrombuf_gap16;
18056819Sralph 			le->sc_zerobuf = bzerobuf_gap16;
18152130Smckusick 
18256819Sralph 			/*
18356819Sralph 			 * And enable Lance dma through the asic.
18456819Sralph 			 */
18557234Sralph 			ssr = (volatile u_int *)ASIC_REG_CSR(asic_base);
18656819Sralph 			ldp = (volatile u_int *)
18757234Sralph 				ASIC_REG_LANCE_DMAPTR(asic_base);
18856819Sralph 			*ldp = (le_iomem << 3);	/* phys addr << 3 */
18956819Sralph 			*ssr |= ASIC_CSR_DMAEN_LANCE;
19056819Sralph 			break;
19156819Sralph 		}
19256819Sralph 		/*
19356819Sralph 		 * Units other than 0 are turbochannel option boards and fall
19456819Sralph 		 * through to DS_3MAX.
19556819Sralph 		 */
19656819Sralph 	case DS_3MAX:
19756819Sralph 		le->sc_r1 = ler1 = (volatile struct lereg1 *)
19856819Sralph 			(dp->pmax_addr + LE_OFFSET_LANCE);
19956819Sralph 		le->sc_r2 = (volatile void *)(dp->pmax_addr + LE_OFFSET_RAM);
20056819Sralph 		cp = (u_char *)(dp->pmax_addr + LE_OFFSET_ROM + 2);
20156819Sralph 		le->sc_ler2pad = 0;
20256819Sralph 		le->sc_copytobuf = copytobuf_contig;
20356819Sralph 		le->sc_copyfrombuf = copyfrombuf_contig;
20456819Sralph 		le->sc_zerobuf = bzerobuf_contig;
20556819Sralph 		break;
20656819Sralph 	default:
20756819Sralph 		printf("Unknown CPU board type %d\n", pmax_boardtype);
20856819Sralph 		return (0);
20956819Sralph 	};
21056819Sralph 
21152695Sralph 	/*
21256819Sralph 	 * Get the ethernet address out of rom
21352695Sralph 	 */
21452695Sralph 	for (i = 0; i < sizeof(le->sc_addr); i++) {
21552695Sralph 		le->sc_addr[i] = *cp;
21652695Sralph 		cp += 4;
21752695Sralph 	}
21852695Sralph 
21952130Smckusick 	/* make sure the chip is stopped */
22056819Sralph 	LEWREG(LE_CSR0, ler1->ler1_rap);
22156819Sralph 	LEWREG(LE_STOP, ler1->ler1_rdp);
22252130Smckusick 
22352130Smckusick 	ifp->if_unit = dp->pmax_unit;
22452130Smckusick 	ifp->if_name = "le";
22552130Smckusick 	ifp->if_mtu = ETHERMTU;
22652130Smckusick 	ifp->if_init = leinit;
22759836Sralph 	ifp->if_reset = lereset;
22852130Smckusick 	ifp->if_ioctl = leioctl;
22952130Smckusick 	ifp->if_output = ether_output;
23052130Smckusick 	ifp->if_start = lestart;
23159836Sralph #ifdef MULTICAST
23259836Sralph 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
23359836Sralph #else
23452130Smckusick 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
23559836Sralph #endif
23652130Smckusick #if NBPFILTER > 0
23759836Sralph 	bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
23852130Smckusick #endif
23952130Smckusick 	if_attach(ifp);
24052130Smckusick 
24152695Sralph 	printf("le%d at nexus0 csr 0x%x priority %d ethernet address %s\n",
24252695Sralph 		dp->pmax_unit, dp->pmax_addr, dp->pmax_pri,
24352695Sralph 		ether_sprintf(le->sc_addr));
24452130Smckusick 	return (1);
24552130Smckusick }
24652130Smckusick 
24759836Sralph #ifdef MULTICAST
24859836Sralph /*
24959836Sralph  * Setup the logical address filter
25059836Sralph  */
25159836Sralph void
252*60599Sralph lesetladrf(le)
253*60599Sralph 	register struct le_softc *le;
25459836Sralph {
255*60599Sralph 	register volatile struct lereg2 *ler2 = le->sc_r2;
256*60599Sralph 	register struct ifnet *ifp = &le->sc_if;
25759836Sralph 	register struct ether_multi *enm;
25859836Sralph 	register u_char *cp;
25959836Sralph 	register u_long crc;
26059836Sralph 	register u_long c;
26159836Sralph 	register int i, len;
26259836Sralph 	struct ether_multistep step;
26359836Sralph 
26459836Sralph 	/*
26559836Sralph 	 * Set up multicast address filter by passing all multicast
26659836Sralph 	 * addresses through a crc generator, and then using the high
26759836Sralph 	 * order 6 bits as a index into the 64 bit logical address
26859836Sralph 	 * filter. The high order two bits select the word, while the
26959836Sralph 	 * rest of the bits select the bit within the word.
27059836Sralph 	 */
27159836Sralph 
272*60599Sralph 	LER2_ladrf0(ler2, 0);
273*60599Sralph 	LER2_ladrf1(ler2, 0);
27459836Sralph 	ifp->if_flags &= ~IFF_ALLMULTI;
275*60599Sralph 	ETHER_FIRST_MULTI(step, &le->sc_ac, enm);
27659836Sralph 	while (enm != NULL) {
27759836Sralph 		if (bcmp((caddr_t)&enm->enm_addrlo,
27859836Sralph 		    (caddr_t)&enm->enm_addrhi, sizeof(enm->enm_addrlo)) == 0) {
27959836Sralph 			/*
28059836Sralph 			 * We must listen to a range of multicast
28159836Sralph 			 * addresses. For now, just accept all
28259836Sralph 			 * multicasts, rather than trying to set only
28359836Sralph 			 * those filter bits needed to match the range.
28459836Sralph 			 * (At this time, the only use of address
28559836Sralph 			 * ranges is for IP multicast routing, for
28659836Sralph 			 * which the range is big enough to require all
28759836Sralph 			 * bits set.)
28859836Sralph 			 */
28959836Sralph 			LER2_ladrf0(ler2, 0xff);
29059836Sralph 			LER2_ladrf1(ler2, 0xff);
29159836Sralph 			LER2_ladrf2(ler2, 0xff);
29259836Sralph 			LER2_ladrf3(ler2, 0xff);
29359836Sralph 			ifp->if_flags |= IFF_ALLMULTI;
29459836Sralph 			return;
29559836Sralph 		}
29659836Sralph 
29759836Sralph 		cp = (unsigned char *)&enm->enm_addrlo;
29859836Sralph 		c = *cp;
29959836Sralph 		crc = 0xffffffff;
30059836Sralph 		len = 6;
30159836Sralph 		while (len-- > 0) {
30259836Sralph 			c = *cp;
30359836Sralph 			for (i = 0; i < 8; i++) {
30459836Sralph 				if ((c & 0x01) ^ (crc & 0x01)) {
30559836Sralph 					crc >>= 1;
30659836Sralph 					crc = crc ^ 0xedb88320;
30759836Sralph 				}
30859836Sralph 				else
30959836Sralph 					crc >>= 1;
31059836Sralph 				c >>= 1;
31159836Sralph 			}
31259836Sralph 			cp++;
31359836Sralph 		}
31459836Sralph 		/* Just want the 6 most significant bits. */
31559836Sralph 		crc = crc >> 26;
31659836Sralph 
31759836Sralph 		/* Turn on the corresponding bit in the filter. */
318*60599Sralph 		switch (crc >> 5) {
319*60599Sralph 		case 0:
320*60599Sralph 			LER2_ladrf0(ler2, 1 << (crc & 0x1f));
321*60599Sralph 			break;
322*60599Sralph 		case 1:
323*60599Sralph 			LER2_ladrf1(ler2, 1 << (crc & 0x1f));
324*60599Sralph 			break;
325*60599Sralph 		case 2:
326*60599Sralph 			LER2_ladrf2(ler2, 1 << (crc & 0x1f));
327*60599Sralph 			break;
328*60599Sralph 		case 3:
329*60599Sralph 			LER2_ladrf3(ler2, 1 << (crc & 0x1f));
330*60599Sralph 		}
33159836Sralph 
33259836Sralph 		ETHER_NEXT_MULTI(step, enm);
33359836Sralph 	}
33459836Sralph }
33559836Sralph #endif
33659836Sralph 
33756819Sralph ledrinit(le)
33856819Sralph 	struct le_softc *le;
33952130Smckusick {
34056819Sralph 	register volatile void *rp;
34152130Smckusick 	register int i;
34252130Smckusick 
34352130Smckusick 	for (i = 0; i < LERBUF; i++) {
34456819Sralph 		rp = LER2_RMDADDR(le->sc_r2, i);
34556819Sralph 		LER2_rmd0(rp, CPU_TO_CHIP_ADDR(ler2_rbuf[i][0]));
34656819Sralph 		LER2_rmd1(rp, LE_OWN);
34756819Sralph 		LER2_rmd2(rp, -LEMTU);
34856819Sralph 		LER2_rmd3(rp, 0);
34952130Smckusick 	}
35052130Smckusick 	for (i = 0; i < LETBUF; i++) {
35156819Sralph 		rp = LER2_TMDADDR(le->sc_r2, i);
35256819Sralph 		LER2_tmd0(rp, CPU_TO_CHIP_ADDR(ler2_tbuf[i][0]));
35356819Sralph 		LER2_tmd1(rp, 0);
35456819Sralph 		LER2_tmd2(rp, 0);
35556819Sralph 		LER2_tmd3(rp, 0);
35652130Smckusick 	}
35752130Smckusick }
35852130Smckusick 
35952130Smckusick lereset(unit)
36052130Smckusick 	register int unit;
36152130Smckusick {
36252130Smckusick 	register struct le_softc *le = &le_softc[unit];
36352130Smckusick 	register volatile struct lereg1 *ler1 = le->sc_r1;
36456819Sralph 	register volatile void *ler2 = le->sc_r2;
36552130Smckusick 	register int timo = 100000;
36652130Smckusick 	register int stat;
36752130Smckusick 
36852130Smckusick #ifdef lint
36952130Smckusick 	stat = unit;
37052130Smckusick #endif
37156819Sralph 	LEWREG(LE_CSR0, ler1->ler1_rap);
37256819Sralph 	LEWREG(LE_STOP, ler1->ler1_rdp);
37356819Sralph 
37456819Sralph 	/*
37556819Sralph 	 * Setup for transmit/receive
37656819Sralph 	 */
37752130Smckusick #if NBPFILTER > 0
37852130Smckusick 	if (le->sc_if.if_flags & IFF_PROMISC)
37952130Smckusick 		/* set the promiscuous bit */
38059836Sralph 		LER2_mode(ler2, LE_MODE | 0x8000);
38152130Smckusick 	else
38252130Smckusick #endif
38356819Sralph 		LER2_mode(ler2, LE_MODE);
38456819Sralph 	LER2_padr0(ler2, (le->sc_addr[1] << 8) | le->sc_addr[0]);
38556819Sralph 	LER2_padr1(ler2, (le->sc_addr[3] << 8) | le->sc_addr[2]);
38656819Sralph 	LER2_padr2(ler2, (le->sc_addr[5] << 8) | le->sc_addr[4]);
38759836Sralph 	/* Setup the logical address filter */
38859836Sralph #ifdef MULTICAST
38959836Sralph 	lesetladrf(le);
39052130Smckusick #else
39156819Sralph 	LER2_ladrf0(ler2, 0);
39256819Sralph 	LER2_ladrf1(ler2, 0);
39356819Sralph 	LER2_ladrf2(ler2, 0);
39456819Sralph 	LER2_ladrf3(ler2, 0);
39552130Smckusick #endif
39656819Sralph 	LER2_rlen(ler2, LE_RLEN);
39756819Sralph 	LER2_rdra(ler2, CPU_TO_CHIP_ADDR(ler2_rmd[0]));
39856819Sralph 	LER2_tlen(ler2, LE_TLEN);
39956819Sralph 	LER2_tdra(ler2, CPU_TO_CHIP_ADDR(ler2_tmd[0]));
40056819Sralph 	ledrinit(le);
40152130Smckusick 	le->sc_rmd = 0;
40252130Smckusick 	le->sc_tmd = LETBUF - 1;
40352130Smckusick 	le->sc_tmdnext = 0;
40452130Smckusick 
40556819Sralph 	LEWREG(LE_CSR1, ler1->ler1_rap);
40656819Sralph 	LEWREG(CPU_TO_CHIP_ADDR(ler2_mode), ler1->ler1_rdp);
40756819Sralph 	LEWREG(LE_CSR2, ler1->ler1_rap);
40856819Sralph 	LEWREG(0, ler1->ler1_rdp);
40956819Sralph 	LEWREG(LE_CSR3, ler1->ler1_rap);
41056819Sralph 	LEWREG(0, ler1->ler1_rdp);
41156819Sralph 	LEWREG(LE_CSR0, ler1->ler1_rap);
41252130Smckusick 	LERDWR(ler0, LE_INIT, ler1->ler1_rdp);
41352130Smckusick 	do {
41452130Smckusick 		if (--timo == 0) {
41552130Smckusick 			printf("le%d: init timeout, stat = 0x%x\n",
41652130Smckusick 			       unit, stat);
41752130Smckusick 			break;
41852130Smckusick 		}
41956819Sralph 		stat = ler1->ler1_rdp;
42052130Smckusick 	} while ((stat & LE_IDON) == 0);
42152130Smckusick 	LERDWR(ler0, LE_IDON, ler1->ler1_rdp);
42252130Smckusick 	LERDWR(ler0, LE_STRT | LE_INEA, ler1->ler1_rdp);
42352130Smckusick 	le->sc_if.if_flags &= ~IFF_OACTIVE;
42452130Smckusick }
42552130Smckusick 
42652130Smckusick /*
42752130Smckusick  * Initialization of interface
42852130Smckusick  */
42952130Smckusick leinit(unit)
43052130Smckusick 	int unit;
43152130Smckusick {
43259836Sralph 	register struct ifnet *ifp = &le_softc[unit].sc_if;
43359836Sralph 	register struct ifaddr *ifa;
43452130Smckusick 	int s;
43552130Smckusick 
43652130Smckusick 	/* not yet, if address still unknown */
43759836Sralph 	for (ifa = ifp->if_addrlist;; ifa = ifa->ifa_next)
43859836Sralph 		if (ifa == 0)
43959836Sralph 			return;
44059836Sralph 		else if (ifa->ifa_addr && ifa->ifa_addr->sa_family != AF_LINK)
44159836Sralph 			break;
44252130Smckusick 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
44352130Smckusick 		s = splnet();
44452130Smckusick 		ifp->if_flags |= IFF_RUNNING;
44552130Smckusick 		lereset(unit);
44652130Smckusick 	        (void) lestart(ifp);
44752130Smckusick 		splx(s);
44852130Smckusick 	}
44952130Smckusick }
45052130Smckusick 
45152130Smckusick #define	LENEXTTMP \
45256819Sralph 	if (++bix == LETBUF) \
45356819Sralph 		bix = 0; \
45456819Sralph 	tmd = LER2_TMDADDR(le->sc_r2, bix)
45552130Smckusick 
45652130Smckusick /*
45752130Smckusick  * Start output on interface.  Get another datagram to send
45852130Smckusick  * off of the interface queue, and copy it to the interface
45952130Smckusick  * before starting the output.
46052130Smckusick  */
46152130Smckusick lestart(ifp)
46252130Smckusick 	struct ifnet *ifp;
46352130Smckusick {
46452130Smckusick 	register struct le_softc *le = &le_softc[ifp->if_unit];
46552130Smckusick 	register int bix = le->sc_tmdnext;
46656819Sralph 	register volatile void *tmd = LER2_TMDADDR(le->sc_r2, bix);
46752130Smckusick 	register struct mbuf *m;
46852130Smckusick 	int len = 0;
46952130Smckusick 
47052130Smckusick 	if ((le->sc_if.if_flags & IFF_RUNNING) == 0)
47152130Smckusick 		return (0);
47252130Smckusick 	while (bix != le->sc_tmd) {
47356819Sralph 		if (LER2V_tmd1(tmd) & LE_OWN)
47452130Smckusick 			panic("lestart");
47552130Smckusick 		IF_DEQUEUE(&le->sc_if.if_snd, m);
47652130Smckusick 		if (m == 0)
47752130Smckusick 			break;
47859836Sralph 		len = leput(le, LER2_TBUFADDR(le->sc_r2, bix), m);
47952130Smckusick #if NBPFILTER > 0
48052130Smckusick 		/*
48152130Smckusick 		 * If bpf is listening on this interface, let it
48252130Smckusick 		 * see the packet before we commit it to the wire.
48352130Smckusick 		 */
48459836Sralph 		if (ifp->if_bpf)
48559836Sralph 			bpf_tap(ifp->if_bpf,
48659836Sralph 				LER2_TBUFADDR(le->sc_r2, le->sc_tmd), len);
48752130Smckusick #endif
48856819Sralph 		LER2_tmd3(tmd, 0);
48956819Sralph 		LER2_tmd2(tmd, -len);
49056819Sralph 		LER2_tmd1(tmd, LE_OWN | LE_STP | LE_ENP);
49152130Smckusick 		LENEXTTMP;
49252130Smckusick 	}
49352130Smckusick 	if (len != 0) {
49452130Smckusick 		le->sc_if.if_flags |= IFF_OACTIVE;
49552130Smckusick 		LERDWR(ler0, LE_TDMD | LE_INEA, le->sc_r1->ler1_rdp);
49652130Smckusick 	}
49752130Smckusick 	le->sc_tmdnext = bix;
49852130Smckusick 	return (0);
49952130Smckusick }
50052130Smckusick 
50152130Smckusick /*
50252130Smckusick  * Process interrupts from the 7990 chip.
50352130Smckusick  */
50452695Sralph void
50552695Sralph leintr(unit)
50652695Sralph 	int unit;
50752130Smckusick {
50852130Smckusick 	register struct le_softc *le;
50952130Smckusick 	register volatile struct lereg1 *ler1;
51052695Sralph 	register int stat;
51152130Smckusick 
51252130Smckusick 	le = &le_softc[unit];
51352130Smckusick 	ler1 = le->sc_r1;
51452130Smckusick 	stat = ler1->ler1_rdp;
51552130Smckusick 	if (!(stat & LE_INTR)) {
51653081Sralph 		printf("le%d: spurrious interrupt\n", unit);
51752130Smckusick 		return;
51852130Smckusick 	}
51952130Smckusick 	if (stat & LE_SERR) {
52052130Smckusick 		leerror(unit, stat);
52152130Smckusick 		if (stat & LE_MERR) {
52252130Smckusick 			le->sc_merr++;
52352130Smckusick 			lereset(unit);
52452130Smckusick 			return;
52552130Smckusick 		}
52652130Smckusick 		if (stat & LE_BABL)
52752130Smckusick 			le->sc_babl++;
52852130Smckusick 		if (stat & LE_CERR)
52952130Smckusick 			le->sc_cerr++;
53052130Smckusick 		if (stat & LE_MISS)
53152130Smckusick 			le->sc_miss++;
53252130Smckusick 		LERDWR(ler0, LE_BABL|LE_CERR|LE_MISS|LE_INEA, ler1->ler1_rdp);
53352130Smckusick 	}
53452130Smckusick 	if ((stat & LE_RXON) == 0) {
53552130Smckusick 		le->sc_rxoff++;
53652130Smckusick 		lereset(unit);
53752130Smckusick 		return;
53852130Smckusick 	}
53952130Smckusick 	if ((stat & LE_TXON) == 0) {
54052130Smckusick 		le->sc_txoff++;
54152130Smckusick 		lereset(unit);
54252130Smckusick 		return;
54352130Smckusick 	}
54452130Smckusick 	if (stat & LE_RINT) {
54552130Smckusick 		/* interrupt is cleared in lerint */
54652130Smckusick 		lerint(unit);
54752130Smckusick 	}
54852130Smckusick 	if (stat & LE_TINT) {
54952130Smckusick 		LERDWR(ler0, LE_TINT|LE_INEA, ler1->ler1_rdp);
55052130Smckusick 		lexint(unit);
55152130Smckusick 	}
55252130Smckusick }
55352130Smckusick 
55452130Smckusick /*
55552130Smckusick  * Ethernet interface transmitter interrupt.
55652130Smckusick  * Start another output if more data to send.
55752130Smckusick  */
55852130Smckusick lexint(unit)
55952130Smckusick 	register int unit;
56052130Smckusick {
56152130Smckusick 	register struct le_softc *le = &le_softc[unit];
56252130Smckusick 	register int bix = le->sc_tmd;
56356819Sralph 	register volatile void *tmd;
56452130Smckusick 
56552130Smckusick 	if ((le->sc_if.if_flags & IFF_OACTIVE) == 0) {
56652130Smckusick 		le->sc_xint++;
56752130Smckusick 		return;
56852130Smckusick 	}
56952130Smckusick 	LENEXTTMP;
57056819Sralph 	while (bix != le->sc_tmdnext && (LER2V_tmd1(tmd) & LE_OWN) == 0) {
57152130Smckusick 		le->sc_tmd = bix;
57256819Sralph 		if ((LER2V_tmd1(tmd) & LE_ERR) || (LER2V_tmd3(tmd) & LE_TBUFF)) {
57352130Smckusick 			lexerror(unit);
57452130Smckusick 			le->sc_if.if_oerrors++;
57556819Sralph 			if (LER2V_tmd3(tmd) & (LE_TBUFF|LE_UFLO)) {
57652130Smckusick 				le->sc_uflo++;
57752130Smckusick 				lereset(unit);
57852130Smckusick 				break;
57952130Smckusick 			}
58056819Sralph 			else if (LER2V_tmd3(tmd) & LE_LCOL)
58152130Smckusick 				le->sc_if.if_collisions++;
58256819Sralph 			else if (LER2V_tmd3(tmd) & LE_RTRY)
58352130Smckusick 				le->sc_if.if_collisions += 16;
58452130Smckusick 		}
58556819Sralph 		else if (LER2V_tmd1(tmd) & LE_ONE)
58652130Smckusick 			le->sc_if.if_collisions++;
58756819Sralph 		else if (LER2V_tmd1(tmd) & LE_MORE)
58852130Smckusick 			/* what is the real number? */
58952130Smckusick 			le->sc_if.if_collisions += 2;
59052130Smckusick 		else
59152130Smckusick 			le->sc_if.if_opackets++;
59252130Smckusick 		LENEXTTMP;
59352130Smckusick 	}
59452130Smckusick 	if (bix == le->sc_tmdnext)
59552130Smckusick 		le->sc_if.if_flags &= ~IFF_OACTIVE;
59652130Smckusick 	(void) lestart(&le->sc_if);
59752130Smckusick }
59852130Smckusick 
59952130Smckusick #define	LENEXTRMP \
60056819Sralph 	if (++bix == LERBUF) \
60156819Sralph 		bix = 0; \
60256819Sralph 	rmd = LER2_RMDADDR(le->sc_r2, bix)
60352130Smckusick 
60452130Smckusick /*
60552130Smckusick  * Ethernet interface receiver interrupt.
60652130Smckusick  * If input error just drop packet.
60752130Smckusick  * Decapsulate packet based on type and pass to type specific
60852130Smckusick  * higher-level input routine.
60952130Smckusick  */
61052130Smckusick lerint(unit)
61152130Smckusick 	int unit;
61252130Smckusick {
61352130Smckusick 	register struct le_softc *le = &le_softc[unit];
61452130Smckusick 	register int bix = le->sc_rmd;
61556819Sralph 	register volatile void *rmd = LER2_RMDADDR(le->sc_r2, bix);
61652130Smckusick 
61752130Smckusick 	/*
61852130Smckusick 	 * Out of sync with hardware, should never happen?
61952130Smckusick 	 */
62056819Sralph 	if (LER2V_rmd1(rmd) & LE_OWN) {
62159836Sralph 		le->sc_rown++;
62252130Smckusick 		LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
62352130Smckusick 		return;
62452130Smckusick 	}
62552130Smckusick 
62652130Smckusick 	/*
62752130Smckusick 	 * Process all buffers with valid data
62852130Smckusick 	 */
62956819Sralph 	while ((LER2V_rmd1(rmd) & LE_OWN) == 0) {
63056819Sralph 		int len = LER2V_rmd3(rmd);
63152130Smckusick 
63252130Smckusick 		/* Clear interrupt to avoid race condition */
63352130Smckusick 		LERDWR(le->sc_r0, LE_RINT|LE_INEA, le->sc_r1->ler1_rdp);
63452130Smckusick 
63556819Sralph 		if (LER2V_rmd1(rmd) & LE_ERR) {
63652130Smckusick 			le->sc_rmd = bix;
63752130Smckusick 			lererror(unit, "bad packet");
63852130Smckusick 			le->sc_if.if_ierrors++;
63956819Sralph 		} else if ((LER2V_rmd1(rmd) & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP)) {
64052130Smckusick 			/*
64152130Smckusick 			 * Find the end of the packet so we can see how long
64252130Smckusick 			 * it was.  We still throw it away.
64352130Smckusick 			 */
64452130Smckusick 			do {
64552130Smckusick 				LERDWR(le->sc_r0, LE_RINT|LE_INEA,
64652130Smckusick 				       le->sc_r1->ler1_rdp);
64756819Sralph 				LER2_rmd3(rmd, 0);
64856819Sralph 				LER2_rmd1(rmd, LE_OWN);
64952130Smckusick 				LENEXTRMP;
65056819Sralph 			} while (!(LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP)));
65152130Smckusick 			le->sc_rmd = bix;
65252130Smckusick 			lererror(unit, "chained buffer");
65352130Smckusick 			le->sc_rxlen++;
65452130Smckusick 			/*
65552130Smckusick 			 * If search terminated without successful completion
65652130Smckusick 			 * we reset the hardware (conservative).
65752130Smckusick 			 */
65856819Sralph 			if ((LER2V_rmd1(rmd) & (LE_OWN|LE_ERR|LE_STP|LE_ENP)) !=
65952130Smckusick 			    LE_ENP) {
66052130Smckusick 				lereset(unit);
66152130Smckusick 				return;
66252130Smckusick 			}
66352130Smckusick 		} else
66456819Sralph 			leread(unit, LER2_RBUFADDR(le->sc_r2, bix), len);
66556819Sralph 		LER2_rmd3(rmd, 0);
66656819Sralph 		LER2_rmd1(rmd, LE_OWN);
66752130Smckusick 		LENEXTRMP;
66852130Smckusick 	}
66952130Smckusick 	MachEmptyWriteBuffer();		/* Paranoia */
67052130Smckusick 	le->sc_rmd = bix;
67152130Smckusick }
67252130Smckusick 
67352130Smckusick /*
67452130Smckusick  * Look at the packet in network buffer memory so we can be smart about how
67552130Smckusick  * we copy the data into mbufs.
67652130Smckusick  * This needs work since we can't just read network buffer memory like
67752130Smckusick  * regular memory.
67852130Smckusick  */
67952130Smckusick leread(unit, buf, len)
68052130Smckusick 	int unit;
68156819Sralph 	volatile void *buf;
68252130Smckusick 	int len;
68352130Smckusick {
68452130Smckusick 	register struct le_softc *le = &le_softc[unit];
68552130Smckusick 	struct ether_header et;
68656819Sralph     	struct mbuf *m, **hdrmp, **tailmp;
68759836Sralph 	int off, resid, flags;
68856819Sralph 	u_short sbuf[2], eth_type;
68952695Sralph 	extern struct mbuf *leget();
69052130Smckusick 
69152130Smckusick 	le->sc_if.if_ipackets++;
69256819Sralph 	(*le->sc_copyfrombuf)(buf, 0, (char *)&et, sizeof (et));
69356819Sralph 	eth_type = ntohs(et.ether_type);
69452130Smckusick 	/* adjust input length to account for header and CRC */
69552130Smckusick 	len = len - sizeof(struct ether_header) - 4;
69652130Smckusick 
69756819Sralph 	if (eth_type >= ETHERTYPE_TRAIL &&
69856819Sralph 	    eth_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
69956819Sralph 		off = (eth_type - ETHERTYPE_TRAIL) * 512;
70052130Smckusick 		if (off >= ETHERMTU)
70152130Smckusick 			return;		/* sanity */
70256819Sralph 		(*le->sc_copyfrombuf)(buf, sizeof (et) + off, (char *)sbuf,
70356819Sralph 			sizeof (sbuf));
70456819Sralph 		eth_type = ntohs(sbuf[0]);
70552130Smckusick 		resid = ntohs(sbuf[1]);
70652130Smckusick 		if (off + resid > len)
70752130Smckusick 			return;		/* sanity */
70852130Smckusick 		len = off + resid;
70952130Smckusick 	} else
71052130Smckusick 		off = 0;
71152130Smckusick 
71252130Smckusick 	if (len <= 0) {
71352130Smckusick 		if (ledebug)
71452130Smckusick 			log(LOG_WARNING,
71552130Smckusick 			    "le%d: ierror(runt packet): from %s: len=%d\n",
71652130Smckusick 			    unit, ether_sprintf(et.ether_shost), len);
71752130Smckusick 		le->sc_runt++;
71852130Smckusick 		le->sc_if.if_ierrors++;
71952130Smckusick 		return;
72052130Smckusick 	}
72159836Sralph 	flags = 0;
72259836Sralph 	if (bcmp((caddr_t)etherbroadcastaddr,
72359836Sralph 	    (caddr_t)et.ether_dhost, sizeof(etherbroadcastaddr)) == 0)
72459836Sralph 		flags |= M_BCAST;
72559836Sralph 	if (et.ether_dhost[0] & 1)
72659836Sralph 		flags |= M_MCAST;
72752130Smckusick 
72859836Sralph #if NBPFILTER > 0
72952130Smckusick 	/*
73059836Sralph 	 * Check if there's a bpf filter listening on this interface.
73159836Sralph 	 * If so, hand off the raw packet to enet.
73259836Sralph 	 */
73359836Sralph 	if (le->sc_if.if_bpf) {
73459836Sralph 		bpf_tap(le->sc_if.if_bpf, buf, len + sizeof(struct ether_header));
73559836Sralph 
73659836Sralph 		/*
73759836Sralph 		 * Keep the packet if it's a broadcast or has our
73859836Sralph 		 * physical ethernet address (or if we support
73959836Sralph 		 * multicast and it's one).
74059836Sralph 		 */
74159836Sralph 		if (
74259836Sralph #ifdef MULTICAST
74359836Sralph 		    (flags & (M_BCAST | M_MCAST)) == 0 &&
74459836Sralph #else
74559836Sralph 		    (flags & M_BCAST) == 0 &&
74659836Sralph #endif
74759836Sralph 		    bcmp(et.ether_dhost, le->sc_addr,
74859836Sralph 			sizeof(et.ether_dhost)) != 0)
74959836Sralph 			return;
75059836Sralph 	}
75159836Sralph #endif
75259836Sralph 
75359836Sralph 	/*
75452130Smckusick 	 * Pull packet off interface.  Off is nonzero if packet
75552130Smckusick 	 * has trailing header; leget will then force this header
75652130Smckusick 	 * information to be at the front, but we still have to drop
75752130Smckusick 	 * the type and length which are at the front of any trailer data.
75856819Sralph 	 * The hdrmp and tailmp pointers are used by lebpf_tap() to
75956819Sralph 	 * temporarily reorder the mbuf list. See the comment at the beginning
76056819Sralph 	 * of lebpf_tap() for all the ugly details.
76152130Smckusick 	 */
76256819Sralph 	m = leget(le, buf, len, off, &le->sc_if, &hdrmp, &tailmp);
76352130Smckusick 	if (m == 0)
76452130Smckusick 		return;
76559836Sralph 	m->m_flags |= flags;
76656819Sralph 	et.ether_type = eth_type;
76752130Smckusick 	ether_input(&le->sc_if, &et, m);
76852130Smckusick }
76952130Smckusick 
77052130Smckusick /*
77152130Smckusick  * Routine to copy from mbuf chain to transmit buffer in
77252130Smckusick  * network buffer memory.
77352130Smckusick  */
77456819Sralph leput(le, lebuf, m)
77556819Sralph 	struct le_softc *le;
77656819Sralph 	register volatile void *lebuf;
77752130Smckusick 	register struct mbuf *m;
77852130Smckusick {
77952130Smckusick 	register struct mbuf *mp;
78052695Sralph 	register int len, tlen = 0;
78156819Sralph 	register int boff = 0;
78252130Smckusick 
78352130Smckusick 	for (mp = m; mp; mp = mp->m_next) {
78452130Smckusick 		len = mp->m_len;
78552130Smckusick 		if (len == 0)
78652130Smckusick 			continue;
78756819Sralph 		(*le->sc_copytobuf)(mtod(mp, char *), lebuf, boff, len);
78852130Smckusick 		tlen += len;
78956819Sralph 		boff += len;
79052130Smckusick 	}
79152130Smckusick 	m_freem(m);
79252695Sralph 	if (tlen < LEMINSIZE) {
79356819Sralph 		(*le->sc_zerobuf)(lebuf, boff, LEMINSIZE - tlen);
79452130Smckusick 		tlen = LEMINSIZE;
79552695Sralph 	}
79652130Smckusick 	return(tlen);
79752130Smckusick }
79852130Smckusick 
79952130Smckusick /*
80052130Smckusick  * Routine to copy from network buffer memory into mbufs.
80152130Smckusick  */
80252130Smckusick struct mbuf *
80356819Sralph leget(le, lebuf, totlen, off, ifp, hdrmp, tailmp)
80456819Sralph 	struct le_softc *le;
80556819Sralph 	volatile void *lebuf;
80652130Smckusick 	int totlen, off;
80752130Smckusick 	struct ifnet *ifp;
80856819Sralph 	struct mbuf ***hdrmp, ***tailmp;
80952130Smckusick {
81052130Smckusick 	register struct mbuf *m;
81152130Smckusick 	struct mbuf *top = 0, **mp = &top;
81256819Sralph 	register int len, resid, boff;
81352130Smckusick 
81452130Smckusick 	/* NOTE: sizeof(struct ether_header) should be even */
81556819Sralph 	boff = sizeof(struct ether_header);
81652130Smckusick 	if (off) {
81752130Smckusick 		/* NOTE: off should be even */
81856819Sralph 		boff += off + 2 * sizeof(u_short);
81952130Smckusick 		totlen -= 2 * sizeof(u_short);
82052130Smckusick 		resid = totlen - off;
82152130Smckusick 	} else
82252130Smckusick 		resid = totlen;
82352130Smckusick 
82452130Smckusick 	MGETHDR(m, M_DONTWAIT, MT_DATA);
82552130Smckusick 	if (m == 0)
82652130Smckusick 		return (0);
82752130Smckusick 	m->m_pkthdr.rcvif = ifp;
82852130Smckusick 	m->m_pkthdr.len = totlen;
82952130Smckusick 	m->m_len = MHLEN;
83052130Smckusick 
83152130Smckusick 	while (totlen > 0) {
83252130Smckusick 		if (top) {
83352130Smckusick 			MGET(m, M_DONTWAIT, MT_DATA);
83452130Smckusick 			if (m == 0) {
83552130Smckusick 				m_freem(top);
83652130Smckusick 				return (0);
83752130Smckusick 			}
83852130Smckusick 			m->m_len = MLEN;
83952130Smckusick 		}
84052130Smckusick 
84152130Smckusick 		if (resid >= MINCLSIZE)
84252130Smckusick 			MCLGET(m, M_DONTWAIT);
84352130Smckusick 		if (m->m_flags & M_EXT)
84455745Sralph 			m->m_len = min(resid, MCLBYTES);
84552130Smckusick 		else if (resid < m->m_len) {
84652130Smckusick 			/*
84752130Smckusick 			 * Place initial small packet/header at end of mbuf.
84852130Smckusick 			 */
84952130Smckusick 			if (top == 0 && resid + max_linkhdr <= m->m_len)
85052130Smckusick 				m->m_data += max_linkhdr;
85152130Smckusick 			m->m_len = resid;
85252130Smckusick 		}
85352130Smckusick 		len = m->m_len;
85456819Sralph 		(*le->sc_copyfrombuf)(lebuf, boff, mtod(m, char *), len);
85556819Sralph 		boff += len;
85652130Smckusick 		*mp = m;
85752130Smckusick 		mp = &m->m_next;
85852130Smckusick 		totlen -= len;
85952130Smckusick 		resid -= len;
86052130Smckusick 		if (resid == 0) {
86156819Sralph 			boff = sizeof (struct ether_header);
86252130Smckusick 			resid = totlen;
86356819Sralph 			*hdrmp = mp;
86452130Smckusick 		}
86552130Smckusick 	}
86656819Sralph 	*tailmp = mp;
86752130Smckusick 	return (top);
86852130Smckusick }
86952130Smckusick 
87052130Smckusick /*
87152130Smckusick  * Process an ioctl request.
87252130Smckusick  */
87352130Smckusick leioctl(ifp, cmd, data)
87452130Smckusick 	register struct ifnet *ifp;
87552130Smckusick 	int cmd;
87652130Smckusick 	caddr_t data;
87752130Smckusick {
87852130Smckusick 	register struct ifaddr *ifa = (struct ifaddr *)data;
87952130Smckusick 	struct le_softc *le = &le_softc[ifp->if_unit];
88052130Smckusick 	volatile struct lereg1 *ler1 = le->sc_r1;
88152130Smckusick 	int s, error = 0;
88252130Smckusick 
88352130Smckusick 	s = splnet();
88452130Smckusick 	switch (cmd) {
88552130Smckusick 
88652130Smckusick 	case SIOCSIFADDR:
88752130Smckusick 		ifp->if_flags |= IFF_UP;
88852130Smckusick 		switch (ifa->ifa_addr->sa_family) {
88952130Smckusick #ifdef INET
89052130Smckusick 		case AF_INET:
89152130Smckusick 			leinit(ifp->if_unit);	/* before arpwhohas */
89252130Smckusick 			((struct arpcom *)ifp)->ac_ipaddr =
89352130Smckusick 				IA_SIN(ifa)->sin_addr;
89452130Smckusick 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
89552130Smckusick 			break;
89652130Smckusick #endif
89752130Smckusick #ifdef NS
89852130Smckusick 		case AF_NS:
89952130Smckusick 		    {
90052130Smckusick 			register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
90152130Smckusick 
90252130Smckusick 			if (ns_nullhost(*ina))
90352130Smckusick 				ina->x_host = *(union ns_host *)(le->sc_addr);
90452130Smckusick 			else {
90552130Smckusick 				/*
90652130Smckusick 				 * The manual says we can't change the address
90752130Smckusick 				 * while the receiver is armed,
90852130Smckusick 				 * so reset everything
90952130Smckusick 				 */
91052130Smckusick 				ifp->if_flags &= ~IFF_RUNNING;
91159836Sralph 				LEWREG(LE_STOP, ler1->ler1_rdp);
91252130Smckusick 				bcopy((caddr_t)ina->x_host.c_host,
91352130Smckusick 				    (caddr_t)le->sc_addr, sizeof(le->sc_addr));
91452130Smckusick 			}
91552130Smckusick 			leinit(ifp->if_unit); /* does le_setaddr() */
91652130Smckusick 			break;
91752130Smckusick 		    }
91852130Smckusick #endif
91952130Smckusick 		default:
92052130Smckusick 			leinit(ifp->if_unit);
92152130Smckusick 			break;
92252130Smckusick 		}
92352130Smckusick 		break;
92452130Smckusick 
92559836Sralph #if defined (CCITT) && defined (LLC)
92659836Sralph 	case SIOCSIFCONF_X25:
92759836Sralph 		ifp->if_flags |= IFF_UP;
92859836Sralph 		ifa->ifa_rtrequest = cons_rtrequest;
92959836Sralph 		error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);
93059836Sralph 		if (error == 0)
93159836Sralph 			leinit(ifp->if_unit);
93259836Sralph 		break;
93359836Sralph #endif /* CCITT && LLC */
93459836Sralph 
93552130Smckusick 	case SIOCSIFFLAGS:
93652130Smckusick 		if ((ifp->if_flags & IFF_UP) == 0 &&
93752130Smckusick 		    ifp->if_flags & IFF_RUNNING) {
93856819Sralph 			LEWREG(LE_STOP, ler1->ler1_rdp);
93952130Smckusick 			ifp->if_flags &= ~IFF_RUNNING;
94052130Smckusick 		} else if (ifp->if_flags & IFF_UP &&
94152130Smckusick 		    (ifp->if_flags & IFF_RUNNING) == 0)
94252130Smckusick 			leinit(ifp->if_unit);
94352130Smckusick 		/*
94452130Smckusick 		 * If the state of the promiscuous bit changes, the interface
94552130Smckusick 		 * must be reset to effect the change.
94652130Smckusick 		 */
94752130Smckusick 		if (((ifp->if_flags ^ le->sc_iflags) & IFF_PROMISC) &&
94852130Smckusick 		    (ifp->if_flags & IFF_RUNNING)) {
94952130Smckusick 			le->sc_iflags = ifp->if_flags;
95052130Smckusick 			lereset(ifp->if_unit);
95152130Smckusick 			lestart(ifp);
95252130Smckusick 		}
95352130Smckusick 		break;
95452130Smckusick 
95559836Sralph #ifdef MULTICAST
95659836Sralph 	case SIOCADDMULTI:
95759836Sralph 	case SIOCDELMULTI:
95859836Sralph 		/* Update our multicast list  */
95959836Sralph 		error = (cmd == SIOCADDMULTI) ?
96059836Sralph 		    ether_addmulti((struct ifreq *)data, &le->sc_ac) :
96159836Sralph 		    ether_delmulti((struct ifreq *)data, &le->sc_ac);
96259836Sralph 
96359836Sralph 		if (error == ENETRESET) {
96459836Sralph 			/*
96559836Sralph 			 * Multicast list has changed; set the hardware
96659836Sralph 			 * filter accordingly.
96759836Sralph 			 */
96859836Sralph 			lereset(ifp->if_unit);
96959836Sralph 			error = 0;
97059836Sralph 		}
97159836Sralph 		break;
97259836Sralph #endif
97359836Sralph 
97452130Smckusick 	default:
97552130Smckusick 		error = EINVAL;
97652130Smckusick 	}
97752130Smckusick 	splx(s);
97852130Smckusick 	return (error);
97952130Smckusick }
98052130Smckusick 
98152130Smckusick leerror(unit, stat)
98252130Smckusick 	int unit;
98352130Smckusick 	int stat;
98452130Smckusick {
98552130Smckusick 	if (!ledebug)
98652130Smckusick 		return;
98752130Smckusick 
98852130Smckusick 	/*
98952130Smckusick 	 * Not all transceivers implement heartbeat
99052130Smckusick 	 * so we only log CERR once.
99152130Smckusick 	 */
99252130Smckusick 	if ((stat & LE_CERR) && le_softc[unit].sc_cerr)
99352130Smckusick 		return;
99452130Smckusick 	log(LOG_WARNING,
99552130Smckusick 	    "le%d: error: stat=%b\n", unit,
99652130Smckusick 	    stat,
99752130Smckusick 	    "\20\20ERR\17BABL\16CERR\15MISS\14MERR\13RINT\12TINT\11IDON\10INTR\07INEA\06RXON\05TXON\04TDMD\03STOP\02STRT\01INIT");
99852130Smckusick }
99952130Smckusick 
100052130Smckusick lererror(unit, msg)
100152130Smckusick 	int unit;
100252130Smckusick 	char *msg;
100352130Smckusick {
100452130Smckusick 	register struct le_softc *le = &le_softc[unit];
100556819Sralph 	register volatile void *rmd;
100654144Sralph 	u_char eaddr[6];
100752130Smckusick 	int len;
100852130Smckusick 
100952130Smckusick 	if (!ledebug)
101052130Smckusick 		return;
101152130Smckusick 
101256819Sralph 	rmd = LER2_RMDADDR(le->sc_r2, le->sc_rmd);
101356819Sralph 	len = LER2V_rmd3(rmd);
101456819Sralph 	if (len > 11)
101556819Sralph 		(*le->sc_copyfrombuf)(LER2_RBUFADDR(le->sc_r2, le->sc_rmd),
101656819Sralph 			6, eaddr, 6);
101752130Smckusick 	log(LOG_WARNING,
101852130Smckusick 	    "le%d: ierror(%s): from %s: buf=%d, len=%d, rmd1=%b\n",
101956819Sralph 	    unit, msg,
102056819Sralph 	    len > 11 ? ether_sprintf(eaddr) : "unknown",
102156819Sralph 	    le->sc_rmd, len,
102256819Sralph 	    LER2V_rmd1(rmd),
102352130Smckusick 	    "\20\20OWN\17ERR\16FRAM\15OFLO\14CRC\13RBUF\12STP\11ENP");
102452130Smckusick }
102552130Smckusick 
102652130Smckusick lexerror(unit)
102752130Smckusick 	int unit;
102852130Smckusick {
102952130Smckusick 	register struct le_softc *le = &le_softc[unit];
103056819Sralph 	register volatile void *tmd;
103154144Sralph 	u_char eaddr[6];
103252130Smckusick 	int len;
103352130Smckusick 
103452130Smckusick 	if (!ledebug)
103552130Smckusick 		return;
103652130Smckusick 
103756819Sralph 	tmd = LER2_TMDADDR(le->sc_r2, 0);
103856819Sralph 	len = -LER2V_tmd2(tmd);
103956819Sralph 	if (len > 5)
104056819Sralph 		(*le->sc_copyfrombuf)(LER2_TBUFADDR(le->sc_r2, 0), 0, eaddr, 6);
104152130Smckusick 	log(LOG_WARNING,
104252130Smckusick 	    "le%d: oerror: to %s: buf=%d, len=%d, tmd1=%b, tmd3=%b\n",
104356819Sralph 	    unit,
104456819Sralph 	    len > 5 ? ether_sprintf(eaddr) : "unknown",
104556819Sralph 	    0, len,
104656819Sralph 	    LER2V_tmd1(tmd),
104752130Smckusick 	    "\20\20OWN\17ERR\16RES\15MORE\14ONE\13DEF\12STP\11ENP",
104856819Sralph 	    LER2V_tmd3(tmd),
104952130Smckusick 	    "\20\20BUFF\17UFLO\16RES\15LCOL\14LCAR\13RTRY");
105052130Smckusick }
105156819Sralph 
105256819Sralph /*
105356819Sralph  * Write a lance register port, reading it back to ensure success. This seems
105456819Sralph  * to be necessary during initialization, since the chip appears to be a bit
105556819Sralph  * pokey sometimes.
105656819Sralph  */
105756819Sralph static void
105856819Sralph lewritereg(regptr, val)
105956819Sralph 	register volatile u_short *regptr;
106056819Sralph 	register u_short val;
106156819Sralph {
106256819Sralph 	register int i = 0;
106356819Sralph 
106456819Sralph 	while (*regptr != val) {
106556819Sralph 		*regptr = val;
106656819Sralph 		MachEmptyWriteBuffer();
106756819Sralph 		if (++i > 10000) {
106856819Sralph 			printf("le: Reg did not settle (to x%x): x%x\n",
106956819Sralph 			       val, *regptr);
107056819Sralph 			return;
107156819Sralph 		}
107256819Sralph 		DELAY(100);
107356819Sralph 	}
107456819Sralph }
107556819Sralph 
107656819Sralph /*
107756819Sralph  * Routines for accessing the transmit and receive buffers. Unfortunately,
107856819Sralph  * CPU addressing of these buffers is done in one of 3 ways:
107956819Sralph  * - contiguous (for the 3max and turbochannel option card)
108056819Sralph  * - gap2, which means shorts (2 bytes) interspersed with short (2 byte)
108156819Sralph  *   spaces (for the pmax)
108256819Sralph  * - gap16, which means 16bytes interspersed with 16byte spaces
108356819Sralph  *   for buffers which must begin on a 32byte boundary (for 3min and maxine)
108456819Sralph  * The buffer offset is the logical byte offset, assuming contiguous storage.
108556819Sralph  */
108656819Sralph void
108756819Sralph copytobuf_contig(from, lebuf, boff, len)
108856819Sralph 	char *from;
108956819Sralph 	volatile void *lebuf;
109056819Sralph 	int boff;
109156819Sralph 	int len;
109256819Sralph {
109356819Sralph 
109456819Sralph 	/*
109556819Sralph 	 * Just call bcopy() to do the work.
109656819Sralph 	 */
109756819Sralph 	bcopy(from, ((char *)lebuf) + boff, len);
109856819Sralph }
109956819Sralph 
110056819Sralph void
110156819Sralph copyfrombuf_contig(lebuf, boff, to, len)
110256819Sralph 	volatile void *lebuf;
110356819Sralph 	int boff;
110456819Sralph 	char *to;
110556819Sralph 	int len;
110656819Sralph {
110756819Sralph 
110856819Sralph 	/*
110956819Sralph 	 * Just call bcopy() to do the work.
111056819Sralph 	 */
111156819Sralph 	bcopy(((char *)lebuf) + boff, to, len);
111256819Sralph }
111356819Sralph 
111456819Sralph void
111556819Sralph bzerobuf_contig(lebuf, boff, len)
111656819Sralph 	volatile void *lebuf;
111756819Sralph 	int boff;
111856819Sralph 	int len;
111956819Sralph {
112056819Sralph 
112156819Sralph 	/*
112256819Sralph 	 * Just let bzero() do the work
112356819Sralph 	 */
112456819Sralph 	bzero(((char *)lebuf) + boff, len);
112556819Sralph }
112656819Sralph 
112756819Sralph /*
112856819Sralph  * For the pmax the buffer consists of shorts (2 bytes) interspersed with
112956819Sralph  * short (2 byte) spaces and must be accessed with halfword load/stores.
113056819Sralph  * (don't worry about doing an extra byte)
113156819Sralph  */
113256819Sralph void
113356819Sralph copytobuf_gap2(from, lebuf, boff, len)
113456819Sralph 	register char *from;
113556819Sralph 	volatile void *lebuf;
113656819Sralph 	int boff;
113756819Sralph 	register int len;
113856819Sralph {
113956819Sralph 	register volatile u_short *bptr;
114056819Sralph 	register int xfer;
114156819Sralph 
114256819Sralph 	if (boff & 0x1) {
114356819Sralph 		/* handle unaligned first byte */
114456819Sralph 		bptr = ((volatile u_short *)lebuf) + (boff - 1);
114556819Sralph 		*bptr = (*from++ << 8) | (*bptr & 0xff);
114656819Sralph 		bptr += 2;
114756819Sralph 		len--;
114856819Sralph 	} else
114956819Sralph 		bptr = ((volatile u_short *)lebuf) + boff;
115056819Sralph 	if ((unsigned)from & 0x1) {
115156819Sralph 		while (len > 1) {
115256819Sralph 			*bptr = (from[1] << 8) | from[0];
115356819Sralph 			bptr += 2;
115456819Sralph 			from += 2;
115556819Sralph 			len -= 2;
115656819Sralph 		}
115756819Sralph 	} else {
115856819Sralph 		/* optimize for aligned transfers */
115956819Sralph 		xfer = (int)((unsigned)len & ~0x1);
116056819Sralph 		CopyToBuffer((u_short *)from, bptr, xfer);
116156819Sralph 		bptr += xfer;
116256819Sralph 		from += xfer;
116356819Sralph 		len -= xfer;
116456819Sralph 	}
116556819Sralph 	if (len == 1)
116656819Sralph 		*bptr = (u_short)*from;
116756819Sralph }
116856819Sralph 
116956819Sralph void
117056819Sralph copyfrombuf_gap2(lebuf, boff, to, len)
117156819Sralph 	volatile void *lebuf;
117256819Sralph 	int boff;
117356819Sralph 	register char *to;
117456819Sralph 	register int len;
117556819Sralph {
117656819Sralph 	register volatile u_short *bptr;
117756819Sralph 	register u_short tmp;
117856819Sralph 	register int xfer;
117956819Sralph 
118056819Sralph 	if (boff & 0x1) {
118156819Sralph 		/* handle unaligned first byte */
118256819Sralph 		bptr = ((volatile u_short *)lebuf) + (boff - 1);
118356819Sralph 		*to++ = (*bptr >> 8) & 0xff;
118456819Sralph 		bptr += 2;
118556819Sralph 		len--;
118656819Sralph 	} else
118756819Sralph 		bptr = ((volatile u_short *)lebuf) + boff;
118856819Sralph 	if ((unsigned)to & 0x1) {
118956819Sralph 		while (len > 1) {
119056819Sralph 			tmp = *bptr;
119156819Sralph 			*to++ = tmp & 0xff;
119256819Sralph 			*to++ = (tmp >> 8) & 0xff;
119356819Sralph 			bptr += 2;
119456819Sralph 			len -= 2;
119556819Sralph 		}
119656819Sralph 	} else {
119756819Sralph 		/* optimize for aligned transfers */
119856819Sralph 		xfer = (int)((unsigned)len & ~0x1);
119956819Sralph 		CopyFromBuffer(bptr, to, xfer);
120056819Sralph 		bptr += xfer;
120156819Sralph 		to += xfer;
120256819Sralph 		len -= xfer;
120356819Sralph 	}
120456819Sralph 	if (len == 1)
120556819Sralph 		*to = *bptr & 0xff;
120656819Sralph }
120756819Sralph 
120856819Sralph void
120956819Sralph bzerobuf_gap2(lebuf, boff, len)
121056819Sralph 	volatile void *lebuf;
121156819Sralph 	int boff;
121256819Sralph 	int len;
121356819Sralph {
121456819Sralph 	register volatile u_short *bptr;
121556819Sralph 
121656819Sralph 	if ((unsigned)boff & 0x1) {
121756819Sralph 		bptr = ((volatile u_short *)lebuf) + (boff - 1);
121856819Sralph 		*bptr &= 0xff;
121956819Sralph 		bptr += 2;
122056819Sralph 		len--;
122156819Sralph 	} else
122256819Sralph 		bptr = ((volatile u_short *)lebuf) + boff;
122356819Sralph 	while (len > 0) {
122456819Sralph 		*bptr = 0;
122556819Sralph 		bptr += 2;
122656819Sralph 		len -= 2;
122756819Sralph 	}
122856819Sralph }
122956819Sralph 
123056819Sralph /*
123156819Sralph  * For the 3min and maxine, the buffers are in main memory filled in with
123256819Sralph  * 16byte blocks interspersed with 16byte spaces.
123356819Sralph  */
123456819Sralph void
123556819Sralph copytobuf_gap16(from, lebuf, boff, len)
123656819Sralph 	register char *from;
123756819Sralph 	volatile void *lebuf;
123856819Sralph 	int boff;
123956819Sralph 	register int len;
124056819Sralph {
124156819Sralph 	register char *bptr;
124256819Sralph 	register int xfer;
124356819Sralph 
124456819Sralph 	bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f);
124556819Sralph 	boff &= 0xf;
124656819Sralph 	xfer = min(len, 16 - boff);
124756819Sralph 	while (len > 0) {
124856819Sralph 		bcopy(from, ((char *)bptr) + boff, xfer);
124956819Sralph 		from += xfer;
125056819Sralph 		bptr += 32;
125156819Sralph 		boff = 0;
125256819Sralph 		len -= xfer;
125356819Sralph 		xfer = min(len, 16);
125456819Sralph 	}
125556819Sralph }
125656819Sralph 
125756819Sralph void
125856819Sralph copyfrombuf_gap16(lebuf, boff, to, len)
125956819Sralph 	volatile void *lebuf;
126056819Sralph 	int boff;
126156819Sralph 	register char *to;
126256819Sralph 	register int len;
126356819Sralph {
126456819Sralph 	register char *bptr;
126556819Sralph 	register int xfer;
126656819Sralph 
126756819Sralph 	bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f);
126856819Sralph 	boff &= 0xf;
126956819Sralph 	xfer = min(len, 16 - boff);
127056819Sralph 	while (len > 0) {
127156819Sralph 		bcopy(((char *)bptr) + boff, to, xfer);
127256819Sralph 		to += xfer;
127356819Sralph 		bptr += 32;
127456819Sralph 		boff = 0;
127556819Sralph 		len -= xfer;
127656819Sralph 		xfer = min(len, 16);
127756819Sralph 	}
127856819Sralph }
127956819Sralph 
128056819Sralph void
128156819Sralph bzerobuf_gap16(lebuf, boff, len)
128256819Sralph 	volatile void *lebuf;
128356819Sralph 	int boff;
128456819Sralph 	register int len;
128556819Sralph {
128656819Sralph 	register char *bptr;
128756819Sralph 	register int xfer;
128856819Sralph 
128956819Sralph 	bptr = ((char *)lebuf) + ((boff << 1) & ~0x1f);
129056819Sralph 	boff &= 0xf;
129156819Sralph 	xfer = min(len, 16 - boff);
129256819Sralph 	while (len > 0) {
129356819Sralph 		bzero(((char *)bptr) + boff, xfer);
129456819Sralph 		bptr += 32;
129556819Sralph 		boff = 0;
129656819Sralph 		len -= xfer;
129756819Sralph 		xfer = min(len, 16);
129856819Sralph 	}
129956819Sralph }
130056819Sralph #endif /* NLE */
1301