xref: /csrg-svn/sys/news3400/if/if_en.c (revision 57180)
153897Smckusick /*
253897Smckusick  * Copyright (c) 1992 The Regents of the University of California.
353897Smckusick  * All rights reserved.
453897Smckusick  *
553897Smckusick  * This code is derived from software contributed to Berkeley by
653897Smckusick  * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
753897Smckusick  *
853897Smckusick  * %sccs.include.redist.c%
953897Smckusick  *
1053897Smckusick  * from: $Hdr: if_en.c,v 4.300 91/06/09 06:25:54 root Rel41 $ SONY
1153897Smckusick  *
12*57180Sutashiro  *	@(#)if_en.c	7.6 (Berkeley) 12/17/92
1353897Smckusick  */
1453897Smckusick 
1553897Smckusick #include "en.h"
1653897Smckusick #include "rawether.h"
1753897Smckusick #include "bpfilter.h"
1853897Smckusick 
1953897Smckusick #if NEN > 0
2053897Smckusick 
2153897Smckusick /*
2253897Smckusick  * Interlan Ethernet Communications Controller interface
2353897Smckusick  */
24*57180Sutashiro #include <sys/types.h>
25*57180Sutashiro #include <machine/fix_machine_type.h>
26*57180Sutashiro #include <machine/pte.h>
2753897Smckusick 
28*57180Sutashiro #include <sys/param.h>
29*57180Sutashiro #include <sys/systm.h>
30*57180Sutashiro #include <sys/mbuf.h>
31*57180Sutashiro #include <sys/buf.h>
32*57180Sutashiro #include <sys/protosw.h>
33*57180Sutashiro #include <sys/socket.h>
34*57180Sutashiro #include <sys/ioctl.h>
35*57180Sutashiro #include <sys/errno.h>
36*57180Sutashiro #include <sys/time.h>
37*57180Sutashiro #include <sys/cdefs.h>
3853897Smckusick 
39*57180Sutashiro #include <net/if.h>
40*57180Sutashiro #include <net/netisr.h>
41*57180Sutashiro #include <net/route.h>
4253897Smckusick 
4353897Smckusick #ifdef INET
44*57180Sutashiro #include <netinet/in.h>
45*57180Sutashiro #include <netinet/in_systm.h>
46*57180Sutashiro #include <netinet/in_var.h>
47*57180Sutashiro #include <netinet/ip.h>
48*57180Sutashiro #include <netinet/if_ether.h>
4953897Smckusick #endif
5053897Smckusick 
51*57180Sutashiro #include <news3400/if/if_news.h>
52*57180Sutashiro #include <news3400/if/if_en.h>
5353897Smckusick 
5453897Smckusick #ifdef CPU_SINGLE
55*57180Sutashiro #include <news3400/hbdev/hbvar.h>
5653897Smckusick #define	iop_device	hb_device
5753897Smckusick #define	iop_driver	hb_driver
5853897Smckusick #define	ii_unit		hi_unit
5953897Smckusick #define	ii_intr		hi_intr
6053897Smckusick #define	ii_alive	hi_alive
6153897Smckusick #else
62*57180Sutashiro #include <news3400/iop/iopvar.h>
6353897Smckusick #endif
6453897Smckusick 
6553897Smckusick int	enprobe(), enattach(), enrint(), enxint();
6653897Smckusick struct	mbuf *m_devget();
6753897Smckusick 
6853897Smckusick #ifdef CPU_SINGLE
6953897Smckusick struct	hb_device *eninfo[NEN];
7053897Smckusick struct	hb_driver endriver = { enprobe, 0, enattach, 0, 0, "en", eninfo };
7153897Smckusick #else
7253897Smckusick struct	iop_device *eninfo[NEN];
7353897Smckusick struct	iop_driver endriver = { enprobe, 0, enattach, 0, "en", eninfo };
7453897Smckusick #endif
7553897Smckusick 
7653897Smckusick #define	ENUNIT(x)	minor(x)
7753897Smckusick 
7854473Sutashiro int	eninit(),enioctl(),enreset(),enwatch(),enstart();
7953897Smckusick int	endebug = 0;
8053897Smckusick 
8153897Smckusick struct ether_addr {
8253897Smckusick 	u_char	addr[6];
8353897Smckusick };
8453897Smckusick 
8553897Smckusick extern struct ifnet loif;
8653897Smckusick 
8753897Smckusick struct en_softc en_softc[NEN];
8853897Smckusick 
8953897Smckusick #if NBPFILTER > 0
90*57180Sutashiro #include <net/bpf.h>
9153897Smckusick #endif
9253897Smckusick 
9353897Smckusick enprobe(ii)
9453897Smckusick 	struct iop_device *ii;
9553897Smckusick {
9653897Smckusick 
9753897Smckusick 	return (en_probe(ii));
9853897Smckusick }
9953897Smckusick 
10053897Smckusick /*
10153897Smckusick  * Interface exists: make available by filling in network interface
10253897Smckusick  * record.  System will initialize the interface when it is ready
10353897Smckusick  * to accept packets.  A STATUS command is done to get the ethernet
10453897Smckusick  * address and other interesting data.
10553897Smckusick  */
10653897Smckusick enattach(ii)
10753897Smckusick 	register struct iop_device *ii;
10853897Smckusick {
10953897Smckusick 	register struct en_softc *es = &en_softc[ii->ii_unit];
11053897Smckusick 	register struct ifnet *ifp = &es->es_if;
11153897Smckusick 	extern char *ether_sprintf();
11253897Smckusick 
11353897Smckusick 	en_attach(ii->ii_unit);
11453897Smckusick 	printf("en%d: hardware address %s\n",
11553897Smckusick 		ii->ii_unit, ether_sprintf((u_char *)es->es_addr));
11653897Smckusick 	ifp->if_unit = ii->ii_unit;
11753897Smckusick 	ifp->if_name = "en";
11853897Smckusick 	ifp->if_mtu = ETHERMTU;
11953897Smckusick 	ifp->if_init = eninit;
12053897Smckusick 	ifp->if_ioctl = enioctl;
12153897Smckusick 	ifp->if_output = ether_output;
12253897Smckusick #ifdef NOTDEF /* KU:XXX if_reset is obsolete */
12353897Smckusick 	ifp->if_reset = enreset;
12453897Smckusick #endif
12553897Smckusick 	ifp->if_start = enstart;
12654517Sutashiro 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
12753897Smckusick #if NBPFILTER > 0
12854517Sutashiro 	bpfattach(&es->es_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
12953897Smckusick #endif
13053897Smckusick 	if_attach(ifp);
13153897Smckusick }
13253897Smckusick 
13353897Smckusick /*
13453897Smckusick  * Reset of interface after IOP reset.
13553897Smckusick  */
13653897Smckusick enreset(unit)
13753897Smckusick 	int unit;
13853897Smckusick {
13953897Smckusick 	register struct iop_device *ii;
14053897Smckusick 
14153897Smckusick 	if (unit >= NEN || (ii = eninfo[unit]) == 0 || ii->ii_alive == 0)
14253897Smckusick 		return;
14353897Smckusick 	printf(" en%d", unit);
14453897Smckusick 	en_softc[unit].es_if.if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
14553897Smckusick 	en_softc[unit].es_flags &= ~ENF_RUNNING;
14653897Smckusick 	eninit(unit);
14753897Smckusick }
14853897Smckusick 
14953897Smckusick /*
15053897Smckusick  * Initialization of interface; clear recorded pending
15153897Smckusick  * operations, and reinitialize IOP usage.
15253897Smckusick  */
15353897Smckusick eninit(unit)
15453897Smckusick 	int unit;
15553897Smckusick {
15653897Smckusick 	register struct en_softc *es = &en_softc[unit];
15753897Smckusick 	register struct ifnet *ifp = &es->es_if;
15853897Smckusick 	int s;
15953897Smckusick 
16053897Smckusick 	/* not yet, if address still unknown */
16153897Smckusick 	if (ifp->if_addrlist == (struct ifaddr *)0)
16253897Smckusick 		return;
16353897Smckusick 	if (es->es_flags & ENF_RUNNING)
16453897Smckusick 		return;
16553897Smckusick 	if ((ifp->if_flags & IFF_RUNNING) == 0) {
16653897Smckusick 		if (if_newsinit(&es->es_ifnews,
16753897Smckusick 		    sizeof (struct en_rheader), (int)btoc(ETHERMTU)) == 0) {
16853897Smckusick 			printf("en%d: can't initialize\n", unit);
16953897Smckusick 			es->es_if.if_flags &= ~IFF_UP;
17053897Smckusick 			return;
17153897Smckusick 		}
17253897Smckusick 		ifp->if_watchdog = enwatch;
17353897Smckusick 		es->es_interval = ENWATCHINTERVAL;
17453897Smckusick 		ifp->if_timer = es->es_interval;
17553897Smckusick 		s = splimp();
17653897Smckusick 		en_init(unit);
17753897Smckusick 		splx(s);
17853897Smckusick 	}
17953897Smckusick 	es->es_if.if_flags |= IFF_RUNNING|IFF_NOTRAILERS;
18053897Smckusick 	es->es_flags |= ENF_RUNNING;
18153897Smckusick }
18253897Smckusick 
18353897Smckusick /*
18453897Smckusick  * Start output on interface.
18553897Smckusick  * Get another datagram to send off of the interface queue,
18653897Smckusick  * and map it to the interface before starting the output.
18753897Smckusick  */
18853897Smckusick enstart(ifp)
18953897Smckusick 	register struct ifnet *ifp;
19053897Smckusick {
19153897Smckusick         int unit = ifp->if_unit, len;
19253897Smckusick 	register struct en_softc *es = &en_softc[unit];
19353897Smckusick 	register struct mbuf *m;
19454584Sutashiro 	int s;
19553897Smckusick 
19653897Smckusick 	IF_DEQUEUE(&es->es_if.if_snd, m);
19753897Smckusick 	if (m == 0)
19853897Smckusick 		return(0);
19953897Smckusick #ifdef CPU_SINGLE
20053897Smckusick 	es->es_ifnews.ifn_waddr = (caddr_t)get_xmit_buffer(unit);
20153897Smckusick #endif
20253897Smckusick 	len = if_wnewsput(&es->es_ifnews, m);
20353897Smckusick 	/*
20453897Smckusick 	 * Ensure minimum packet length.
20553897Smckusick 	 * This makes the safe assumtion that there are no virtual holes
20653897Smckusick 	 * after the data.
20753897Smckusick 	 * For security, it might be wise to zero out the added bytes,
20853897Smckusick 	 * but we're mainly interested in speed at the moment.
20953897Smckusick 	 */
21053897Smckusick 	if (len - sizeof(struct ether_header) < ETHERMIN)
21153897Smckusick 		len = ETHERMIN + sizeof(struct ether_header);
21254584Sutashiro 	s = splclock();			/* KU:XXX should be gone */
21353897Smckusick 	en_start(unit, len);
21454584Sutashiro 	es->es_if.if_flags |= IFF_OACTIVE;
21554584Sutashiro 	(void) splx(s);			/* KU:XXX */
21653897Smckusick #if NBPFILTER > 0
21753897Smckusick 	/*
21853897Smckusick 	 * If bpf is listening on this interface, let it
21953897Smckusick 	 * see the packet before we commit it to the wire.
22053897Smckusick 	 */
22154517Sutashiro 	if (es->es_bpf) {
22253897Smckusick #ifdef CPU_SINGLE
22354517Sutashiro 		bpf_tap(es->es_bpf, es->es_ifnews.ifn_waddr, len);
22453897Smckusick #else
22554517Sutashiro 		bpf_mtap(es->es_bpf, m);
22653897Smckusick #endif
22753897Smckusick 	}
22853897Smckusick #endif /* NBPFILTER > 0 */
22953897Smckusick 	return(0);
23053897Smckusick }
23153897Smckusick 
23253897Smckusick /*
23353897Smckusick  * Transmit done interrupt.
23453897Smckusick  */
23553897Smckusick _enxint(unit, error, collision)
23653897Smckusick 	int unit;
23753897Smckusick 	int error, collision;
23853897Smckusick {
23953897Smckusick 	register struct en_softc *es = &en_softc[unit];
24053897Smckusick 
24153897Smckusick #ifdef notyet /* KU:XXX */
24253897Smckusick 	intrcnt[INTR_ETHER0 + unit]++;
24353897Smckusick #endif
24453897Smckusick 	if ((es->es_if.if_flags & IFF_OACTIVE) == 0) {
24553897Smckusick 		printf("en%d: stray xmit interrupt\n", unit);
24653897Smckusick 		return;
24753897Smckusick 	} else {
24853897Smckusick 		es->es_if.if_flags &= ~IFF_OACTIVE;
24953897Smckusick 		es->es_if.if_opackets++;
25053897Smckusick 	}
25154517Sutashiro 	if (error) {
25254517Sutashiro #ifdef DEBUG
25354517Sutashiro 		printf("_enxint: error (unit=%d)\n", unit);
25454517Sutashiro #endif
25553897Smckusick 		es->es_if.if_oerrors++;
25654517Sutashiro 	}
25754517Sutashiro 	if (collision) {
25854517Sutashiro #ifdef DEBUG
25954517Sutashiro 		printf("_enxint: collision (unit=%d)\n", unit);
26054517Sutashiro #endif
26153897Smckusick 		es->es_if.if_collisions++;
26254517Sutashiro 	}
26353897Smckusick 	enstart(&es->es_if);
26453897Smckusick }
26553897Smckusick 
26653897Smckusick /*
26753897Smckusick  * Ethernet interface receiver interrupt.
26853897Smckusick  * If input error just drop packet.
26953897Smckusick  * Otherwise purge input buffered data path and examine
27053897Smckusick  * packet to determine type.  If can't determine length
27153897Smckusick  * from type, then have to drop packet.  Othewise decapsulate
27253897Smckusick  * packet based on type and pass to type specific higher-level
27353897Smckusick  * input routine.
27453897Smckusick  */
27553897Smckusick _enrint(unit, len)
27653897Smckusick 	int unit;
27753897Smckusick 	register int len;
27853897Smckusick {
27953897Smckusick 	register struct en_softc *es = &en_softc[unit];
28053897Smckusick 	register struct en_rheader *en;
28153897Smckusick     	struct mbuf *m;
28253897Smckusick 	int off, resid, s;
28354522Sutashiro 	int type;
28453897Smckusick 	register struct ensw *esp;
28553897Smckusick 	extern struct mbuf *if_rnewsget();
28654522Sutashiro #if defined(mips) && defined(CPU_SINGLE)
28754522Sutashiro 	int bxcopy();
28854522Sutashiro #endif
28953897Smckusick 
29053897Smckusick #ifdef notyet /* KU:XXX */
29153897Smckusick 	intrcnt[INTR_ETHER0 + unit]++;
29253897Smckusick #endif
29353897Smckusick 	es->es_if.if_ipackets++;
29453897Smckusick 	if ((es->es_flags & ENF_RUNNING) == 0)
29553897Smckusick 		return;
29653897Smckusick 	en = (struct en_rheader *)(es->es_ifnews.ifn_raddr);
29753897Smckusick 	if (len < ETHERMIN || len > ETHERMTU) {
29853897Smckusick 		es->es_if.if_ierrors++;
29953897Smckusick 		return;
30053897Smckusick 	}
30153897Smckusick #if NBPFILTER > 0
30253897Smckusick 	/*
30353897Smckusick 	 * Check if there's a bpf filter listening on this interface.
30453897Smckusick 	 * If so, hand off the raw packet to enet.
30553897Smckusick 	 */
30654517Sutashiro 	if (es->es_bpf) {
30754517Sutashiro 		bpf_tap(es->es_bpf, es->es_ifnews.ifn_raddr,
30853897Smckusick 			len + sizeof(struct en_rheader));
30953897Smckusick 		/*
31053897Smckusick 		 * Note that the interface cannot be in promiscuous mode if
31153897Smckusick 		 * there are no bpf listeners.	And if we are in promiscuous
31253897Smckusick 		 * mode, we have to check if this packet is really ours.
31353897Smckusick 		 *
31453897Smckusick 		 * XXX This test does not support multicasts.
31553897Smckusick 		 */
31653897Smckusick 		 if ((es->es_if.if_flags & IFF_PROMISC)
31753897Smckusick 		     && bcmp(en->enr_dhost, es->es_addr,
31853897Smckusick 				sizeof(en->enr_dhost)) != 0
31953897Smckusick 		     && bcmp(en->enr_dhost, etherbroadcastaddr,
32053897Smckusick 				sizeof(en->enr_dhost)) != 0)
32153897Smckusick 			return;
32253897Smckusick 	}
32353897Smckusick #endif /* NBPFILTER > 0 */
32453897Smckusick 	/*
32553897Smckusick 	 * Deal with trailer protocol: if type is trailer type
32653897Smckusick 	 * get true type from first 16-bit word past data.
32753897Smckusick 	 * Remember that type was trailer by setting off.
32853897Smckusick 	 */
32953897Smckusick 	en->enr_type = ntohs((u_short)en->enr_type);
33053897Smckusick #define	endataaddr(en, off, type)	((type)(((caddr_t)((en)+1)+(off))))
33153897Smckusick 	if (en->enr_type >= ETHERTYPE_TRAIL &&
33253897Smckusick 	    en->enr_type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) {
33353897Smckusick 		off = (en->enr_type - ETHERTYPE_TRAIL) * 512;
33453897Smckusick 		if (off >= ETHERMTU)
33553897Smckusick 			return;
33653897Smckusick 		en->enr_type = ntohs(*endataaddr(en, off, u_short *));
33753897Smckusick 		resid = ntohs(*(endataaddr(en, off+2, u_short *)));
33853897Smckusick 		if (off + resid > len)
33953897Smckusick 			return;
34053897Smckusick 		len = off + resid;
34153897Smckusick 	} else
34253897Smckusick 		off = 0;
34353897Smckusick 	/*
34453897Smckusick 	 * Pull packet off interface.  Off is nonzero if packet
34553897Smckusick 	 * has trailing header; m_devget will then force this header
34653897Smckusick 	 * information to be at the front, but we still have to drop
34753897Smckusick 	 * the type and length which are at the front of any trailer data.
34853897Smckusick 	 * KU:XXX really?
34953897Smckusick 	 */
35053897Smckusick 	type = en->enr_type;
35154522Sutashiro #if defined(mips) && defined(CPU_SINGLE)
35254522Sutashiro 	m = m_devget((char *)(en + 1), len, off, &es->es_if, bxcopy);
35354522Sutashiro #else
35453897Smckusick 	m = m_devget((char *)(en + 1), len, off, &es->es_if, 0);
35554522Sutashiro #endif
35653897Smckusick 	if (m == 0)
35753897Smckusick 		return;
35853897Smckusick 	ether_input(&es->es_if, (struct ether_header *) en->enr_dhost, m);
35953897Smckusick }
36053897Smckusick 
36153897Smckusick /*
36253897Smckusick  * Watchdog routine, request statistics from board.
36353897Smckusick  */
36453897Smckusick enwatch(unit)
36553897Smckusick 	int unit;
36653897Smckusick {
36753897Smckusick 	register struct en_softc *es = &en_softc[unit];
36853897Smckusick 	register struct ifnet *ifp = &es->es_if;
36953897Smckusick 
37053897Smckusick 	ifp->if_timer = es->es_interval;
37153897Smckusick }
37253897Smckusick 
37353897Smckusick /*
37453897Smckusick  * Process an ioctl request.
37553897Smckusick  */
37653897Smckusick enioctl(ifp, cmd, data)
37753897Smckusick 	register struct ifnet *ifp;
37853897Smckusick 	int cmd;
37953897Smckusick 	caddr_t data;
38053897Smckusick {
38153897Smckusick 	register struct ifaddr *ifa = (struct ifaddr *)data;
38253897Smckusick 	register struct en_softc *es = &en_softc[ifp->if_unit];
38353897Smckusick 	register struct ensw *esp;
38453897Smckusick 	register int family;
38553897Smckusick 	int s = splimp(), error = 0;
38653897Smckusick 
38753897Smckusick 	switch (cmd) {
38853897Smckusick 
38953897Smckusick 	case SIOCSIFADDR:
39053897Smckusick 		ifp->if_flags |= IFF_UP;
39153897Smckusick 		eninit(ifp->if_unit);
39253897Smckusick 		switch (ifa->ifa_addr->sa_family) {
39353897Smckusick #ifdef INET
39453897Smckusick 		case AF_INET:
39553897Smckusick 			((struct arpcom *)ifp)->ac_ipaddr =
39653897Smckusick 				IA_SIN(ifa)->sin_addr;
39753897Smckusick 			arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
39853897Smckusick 			break;
39953897Smckusick #endif
40053897Smckusick 		}
40153897Smckusick 		break;
40253897Smckusick 
40353897Smckusick 	case SIOCSIFFLAGS:
40453897Smckusick 		if ((ifp->if_flags & IFF_UP) == 0 &&
40553897Smckusick 		    es->es_flags & ENF_RUNNING) {
40653897Smckusick 			es->es_flags &= ~ENF_RUNNING;
40753897Smckusick 		} else if (ifp->if_flags & IFF_UP &&
40853897Smckusick 		    (es->es_flags & ENF_RUNNING) == 0)
40953897Smckusick 			eninit(ifp->if_unit);
41053897Smckusick #if NBPFILTER > 0
41153897Smckusick 		else if (ifp->if_flags & IFF_UP &&
41253897Smckusick 		    (ifp->if_flags & IFF_RUNNING) == 0) {
41353897Smckusick 			en_prom_mode(ifp->if_unit,
41453897Smckusick 				ifp->if_flags & IFF_PROMISC);
41553897Smckusick 			ifp->if_flags |= IFF_RUNNING;
41653897Smckusick 		}
41753897Smckusick #endif
41853897Smckusick 		break;
41953897Smckusick 
42053897Smckusick 	default:
42153897Smckusick 		error = EINVAL;
42253897Smckusick 	}
42353897Smckusick 	splx(s);
42453897Smckusick 	return (error);
42553897Smckusick }
42653897Smckusick 
42753897Smckusick /*
42853897Smckusick  * set ethernet address for unit
42953897Smckusick  */
43053897Smckusick ensetaddr(physaddr, unit)
43153897Smckusick 	u_char *physaddr;
43253897Smckusick 	int unit;
43353897Smckusick {
43453897Smckusick 	register struct en_softc *es = &en_softc[unit];
43553897Smckusick 
43653897Smckusick 	if (!(es->es_flags & ENF_RUNNING))
43753897Smckusick 		return;
43853897Smckusick 
43953897Smckusick 	bcopy((caddr_t)physaddr, (caddr_t)es->es_addr, sizeof es->es_addr);
44053897Smckusick 	es->es_flags &= ~ENF_RUNNING;
44153897Smckusick 	es->es_flags |= ENF_SETADDR;
44253897Smckusick 	eninit(unit);
44353897Smckusick }
44453897Smckusick 
44553897Smckusick /*
44653897Smckusick  * Machine dependent functions
44753897Smckusick  *
44853897Smckusick  *	en_probe();
44953897Smckusick  *	en_attach();
45053897Smckusick  *	en_init();
45153897Smckusick  *	enxint();
45253897Smckusick  *	enrint();
45353897Smckusick  *	en_prom_mode()
45453897Smckusick  */
45553897Smckusick #ifdef CPU_SINGLE
456*57180Sutashiro #include <machine/cpu.h>
45753897Smckusick 
45853897Smckusick en_probe(hi)
45953897Smckusick 	struct hb_device *hi;
46053897Smckusick {
46153897Smckusick 
46253897Smckusick 	return (lance_probe(hi->hi_unit));
46353897Smckusick }
46453897Smckusick 
46553897Smckusick en_attach(unit)
46653897Smckusick 	int unit;
46753897Smckusick {
46853897Smckusick 	register struct en_softc *es = &en_softc[unit];
46953897Smckusick 	register u_char *p;
47053897Smckusick 	register int i;
47153897Smckusick 	extern lance_intr();
47253897Smckusick 
47353897Smckusick #if !defined(news700) && !defined(mips)
47453897Smckusick 	register_hb_intr4(lance_intr, unit, eninfo[unit]->ii_intr);
47553897Smckusick #endif
47653897Smckusick 	if (lance_open(unit) < 0)
47753897Smckusick 		printf("lance initialize error\n");
47853897Smckusick 	lance_get_addr(unit, (caddr_t)es->es_addr);
47953897Smckusick }
48053897Smckusick 
48153897Smckusick en_init(unit)
48253897Smckusick 	int unit;
48353897Smckusick {
48453897Smckusick 
48553897Smckusick }
48653897Smckusick 
48753897Smckusick en_start(unit, len)
48853897Smckusick 	int unit;
48953897Smckusick 	int len;
49053897Smckusick {
49153897Smckusick 
49253897Smckusick 	lance_transmit(unit, len);
49353897Smckusick }
49453897Smckusick 
49553897Smckusick enxint(unit)
49653897Smckusick 	register int unit;
49753897Smckusick {
49853897Smckusick 
49953897Smckusick 	_enxint(unit, lance_xmit_error(unit), lance_collision(unit));
50053897Smckusick }
50153897Smckusick 
50253897Smckusick enrint(unit)
50353897Smckusick 	register int unit;
50453897Smckusick {
50553897Smckusick 	register struct en_softc *es = &en_softc[unit];
50653897Smckusick 	caddr_t get_recv_buffer();
50753897Smckusick 
50853897Smckusick 	while (es->es_ifnews.ifn_raddr = get_recv_buffer(unit)) {
50953897Smckusick 		_enrint(unit,
51053897Smckusick 		    get_recv_length(unit) - sizeof(struct en_rheader));
51153897Smckusick 		free_recv_buffer(unit);
51253897Smckusick 	}
51353897Smckusick }
51453897Smckusick 
51553897Smckusick en_prom_mode(unit, mode)
51653897Smckusick 	int unit, mode;
51753897Smckusick {
51853897Smckusick 
51953897Smckusick 	lance_prom_mode(unit, mode);
52053897Smckusick }
52153897Smckusick #endif /* CPU_SINGLE */
52253897Smckusick 
52353897Smckusick #ifdef IPC_MRX
52453897Smckusick #include "../ipc/newsipc.h"
52553897Smckusick #include "../mrx/h/lancereg.h"
52653897Smckusick #include "../mrx/h/lance.h"
52753897Smckusick 
52853897Smckusick int	port_enxmit[NEN];
52953897Smckusick int	port_enrecv[NEN];
53053897Smckusick int	port_enctrl[NEN];
53153897Smckusick int	port_enxmit_iop[NEN];
53253897Smckusick int	port_enrecv_iop[NEN];
53353897Smckusick int	port_enctrl_iop[NEN];
53453897Smckusick 
53553897Smckusick en_probe(ii)
53653897Smckusick 	register struct iop_device *ii;
53753897Smckusick {
53853897Smckusick 	int unit = ii->ii_unit;
53953897Smckusick 	int lance_func, *reply;
54053897Smckusick 	char name[32];
54153897Smckusick 	extern char *make_name();
54253897Smckusick 
54353897Smckusick 	if (port_enrecv[unit] == 0) {
54453897Smckusick 
54553897Smckusick #define	PT_CREATE(buf, name, unit, func)	\
54653897Smckusick 	port_create(make_name(buf, name, unit), func, unit)
54753897Smckusick #define	OB_QUERY(buf, name, unit) \
54853897Smckusick 	object_query(make_name(buf, name, unit))
54953897Smckusick 
55053897Smckusick 		make_name(name, "@enrecvX", unit);
55153897Smckusick 		port_enrecv[unit] = PT_CREATE(name, "@enrecvX", unit, enrint);
55253897Smckusick 		port_enxmit[unit] = PT_CREATE(name, "@enxmitX", unit, enxint);
55353897Smckusick 		port_enctrl[unit] = PT_CREATE(name, "@enctrlX", unit, NULL);
55453897Smckusick 		/* use NULL action port */
55553897Smckusick 		port_enrecv_iop[unit] = OB_QUERY(name, "lance_inputX", unit);
55653897Smckusick 		port_enxmit_iop[unit] = OB_QUERY(name, "lance_outputX", unit);
55753897Smckusick 		port_enctrl_iop[unit] = OB_QUERY(name, "lance_ctrlX", unit);
55853897Smckusick 	}
55953897Smckusick 	if (port_enctrl_iop[unit] < 0)
56053897Smckusick 		goto bad;
56153897Smckusick 	lance_func = EN_START;
56253897Smckusick 	msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
56353897Smckusick 	    sizeof(lance_func), 0);
56453897Smckusick 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
56553897Smckusick 	if (*reply < 0)
56653897Smckusick 		goto bad;
56753897Smckusick 	lance_func = EN_STOP;
56853897Smckusick 	msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
56953897Smckusick 	    sizeof(lance_func), 0);
57053897Smckusick 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
57153897Smckusick 	return (1);
57253897Smckusick bad:
57353897Smckusick 	return (0);
57453897Smckusick }
57553897Smckusick 
57653897Smckusick en_attach(unit)
57753897Smckusick 	int unit;
57853897Smckusick {
57953897Smckusick 	register struct en_softc *es = &en_softc[unit];
58053897Smckusick 	int lance_func;
58153897Smckusick 	struct ether_addr *ether_addr;
58253897Smckusick 
58353897Smckusick 	lance_func = EN_GETADDR;
58453897Smckusick 	msg_send(port_enctrl_iop[unit], port_enctrl[unit], &lance_func,
58553897Smckusick 	    sizeof(lance_func), 0);
58653897Smckusick 	msg_recv(port_enctrl[unit], NULL, &ether_addr, NULL, 0);
58753897Smckusick 	bcopy(ether_addr, es->es_addr, sizeof(struct ether_addr));
58853897Smckusick 	msg_free(port_enctrl[unit]);
58953897Smckusick }
59053897Smckusick 
59153897Smckusick en_init(unit)
59253897Smckusick 	int unit;
59353897Smckusick {
59453897Smckusick 	register struct en_softc *es = &en_softc[unit];
59553897Smckusick 	register int port;
59653897Smckusick 	struct lance_ctrl_req req;
59753897Smckusick 	int *reply;
59853897Smckusick 
59953897Smckusick 	req.lance_func = EN_SETXMITBUF;
60053897Smckusick 	mapsetup(&req.lance_map, es->es_ifnews.ifn_waddr,
60153897Smckusick 		ETHERMTU + sizeof(struct en_rheader));
60253897Smckusick 	msg_send(port_enctrl_iop[unit], port_enctrl[unit],
60353897Smckusick 	    &req, sizeof(req), 0);
60453897Smckusick 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
60553897Smckusick 
60653897Smckusick 	req.lance_func = EN_START;
60753897Smckusick 	msg_send(port_enctrl_iop[unit], port_enctrl[unit],
60853897Smckusick 	    &req, sizeof(req), 0);
60953897Smckusick 	msg_recv(port_enctrl[unit], NULL, &reply, NULL, 0);
61053897Smckusick 	msg_free(port_enctrl[unit]);
61153897Smckusick 
61253897Smckusick 	msg_send(port_enrecv_iop[unit], port_enrecv[unit],
61353897Smckusick 	    es->es_ifnews.ifn_raddr,
61453897Smckusick 	    ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT);
61553897Smckusick }
61653897Smckusick 
61753897Smckusick en_start(unit, len)
61853897Smckusick 	int unit;
61953897Smckusick 	int len;
62053897Smckusick {
62153897Smckusick 
62253897Smckusick 	msg_send(port_enxmit_iop[unit], port_enxmit[unit], &len, sizeof(len), 0);
62353897Smckusick }
62453897Smckusick 
62553897Smckusick enxint(unit)
62653897Smckusick 	register int unit;
62753897Smckusick {
62853897Smckusick 	int *len;
62953897Smckusick 	struct en_softc *es = &en_softc[unit];
63053897Smckusick 
63153897Smckusick 	if (msg_recv(port_enxmit[unit], NULL, &len, NULL, 0) < 0) {
63253897Smckusick 		printf("stray enxint\n");
63353897Smckusick 		return;
63453897Smckusick 	}
63553897Smckusick 	if (es->es_ifnews.ifn_mbuf)
63653897Smckusick 		m_freem(es->es_ifnews.ifn_mbuf);
63753897Smckusick 	_enxint(unit, *len < 0, *len & 0x10000);
63853897Smckusick }
63953897Smckusick 
64053897Smckusick enrint(unit)
64153897Smckusick 	int unit;
64253897Smckusick {
64353897Smckusick 	int len;
64453897Smckusick 	int *reply;
64553897Smckusick 
64653897Smckusick 	if (msg_recv(port_enrecv[unit], NULL, &reply, NULL, 0) < 0) {
64753897Smckusick 		printf("stray enrint\n");
64853897Smckusick 		return;
64953897Smckusick 	}
65053897Smckusick 	len = *reply - sizeof(struct en_rheader);
65153897Smckusick 	msg_free(port_enrecv[unit]);
65253897Smckusick #ifdef mips
65353897Smckusick 	/*
65453897Smckusick 	 * cache flush address must aligned long word boundary.
65553897Smckusick 	 * so, add 3 for sanity.
65653897Smckusick 	 */
65753897Smckusick 	clean_k2dcache((int)en_softc[unit].es_ifnews.ifn_raddr & ~03,
65853897Smckusick 	    len + sizeof (struct en_rheader) + 3);
65953897Smckusick #endif
66053897Smckusick 	_enrint(unit, len);
66153897Smckusick 	msg_send(port_enrecv_iop[unit], port_enrecv[unit],
66253897Smckusick 	    en_softc[unit].es_ifnews.ifn_raddr,
66353897Smckusick 	    ETHERMTU + sizeof(struct en_rheader), MSG_INDIRECT);
66453897Smckusick }
66553897Smckusick 
66653897Smckusick en_prom_mode(unit, mode)
66753897Smckusick 	int unit, mode;
66853897Smckusick {
66953897Smckusick 	static int port;
67053897Smckusick 	struct lance_ctrl_req req;
67153897Smckusick 	extern int port_enctrl_iop[];
67253897Smckusick 
67353897Smckusick 	req.lance_func = EN_PROMMODE;
67453897Smckusick 	req.lance_mode = mode;
67553897Smckusick 	msg_send(port_enctrl_iop[unit], 0, &req, sizeof(req), 0);
67653897Smckusick }
67753897Smckusick #endif /* IPC_MRX */
67853897Smckusick #endif /* NEN > 0 */
679