xref: /netbsd-src/sys/arch/sun3/dev/if_ie.c (revision f3cfa6f6ce31685c6c4a758bc430e69eb99f50a4)
1 /*	$NetBSD: if_ie.c,v 1.70 2019/05/28 07:41:48 msaitoh Exp $ */
2 
3 /*-
4  * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.
5  * Copyright (c) 1992, 1993, University of Vermont and State
6  *  Agricultural College.
7  * Copyright (c) 1992, 1993, Garrett A. Wollman.
8  *
9  * Portions:
10  * Copyright (c) 1994, 1995, Rafal K. Boni
11  * Copyright (c) 1990, 1991, William F. Jolitz
12  * Copyright (c) 1990, The Regents of the University of California
13  *
14  * All rights reserved.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  * 3. All advertising materials mentioning features or use of this software
25  *    must display the following acknowledgement:
26  *	This product includes software developed by Charles M. Hannum, by the
27  *	University of Vermont and State Agricultural College and Garrett A.
28  *	Wollman, by William F. Jolitz, and by the University of California,
29  *	Berkeley, Lawrence Berkeley Laboratory, and its contributors.
30  * 4. Neither the names of the Universities nor the names of the authors
31  *    may be used to endorse or promote products derived from this software
32  *    without specific prior written permission.
33  *
34  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR AUTHORS BE LIABLE
38  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  */
46 
47 /*
48  * Intel 82586 Ethernet chip
49  * Register, bit, and structure definitions.
50  *
51  * Original StarLAN driver written by Garrett Wollman with reference to the
52  * Clarkson Packet Driver code for this chip written by Russ Nelson and others.
53  *
54  * BPF support code taken from hpdev/if_le.c, supplied with tcpdump.
55  *
56  * 3C507 support is loosely based on code donated to NetBSD by Rafal Boni.
57  *
58  * Majorly cleaned up and 3C507 code merged by Charles Hannum.
59  *
60  * Converted to SUN ie driver by Charles D. Cranor,
61  *		October 1994, January 1995.
62  * This sun version based on i386 version 1.30.
63  * [ see sys/dev/isa/if_ie.c ]
64  */
65 
66 /*
67  * The i82586 is a very painful chip, found in sun3's, sun-4/100's
68  * sun-4/200's, and VME based suns.  The byte order is all wrong for a
69  * SUN, making life difficult.  Programming this chip is mostly the same,
70  * but certain details differ from system to system.  This driver is
71  * written so that different "ie" interfaces can be controled by the same
72  * driver.
73  */
74 
75 /*
76    Mode of operation:
77 
78    We run the 82586 in a standard Ethernet mode.  We keep NFRAMES
79    received frame descriptors around for the receiver to use, and
80    NRXBUF associated receive buffer descriptors, both in a circular
81    list.  Whenever a frame is received, we rotate both lists as
82    necessary.  (The 586 treats both lists as a simple queue.)  We also
83    keep a transmit command around so that packets can be sent off
84    quickly.
85 
86    We configure the adapter in AL-LOC = 1 mode, which means that the
87    Ethernet/802.3 MAC header is placed at the beginning of the receive
88    buffer rather than being split off into various fields in the RFD.
89    This also means that we must include this header in the transmit
90    buffer as well.
91 
92    By convention, all transmit commands, and only transmit commands,
93    shall have the I (IE_CMD_INTR) bit set in the command.  This way,
94    when an interrupt arrives at ieintr(), it is immediately possible
95    to tell what precisely caused it.  ANY OTHER command-sending
96    routines should run at splnet(), and should post an acknowledgement
97    to every interrupt they generate.
98 */
99 
100 #include <sys/cdefs.h>
101 __KERNEL_RCSID(0, "$NetBSD: if_ie.c,v 1.70 2019/05/28 07:41:48 msaitoh Exp $");
102 
103 #include "opt_inet.h"
104 #include "opt_ns.h"
105 
106 #include <sys/param.h>
107 #include <sys/systm.h>
108 #include <sys/mbuf.h>
109 #include <sys/buf.h>
110 #include <sys/protosw.h>
111 #include <sys/socket.h>
112 #include <sys/ioctl.h>
113 #include <sys/errno.h>
114 #include <sys/syslog.h>
115 #include <sys/device.h>
116 
117 #include <net/if.h>
118 #include <net/if_types.h>
119 #include <net/if_dl.h>
120 #include <net/if_ether.h>
121 #include <net/bpf.h>
122 
123 #ifdef INET
124 #include <netinet/in.h>
125 #include <netinet/in_systm.h>
126 #include <netinet/in_var.h>
127 #include <netinet/ip.h>
128 #include <netinet/if_inarp.h>
129 #endif
130 
131 #include <uvm/uvm_extern.h>
132 
133 #include <machine/autoconf.h>
134 #include <machine/cpu.h>
135 #include <machine/pmap.h>
136 
137 /*
138  * ugly byte-order hack for SUNs
139  */
140 
141 #define XSWAP(y)	( (((y) & 0xff00) >> 8) | (((y) & 0xff) << 8) )
142 #define SWAP(x)		((u_short)(XSWAP((u_short)(x))))
143 
144 #include "i82586.h"
145 #include "if_iereg.h"
146 #include "if_ievar.h"
147 
148 /* #define	IEDEBUG	XXX */
149 
150 /*
151  * IED: ie debug flags
152  */
153 
154 #define	IED_RINT	0x01
155 #define	IED_TINT	0x02
156 #define	IED_RNR		0x04
157 #define	IED_CNA		0x08
158 #define	IED_READFRAME	0x10
159 #define	IED_ENQ		0x20
160 #define	IED_XMIT	0x40
161 #define	IED_ALL		0x7f
162 
163 #ifdef	IEDEBUG
164 #define	inline	/* not */
165 void print_rbd(volatile struct ie_recv_buf_desc *);
166 int	in_ierint = 0;
167 int	in_ietint = 0;
168 int	ie_debug_flags = 0;
169 #endif
170 
171 /* XXX - Skip TDR for now - it always complains... */
172 int	ie_run_tdr = 0;
173 
174 static void iewatchdog(struct ifnet *);
175 static int ieinit(struct ie_softc *);
176 static int ieioctl(struct ifnet *, u_long, void *);
177 static void iestart(struct ifnet *);
178 static void iereset(struct ie_softc *);
179 static int ie_setupram(struct ie_softc *);
180 
181 static int cmd_and_wait(struct ie_softc *, int, void *, int);
182 
183 static void ie_drop_packet_buffer(struct ie_softc *);
184 static void ie_readframe(struct ie_softc *, int);
185 static inline void ie_setup_config(struct ie_config_cmd *, int, int);
186 
187 static void ierint(struct ie_softc *);
188 static void iestop(struct ie_softc *);
189 static void ietint(struct ie_softc *);
190 static void iexmit(struct ie_softc *);
191 
192 static int mc_setup(struct ie_softc *, void *);
193 static void mc_reset(struct ie_softc *);
194 static void run_tdr(struct ie_softc *, struct ie_tdr_cmd *);
195 static void iememinit(struct ie_softc *);
196 
197 static inline uint8_t *Align(char *);
198 static inline u_int Swap32(u_int);
199 static inline u_int vtop24(struct ie_softc *, void *);
200 static inline uint16_t vtop16sw(struct ie_softc *, void *);
201 
202 static inline void ie_ack(struct ie_softc *, u_int);
203 static inline u_short ether_cmp(u_char *, uint8_t *);
204 static inline int ie_buflen(struct ie_softc *, int);
205 static inline int ie_packet_len(struct ie_softc *);
206 static inline struct mbuf * ieget(struct ie_softc *);
207 
208 
209 /*
210  * Here are a few useful functions.  We could have done these as macros,
211  * but since we have the inline facility, it makes sense to use that
212  * instead.
213  */
214 
215 /* KVA to 24 bit device address */
216 static inline u_int
217 vtop24(struct ie_softc *sc, void *ptr)
218 {
219 	u_int pa;
220 
221 	pa = (vaddr_t)ptr - (vaddr_t)sc->sc_iobase;
222 #ifdef	IEDEBUG
223 	if (pa & ~0xffFFff)
224 		panic("ie:vtop24");
225 #endif
226 	return pa;
227 }
228 
229 /* KVA to 16 bit offset, swapped */
230 static inline u_short
231 vtop16sw(struct ie_softc *sc, void *ptr)
232 {
233 	u_int pa;
234 
235 	pa = (vaddr_t)ptr - (vaddr_t)sc->sc_maddr;
236 #ifdef	IEDEBUG
237 	if (pa & ~0xFFff)
238 		panic("ie:vtop16");
239 #endif
240 
241 	return SWAP(pa);
242 }
243 
244 static inline u_int
245 Swap32(u_int x)
246 {
247 	u_int y;
248 
249 	y = x & 0xFF;
250 	y <<= 8; x >>= 8;
251 	y |= x & 0xFF;
252 	y <<= 8; x >>= 8;
253 	y |= x & 0xFF;
254 	y <<= 8; x >>= 8;
255 	y |= x & 0xFF;
256 
257 	return y;
258 }
259 
260 static inline uint8_t *
261 Align(char *ptr)
262 {
263 	u_long  l = (u_long)ptr;
264 
265 	l = (l + 3) & ~3L;
266 	return (uint8_t *)l;
267 }
268 
269 
270 static inline void
271 ie_ack(struct ie_softc *sc, u_int mask)
272 {
273 	volatile struct ie_sys_ctl_block *scb = sc->scb;
274 
275 	cmd_and_wait(sc, scb->ie_status & mask, 0, 0);
276 }
277 
278 
279 /*
280  * Taken almost exactly from Bill's if_is.c,
281  * then modified beyond recognition...
282  */
283 void
284 ie_attach(struct ie_softc *sc)
285 {
286 	struct ifnet *ifp = &sc->sc_if;
287 
288 	/* MD code has done its part before calling this. */
289 	printf(": macaddr %s\n", ether_sprintf(sc->sc_addr));
290 
291 	/*
292 	 * Compute number of transmit and receive buffers.
293 	 * Tx buffers take 1536 bytes, and fixed in number.
294 	 * Rx buffers are 512 bytes each, variable number.
295 	 * Need at least 1 frame for each 3 rx buffers.
296 	 * The ratio 3bufs:2frames is a compromise.
297 	 */
298 	sc->ntxbuf = NTXBUF;	/* XXX - Fix me... */
299 	switch (sc->sc_msize) {
300 	case 16384:
301 		sc->nframes = 8 * 4;
302 		sc->nrxbuf  = 8 * 6;
303 		break;
304 	case 32768:
305 		sc->nframes = 16 * 4;
306 		sc->nrxbuf  = 16 * 6;
307 		break;
308 	case 65536:
309 		sc->nframes = 32 * 4;
310 		sc->nrxbuf  = 32 * 6;
311 		break;
312 	default:
313 		sc->nframes = 0;
314 	}
315 	if (sc->nframes > MXFRAMES)
316 		sc->nframes = MXFRAMES;
317 	if (sc->nrxbuf > MXRXBUF)
318 		sc->nrxbuf = MXRXBUF;
319 
320 #ifdef	IEDEBUG
321 	aprint_debug_dev(sc->sc_dev,
322 	    "%dK memory, %d tx frames, %d rx frames, %d rx bufs\n",
323 	    (sc->sc_msize >> 10), sc->ntxbuf, sc->nframes, sc->nrxbuf);
324 #endif
325 
326 	if ((sc->nframes <= 0) || (sc->nrxbuf <= 0))
327 		panic("%s: weird memory size", __func__);
328 
329 	/*
330 	 * Setup RAM for transmit/receive
331 	 */
332 	if (ie_setupram(sc) == 0) {
333 		aprint_error(": RAM CONFIG FAILED!\n");
334 		/* XXX should reclaim resources? */
335 		return;
336 	}
337 
338 	/*
339 	 * Initialize and attach S/W interface
340 	 */
341 	strcpy(ifp->if_xname, device_xname(sc->sc_dev));
342 	ifp->if_softc = sc;
343 	ifp->if_start = iestart;
344 	ifp->if_ioctl = ieioctl;
345 	ifp->if_watchdog = iewatchdog;
346 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
347 
348 	/* Attach the interface. */
349 	if_attach(ifp);
350 	if_deferred_start_init(ifp, NULL);
351 	ether_ifattach(ifp, sc->sc_addr);
352 }
353 
354 /*
355  * Setup IE's ram space.
356  */
357 static int
358 ie_setupram(struct ie_softc *sc)
359 {
360 	volatile struct ie_sys_conf_ptr *scp;
361 	volatile struct ie_int_sys_conf_ptr *iscp;
362 	volatile struct ie_sys_ctl_block *scb;
363 	int off;
364 
365 	/*
366 	 * Allocate from end of buffer space for
367 	 * ISCP, SCB, and other small stuff.
368 	 */
369 	off = sc->buf_area_sz;
370 	off &= ~3;
371 
372 	/* SCP (address already chosen). */
373 	scp = sc->scp;
374 	(sc->sc_memset)(__UNVOLATILE(scp), 0, sizeof(*scp));
375 
376 	/* ISCP */
377 	off -= sizeof(*iscp);
378 	iscp = (volatile void *)(sc->buf_area + off);
379 	(sc->sc_memset)(__UNVOLATILE(iscp), 0, sizeof(*iscp));
380 	sc->iscp = iscp;
381 
382 	/* SCB */
383 	off -= sizeof(*scb);
384 	scb  = (volatile void *)(sc->buf_area + off);
385 	(sc->sc_memset)(__UNVOLATILE(scb), 0, sizeof(*scb));
386 	sc->scb = scb;
387 
388 	/* Remainder is for buffers, etc. */
389 	sc->buf_area_sz = off;
390 
391 	/*
392 	 * Now fill in the structures we just allocated.
393 	 */
394 
395 	/* SCP: main thing is 24-bit ptr to ISCP */
396 	scp->ie_bus_use = 0;	/* 16-bit */
397 	scp->ie_iscp_ptr = Swap32(vtop24(sc, __UNVOLATILE(iscp)));
398 
399 	/* ISCP */
400 	iscp->ie_busy = 1;	/* ie_busy == char */
401 	iscp->ie_scb_offset = vtop16sw(sc, __UNVOLATILE(scb));
402 	iscp->ie_base = Swap32(vtop24(sc, sc->sc_maddr));
403 
404 	/* SCB */
405 	scb->ie_command_list = SWAP(0xffff);
406 	scb->ie_recv_list    = SWAP(0xffff);
407 
408 	/* Other stuff is done in ieinit() */
409 	(sc->reset_586)(sc);
410 	(sc->chan_attn)(sc);
411 
412 	delay(100);		/* wait a while... */
413 
414 	if (iscp->ie_busy) {
415 		return 0;
416 	}
417 	/*
418 	 * Acknowledge any interrupts we may have caused...
419 	 */
420 	ie_ack(sc, IE_ST_WHENCE);
421 
422 	return 1;
423 }
424 
425 /*
426  * Device timeout/watchdog routine.  Entered if the device neglects to
427  * generate an interrupt after a transmit has been started on it.
428  */
429 static void
430 iewatchdog(struct ifnet *ifp)
431 {
432 	struct ie_softc *sc = ifp->if_softc;
433 
434 	log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev));
435 	++ifp->if_oerrors;
436 	iereset(sc);
437 }
438 
439 /*
440  * What to do upon receipt of an interrupt.
441  */
442 int
443 ie_intr(void *arg)
444 {
445 	struct ie_softc *sc = arg;
446 	uint16_t status;
447 	int loopcnt;
448 
449 	/*
450 	 * check for parity error
451 	 */
452 	if (sc->hard_type == IE_VME) {
453 		volatile struct ievme *iev =
454 		    (volatile struct ievme *)sc->sc_reg;
455 
456 		if (iev->status & IEVME_PERR) {
457 			printf("%s: parity error (ctrl 0x%x @ 0x%02x%04x)\n",
458 			    device_xname(sc->sc_dev), iev->pectrl,
459 			    iev->pectrl & IEVME_HADDR, iev->peaddr);
460 			iev->pectrl = iev->pectrl | IEVME_PARACK;
461 		}
462 	}
463 
464 	status = sc->scb->ie_status;
465 	if ((status & IE_ST_WHENCE) == 0)
466 		return 0;
467 
468 	loopcnt = sc->nframes;
469  loop:
470 	/* Ack interrupts FIRST in case we receive more during the ISR. */
471 	ie_ack(sc, IE_ST_WHENCE & status);
472 
473 	if (status & (IE_ST_RECV | IE_ST_RNR)) {
474 #ifdef IEDEBUG
475 		in_ierint++;
476 		if (sc->sc_debug & IED_RINT)
477 			printf("%s: rint\n", device_xname(sc->sc_dev));
478 #endif
479 		ierint(sc);
480 #ifdef IEDEBUG
481 		in_ierint--;
482 #endif
483 	}
484 
485 	if (status & IE_ST_DONE) {
486 #ifdef IEDEBUG
487 		in_ietint++;
488 		if (sc->sc_debug & IED_TINT)
489 			printf("%s: tint\n", device_xname(sc->sc_dev));
490 #endif
491 		ietint(sc);
492 #ifdef IEDEBUG
493 		in_ietint--;
494 #endif
495 	}
496 
497 	/*
498 	 * Receiver not ready (RNR) just means it has
499 	 * run out of resources (buffers or frames).
500 	 * One can easily cause this with (i.e.) spray.
501 	 * This is not a serious error, so be silent.
502 	 */
503 	if (status & IE_ST_RNR) {
504 #ifdef IEDEBUG
505 		printf("%s: receiver not ready\n", device_xname(sc->sc_dev));
506 #endif
507 		sc->sc_if.if_ierrors++;
508 		iereset(sc);
509 	}
510 
511 #ifdef IEDEBUG
512 	if ((status & IE_ST_ALLDONE) && (sc->sc_debug & IED_CNA))
513 		printf("%s: cna\n", device_xname(sc->sc_dev));
514 #endif
515 
516 	status = sc->scb->ie_status;
517 	if (status & IE_ST_WHENCE) {
518 		/* It still wants service... */
519 		if (--loopcnt > 0)
520 			goto loop;
521 		/* ... but we've been here long enough. */
522 		log(LOG_ERR, "%s: interrupt stuck?\n",
523 		    device_xname(sc->sc_dev));
524 		iereset(sc);
525 	}
526 	return 1;
527 }
528 
529 /*
530  * Process a received-frame interrupt.
531  */
532 void
533 ierint(struct ie_softc *sc)
534 {
535 	volatile struct ie_sys_ctl_block *scb = sc->scb;
536 	int i, status;
537 	static int timesthru = 1024;
538 
539 	i = sc->rfhead;
540 	for (;;) {
541 		status = sc->rframes[i]->ie_fd_status;
542 
543 		if ((status & IE_FD_COMPLETE) && (status & IE_FD_OK)) {
544 			if (!--timesthru) {
545 				sc->sc_if.if_ierrors +=
546 				    SWAP(scb->ie_err_crc) +
547 				    SWAP(scb->ie_err_align) +
548 				    SWAP(scb->ie_err_resource) +
549 				    SWAP(scb->ie_err_overrun);
550 				scb->ie_err_crc = 0;
551 				scb->ie_err_align = 0;
552 				scb->ie_err_resource = 0;
553 				scb->ie_err_overrun = 0;
554 				timesthru = 1024;
555 			}
556 			ie_readframe(sc, i);
557 		} else {
558 			if ((status & IE_FD_RNR) != 0 &&
559 			    (scb->ie_status & IE_RU_READY) == 0) {
560 				sc->rframes[0]->ie_fd_buf_desc = vtop16sw(sc,
561 				    __UNVOLATILE(sc->rbuffs[0]));
562 				scb->ie_recv_list = vtop16sw(sc,
563 				    __UNVOLATILE(sc->rframes[0]));
564 				cmd_and_wait(sc, IE_RU_START, 0, 0);
565 			}
566 			break;
567 		}
568 		i = (i + 1) % sc->nframes;
569 	}
570 }
571 
572 /*
573  * Process a command-complete interrupt.  These are only generated by the
574  * transmission of frames.  This routine is deceptively simple, since most
575  * of the real work is done by iestart().
576  */
577 void
578 ietint(struct ie_softc *sc)
579 {
580 	struct ifnet *ifp;
581 	int status;
582 
583 	ifp = &sc->sc_if;
584 
585 	ifp->if_timer = 0;
586 	ifp->if_flags &= ~IFF_OACTIVE;
587 
588 	status = sc->xmit_cmds[sc->xctail]->ie_xmit_status;
589 
590 	if (!(status & IE_STAT_COMPL) || (status & IE_STAT_BUSY))
591 		printf("%s: command still busy!\n", __func__);
592 
593 	if (status & IE_STAT_OK) {
594 		ifp->if_opackets++;
595 		ifp->if_collisions += SWAP(status & IE_XS_MAXCOLL);
596 	} else {
597 		ifp->if_oerrors++;
598 		/*
599 		 * XXX
600 		 * Check SQE and DEFERRED?
601 		 * What if more than one bit is set?
602 		 */
603 		if (status & IE_STAT_ABORT)
604 			printf("%s: send aborted\n", device_xname(sc->sc_dev));
605 		if (status & IE_XS_LATECOLL)
606 			printf("%s: late collision\n",
607 			    device_xname(sc->sc_dev));
608 		if (status & IE_XS_NOCARRIER)
609 			printf("%s: no carrier\n", device_xname(sc->sc_dev));
610 		if (status & IE_XS_LOSTCTS)
611 			printf("%s: lost CTS\n", device_xname(sc->sc_dev));
612 		if (status & IE_XS_UNDERRUN)
613 			printf("%s: DMA underrun\n", device_xname(sc->sc_dev));
614 		if (status & IE_XS_EXCMAX) {
615 			/* Do not print this one (too noisy). */
616 			ifp->if_collisions += 16;
617 		}
618 	}
619 
620 	/*
621 	 * If multicast addresses were added or deleted while we
622 	 * were transmitting, mc_reset() set the want_mcsetup flag
623 	 * indicating that we should do it.
624 	 */
625 	if (sc->want_mcsetup) {
626 		mc_setup(sc, (void *)sc->xmit_cbuffs[sc->xctail]);
627 		sc->want_mcsetup = 0;
628 	}
629 
630 	/* Done with the buffer. */
631 	sc->xmit_busy--;
632 	sc->xctail = (sc->xctail + 1) % NTXBUF;
633 
634 	/* Start the next packet, if any, transmitting. */
635 	if (sc->xmit_busy > 0)
636 		iexmit(sc);
637 
638 	if_schedule_deferred_start(ifp);
639 }
640 
641 /*
642  * Compare two Ether/802 addresses for equality, inlined and
643  * unrolled for speed.  I'd love to have an inline assembler
644  * version of this...   XXX: Who wanted that? mycroft?
645  * I wrote one, but the following is just as efficient.
646  * This expands to 10 short m68k instructions! -gwr
647  * Note: use this like memcmp()
648  */
649 static inline uint16_t
650 ether_cmp(uint8_t *one, uint8_t *two)
651 {
652 	uint16_t *a = (uint16_t *)one;
653 	uint16_t *b = (uint16_t *)two;
654 	uint16_t diff;
655 
656 	diff  = *a++ - *b++;
657 	diff |= *a++ - *b++;
658 	diff |= *a++ - *b++;
659 
660 	return diff;
661 }
662 #define	ether_equal !ether_cmp
663 
664 /*
665  * We want to isolate the bits that have meaning...  This assumes that
666  * IE_RBUF_SIZE is an even power of two.  If somehow the act_len exceeds
667  * the size of the buffer, then we are screwed anyway.
668  */
669 static inline int
670 ie_buflen(struct ie_softc *sc, int head)
671 {
672 	int len;
673 
674 	len = SWAP(sc->rbuffs[head]->ie_rbd_actual);
675 	len &= (IE_RBUF_SIZE | (IE_RBUF_SIZE - 1));
676 	return len;
677 }
678 
679 static inline int
680 ie_packet_len(struct ie_softc *sc)
681 {
682 	int i;
683 	int head = sc->rbhead;
684 	int acc = 0;
685 
686 	do {
687 		if ((sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_USED)
688 		    == 0) {
689 #ifdef IEDEBUG
690 			print_rbd(sc->rbuffs[sc->rbhead]);
691 #endif
692 			log(LOG_ERR,
693 			    "%s: receive descriptors out of sync at %d\n",
694 			    device_xname(sc->sc_dev), sc->rbhead);
695 			iereset(sc);
696 			return -1;
697 		}
698 
699 		i = sc->rbuffs[head]->ie_rbd_actual & IE_RBD_LAST;
700 
701 		acc += ie_buflen(sc, head);
702 		head = (head + 1) % sc->nrxbuf;
703 	} while (i == 0);
704 
705 	return acc;
706 }
707 
708 /*
709  * Setup all necessary artifacts for an XMIT command, and then pass the XMIT
710  * command to the chip to be executed.  On the way, if we have a BPF listener
711  * also give him a copy.
712  */
713 static void
714 iexmit(struct ie_softc *sc)
715 {
716 	struct ifnet *ifp;
717 
718 	ifp = &sc->sc_if;
719 
720 #ifdef IEDEBUG
721 	if (sc->sc_debug & IED_XMIT)
722 		printf("%s: xmit buffer %d\n", device_xname(sc->sc_dev),
723 		    sc->xctail);
724 #endif
725 
726 	sc->xmit_buffs[sc->xctail]->ie_xmit_flags |= IE_XMIT_LAST;
727 	sc->xmit_buffs[sc->xctail]->ie_xmit_next = SWAP(0xffff);
728 	sc->xmit_buffs[sc->xctail]->ie_xmit_buf =
729 	    Swap32(vtop24(sc, sc->xmit_cbuffs[sc->xctail]));
730 
731 	sc->xmit_cmds[sc->xctail]->com.ie_cmd_link = SWAP(0xffff);
732 	sc->xmit_cmds[sc->xctail]->com.ie_cmd_cmd =
733 	    IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST;
734 
735 	sc->xmit_cmds[sc->xctail]->ie_xmit_status = SWAP(0);
736 	sc->xmit_cmds[sc->xctail]->ie_xmit_desc =
737 	    vtop16sw(sc, __UNVOLATILE(sc->xmit_buffs[sc->xctail]));
738 
739 	sc->scb->ie_command_list =
740 	    vtop16sw(sc, __UNVOLATILE(sc->xmit_cmds[sc->xctail]));
741 	cmd_and_wait(sc, IE_CU_START, 0, 0);
742 
743 	ifp->if_timer = 5;
744 }
745 
746 /*
747  * Read data off the interface, and turn it into an mbuf chain.
748  *
749  * This code is DRAMATICALLY different from the previous version; this
750  * version tries to allocate the entire mbuf chain up front, given the
751  * length of the data available.  This enables us to allocate mbuf
752  * clusters in many situations where before we would have had a long
753  * chain of partially-full mbufs.  This should help to speed up the
754  * operation considerably.  (Provided that it works, of course.)
755  */
756 static inline struct mbuf *
757 ieget(struct ie_softc *sc)
758 {
759 	struct mbuf *top, **mp, *m;
760 	int len, totlen, resid;
761 	int thisrboff, thismboff;
762 	int head;
763 	struct ether_header eh;
764 
765 	totlen = ie_packet_len(sc);
766 	if (totlen <= 0)
767 		return 0;
768 
769 	head = sc->rbhead;
770 
771 	/*
772 	 * Snarf the Ethernet header.
773 	 */
774 	(sc->sc_memcpy)((void *)&eh, (void *)sc->cbuffs[head],
775 	    sizeof(struct ether_header));
776 
777 	resid = totlen;
778 
779 	MGETHDR(m, M_DONTWAIT, MT_DATA);
780 	if (m == 0)
781 		return 0;
782 
783 	m_set_rcvif(m, &sc->sc_if);
784 	m->m_pkthdr.len = totlen;
785 	len = MHLEN;
786 	top = 0;
787 	mp = &top;
788 
789 	/*
790 	 * This loop goes through and allocates mbufs for all the data we will
791 	 * be copying in.  It does not actually do the copying yet.
792 	 */
793 	while (totlen > 0) {
794 		if (top) {
795 			MGET(m, M_DONTWAIT, MT_DATA);
796 			if (m == 0) {
797 				m_freem(top);
798 				return 0;
799 			}
800 			len = MLEN;
801 		}
802 		if (totlen >= MINCLSIZE) {
803 			MCLGET(m, M_DONTWAIT);
804 			if (m->m_flags & M_EXT)
805 				len = MCLBYTES;
806 		}
807 
808 		if (mp == &top) {
809 			char *newdata = (char *)
810 			    ALIGN(m->m_data + sizeof(struct ether_header)) -
811 			    sizeof(struct ether_header);
812 			len -= newdata - m->m_data;
813 			m->m_data = newdata;
814 		}
815 
816 		m->m_len = len = uimin(totlen, len);
817 
818 		totlen -= len;
819 		*mp = m;
820 		mp = &m->m_next;
821 	}
822 
823 	m = top;
824 	thismboff = 0;
825 
826 	/*
827 	 * Copy the Ethernet header into the mbuf chain.
828 	 */
829 	memcpy(mtod(m, void *), &eh, sizeof(struct ether_header));
830 	thismboff = sizeof(struct ether_header);
831 	thisrboff = sizeof(struct ether_header);
832 	resid -= sizeof(struct ether_header);
833 
834 	/*
835 	 * Now we take the mbuf chain (hopefully only one mbuf most of the
836 	 * time) and stuff the data into it.  There are no possible failures
837 	 * at or after this point.
838 	 */
839 	while (resid > 0) {
840 		int thisrblen = ie_buflen(sc, head) - thisrboff;
841 		int thismblen = m->m_len - thismboff;
842 
843 		len = uimin(thisrblen, thismblen);
844 		(sc->sc_memcpy)(mtod(m, char *) + thismboff,
845 		    (void *)(sc->cbuffs[head] + thisrboff),
846 		    (u_int)len);
847 		resid -= len;
848 
849 		if (len == thismblen) {
850 			m = m->m_next;
851 			thismboff = 0;
852 		} else
853 			thismboff += len;
854 
855 		if (len == thisrblen) {
856 			head = (head + 1) % sc->nrxbuf;
857 			thisrboff = 0;
858 		} else
859 			thisrboff += len;
860 	}
861 
862 	/*
863 	 * Unless something changed strangely while we were doing the copy,
864 	 * we have now copied everything in from the shared memory.
865 	 * This means that we are done.
866 	 */
867 	return top;
868 }
869 
870 /*
871  * Read frame NUM from unit UNIT (pre-cached as IE).
872  *
873  * This routine reads the RFD at NUM, and copies in the buffers from
874  * the list of RBD, then rotates the RBD and RFD lists so that the receiver
875  * doesn't start complaining.  Trailers are DROPPED---there's no point
876  * in wasting time on confusing code to deal with them.  Hopefully,
877  * this machine will never ARP for trailers anyway.
878  */
879 static void
880 ie_readframe(struct ie_softc *sc, int num)
881 {
882 	int status;
883 	struct mbuf *m = 0;
884 
885 	status = sc->rframes[num]->ie_fd_status;
886 
887 	/* Advance the RFD list, since we're done with this descriptor. */
888 	sc->rframes[num]->ie_fd_status = SWAP(0);
889 	sc->rframes[num]->ie_fd_last |= IE_FD_LAST;
890 	sc->rframes[sc->rftail]->ie_fd_last &= ~IE_FD_LAST;
891 	sc->rftail = (sc->rftail + 1) % sc->nframes;
892 	sc->rfhead = (sc->rfhead + 1) % sc->nframes;
893 
894 	if (status & IE_FD_OK) {
895 		m = ieget(sc);
896 		ie_drop_packet_buffer(sc);
897 	}
898 	if (m == 0) {
899 		sc->sc_if.if_ierrors++;
900 		return;
901 	}
902 
903 #ifdef IEDEBUG
904 	if (sc->sc_debug & IED_READFRAME) {
905 		struct ether_header *eh = mtod(m, struct ether_header *);
906 
907 		printf("%s: frame from ether %s type 0x%x\n",
908 		    device_xname(sc->sc_dev),
909 		    ether_sprintf(eh->ether_shost), (u_int)eh->ether_type);
910 	}
911 #endif
912 
913 	/*
914 	 * Finally pass this packet up to higher layers.
915 	 */
916 	if_percpuq_enqueue((&sc->sc_if)->if_percpuq, m);
917 }
918 
919 static void
920 ie_drop_packet_buffer(struct ie_softc *sc)
921 {
922 	int i;
923 
924 	do {
925 		/*
926 		 * This means we are somehow out of sync.  So, we reset the
927 		 * adapter.
928 		 */
929 		if ((sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_USED)
930 		    == 0) {
931 #ifdef IEDEBUG
932 			print_rbd(sc->rbuffs[sc->rbhead]);
933 #endif
934 			log(LOG_ERR,
935 			    "%s: receive descriptors out of sync at %d\n",
936 			    device_xname(sc->sc_dev), sc->rbhead);
937 			iereset(sc);
938 			return;
939 		}
940 
941 		i = sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_LAST;
942 
943 		sc->rbuffs[sc->rbhead]->ie_rbd_length |= IE_RBD_LAST;
944 		sc->rbuffs[sc->rbhead]->ie_rbd_actual = SWAP(0);
945 		sc->rbhead = (sc->rbhead + 1) % sc->nrxbuf;
946 		sc->rbuffs[sc->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
947 		sc->rbtail = (sc->rbtail + 1) % sc->nrxbuf;
948 	} while (i == 0);
949 }
950 
951 /*
952  * Start transmission on an interface.
953  */
954 static void
955 iestart(struct ifnet *ifp)
956 {
957 	struct ie_softc *sc = ifp->if_softc;
958 	struct mbuf *m0, *m;
959 	uint8_t *buffer;
960 	uint16_t len;
961 
962 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
963 		return;
964 
965 	for (;;) {
966 		if (sc->xmit_busy == sc->ntxbuf) {
967 			ifp->if_flags |= IFF_OACTIVE;
968 			break;
969 		}
970 
971 		IF_DEQUEUE(&ifp->if_snd, m0);
972 		if (m0 == 0)
973 			break;
974 
975 		/* We need to use m->m_pkthdr.len, so require the header */
976 		if ((m0->m_flags & M_PKTHDR) == 0)
977 			panic("%s: no header mbuf", __func__);
978 
979 		/* Tap off here if there is a BPF listener. */
980 		bpf_mtap(ifp, m0, BPF_D_OUT);
981 
982 #ifdef IEDEBUG
983 		if (sc->sc_debug & IED_ENQ)
984 			printf("%s: fill buffer %d\n", device_xname(sc->sc_dev),
985 			    sc->xchead);
986 #endif
987 
988 		buffer = sc->xmit_cbuffs[sc->xchead];
989 		for (m = m0; m != 0; m = m->m_next) {
990 			(sc->sc_memcpy)(buffer, mtod(m, void *), m->m_len);
991 			buffer += m->m_len;
992 		}
993 		if (m0->m_pkthdr.len < ETHER_MIN_LEN - ETHER_CRC_LEN) {
994 			sc->sc_memset(buffer, 0,
995 			    ETHER_MIN_LEN - ETHER_CRC_LEN - m0->m_pkthdr.len);
996 			len = ETHER_MIN_LEN - ETHER_CRC_LEN;
997 		} else
998 			len = m0->m_pkthdr.len;
999 
1000 		m_freem(m0);
1001 		sc->xmit_buffs[sc->xchead]->ie_xmit_flags = SWAP(len);
1002 
1003 		/* Start the first packet transmitting. */
1004 		if (sc->xmit_busy == 0)
1005 			iexmit(sc);
1006 
1007 		sc->xchead = (sc->xchead + 1) % sc->ntxbuf;
1008 		sc->xmit_busy++;
1009 	}
1010 }
1011 
1012 static void
1013 iereset(struct ie_softc *sc)
1014 {
1015 	int s;
1016 
1017 	s = splnet();
1018 
1019 	/* No message here.  The caller does that. */
1020 	iestop(sc);
1021 
1022 	/*
1023 	 * Stop i82586 dead in its tracks.
1024 	 */
1025 	if (cmd_and_wait(sc, IE_RU_ABORT | IE_CU_ABORT, 0, 0))
1026 		printf("%s: abort commands timed out\n",
1027 		    device_xname(sc->sc_dev));
1028 
1029 	if (cmd_and_wait(sc, IE_RU_DISABLE | IE_CU_STOP, 0, 0))
1030 		printf("%s: disable commands timed out\n",
1031 		    device_xname(sc->sc_dev));
1032 
1033 	ieinit(sc);
1034 
1035 	splx(s);
1036 }
1037 
1038 /*
1039  * Send a command to the controller and wait for it to either
1040  * complete or be accepted, depending on the command.  If the
1041  * command pointer is null, then pretend that the command is
1042  * not an action command.  If the command pointer is not null,
1043  * and the command is an action command, wait for
1044  * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK
1045  * to become true.
1046  */
1047 static int
1048 cmd_and_wait(struct ie_softc *sc, int cmd, void *pcmd, int mask)
1049 {
1050 	volatile struct ie_cmd_common *cc = pcmd;
1051 	volatile struct ie_sys_ctl_block *scb = sc->scb;
1052 	int tmo;
1053 
1054 	scb->ie_command = (uint16_t)cmd;
1055 	(sc->chan_attn)(sc);
1056 
1057 	/* Wait for the command to be accepted by the CU. */
1058 	tmo = 10;
1059 	while (scb->ie_command && --tmo)
1060 		delay(10);
1061 	if (scb->ie_command) {
1062 #ifdef	IEDEBUG
1063 		printf("%s: cmd_and_wait, CU stuck (1)\n",
1064 		    device_xname(sc->sc_dev));
1065 #endif
1066 		return -1;	/* timed out */
1067 	}
1068 
1069 	/*
1070 	 * If asked, also wait for it to finish.
1071 	 */
1072 	if (IE_ACTION_COMMAND(cmd) && pcmd) {
1073 
1074 		/*
1075 		 * According to the packet driver, the minimum timeout should
1076 		 * be .369 seconds, which we round up to .4.
1077 		 */
1078 		tmo = 36900;
1079 
1080 		/*
1081 		 * Now spin-lock waiting for status.  This is not a very nice
1082 		 * thing to do, but I haven't figured out how, or indeed if, we
1083 		 * can put the process waiting for action to sleep.  (We may
1084 		 * be getting called through some other timeout running in the
1085 		 * kernel.)
1086 		 */
1087 		while (((cc->ie_cmd_status & mask) == 0) && --tmo)
1088 			delay(10);
1089 
1090 		if ((cc->ie_cmd_status & mask) == 0) {
1091 #ifdef	IEDEBUG
1092 			printf("%s: cmd_and_wait, CU stuck (2)\n",
1093 			    device_xname(sc->sc_dev));
1094 #endif
1095 			return -1;	/* timed out */
1096 		}
1097 	}
1098 	return 0;
1099 }
1100 
1101 /*
1102  * Run the time-domain reflectometer.
1103  */
1104 static void
1105 run_tdr(struct ie_softc *sc, struct ie_tdr_cmd *cmd)
1106 {
1107 	int result;
1108 
1109 	cmd->com.ie_cmd_status = SWAP(0);
1110 	cmd->com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST;
1111 	cmd->com.ie_cmd_link = SWAP(0xffff);
1112 
1113 	sc->scb->ie_command_list = vtop16sw(sc, cmd);
1114 	cmd->ie_tdr_time = SWAP(0);
1115 
1116 	if (cmd_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
1117 	    (cmd->com.ie_cmd_status & IE_STAT_OK) == 0)
1118 		result = 0x10000;	/* impossible value */
1119 	else
1120 		result = cmd->ie_tdr_time;
1121 
1122 	ie_ack(sc, IE_ST_WHENCE);
1123 
1124 	if (result & IE_TDR_SUCCESS)
1125 		return;
1126 
1127 	if (result & 0x10000) {
1128 		printf("%s: TDR command failed\n", device_xname(sc->sc_dev));
1129 	} else if (result & IE_TDR_XCVR) {
1130 		printf("%s: transceiver problem\n", device_xname(sc->sc_dev));
1131 	} else if (result & IE_TDR_OPEN) {
1132 		printf("%s: TDR detected an open %d clocks away\n",
1133 		    device_xname(sc->sc_dev), SWAP(result & IE_TDR_TIME));
1134 	} else if (result & IE_TDR_SHORT) {
1135 		printf("%s: TDR detected a short %d clocks away\n",
1136 		    device_xname(sc->sc_dev), SWAP(result & IE_TDR_TIME));
1137 	} else {
1138 		printf("%s: TDR returned unknown status 0x%x\n",
1139 		    device_xname(sc->sc_dev), result);
1140 	}
1141 }
1142 
1143 /*
1144  * iememinit: set up the buffers
1145  *
1146  * we have a block of KVA at sc->buf_area which is of size sc->buf_area_sz.
1147  * this is to be used for the buffers.  the chip indexs its control data
1148  * structures with 16 bit offsets, and it indexes actual buffers with
1149  * 24 bit addresses.   so we should allocate control buffers first so that
1150  * we don't overflow the 16 bit offset field.   The number of transmit
1151  * buffers is fixed at compile time.
1152  *
1153  * note: this function was written to be easy to understand, rather than
1154  *       highly efficient (it isn't in the critical path).
1155  *
1156  * The memory layout is: tbufs, rbufs, (gap), control blocks
1157  * [tbuf0, tbuf1] [rbuf0,...rbufN] gap [rframes] [tframes]
1158  * XXX - This needs review...
1159  */
1160 static void
1161 iememinit(struct ie_softc *sc)
1162 {
1163 	uint8_t *ptr;
1164 	int i;
1165 	uint16_t nxt;
1166 
1167 	/* First, zero all the memory. */
1168 	ptr = sc->buf_area;
1169 	(sc->sc_memset)(ptr, 0, sc->buf_area_sz);
1170 
1171 	/* Allocate tx/rx buffers. */
1172 	for (i = 0; i < NTXBUF; i++) {
1173 		sc->xmit_cbuffs[i] = ptr;
1174 		ptr += IE_TBUF_SIZE;
1175 	}
1176 	for (i = 0; i < sc->nrxbuf; i++) {
1177 		sc->cbuffs[i] = ptr;
1178 		ptr += IE_RBUF_SIZE;
1179 	}
1180 
1181 	/* Small pad (Don't trust the chip...) */
1182 	ptr += 16;
1183 
1184 	/* Allocate and fill in xmit buffer descriptors. */
1185 	for (i = 0; i < NTXBUF; i++) {
1186 		sc->xmit_buffs[i] = (volatile void *)ptr;
1187 		ptr = Align(ptr + sizeof(*sc->xmit_buffs[i]));
1188 		sc->xmit_buffs[i]->ie_xmit_buf =
1189 		    Swap32(vtop24(sc, sc->xmit_cbuffs[i]));
1190 		sc->xmit_buffs[i]->ie_xmit_next = SWAP(0xffff);
1191 	}
1192 
1193 	/* Allocate and fill in recv buffer descriptors. */
1194 	for (i = 0; i < sc->nrxbuf; i++) {
1195 		sc->rbuffs[i] = (volatile void *)ptr;
1196 		ptr = Align(ptr + sizeof(*sc->rbuffs[i]));
1197 		sc->rbuffs[i]->ie_rbd_buffer =
1198 		    Swap32(vtop24(sc, sc->cbuffs[i]));
1199 		sc->rbuffs[i]->ie_rbd_length = SWAP(IE_RBUF_SIZE);
1200 	}
1201 
1202 	/* link together recv bufs and set EOL on last */
1203 	i = sc->nrxbuf - 1;
1204 	sc->rbuffs[i]->ie_rbd_length |= IE_RBD_LAST;
1205 	nxt = vtop16sw(sc, __UNVOLATILE(sc->rbuffs[0]));
1206 	do {
1207 		sc->rbuffs[i]->ie_rbd_next = nxt;
1208 		nxt = vtop16sw(sc, __UNVOLATILE(sc->rbuffs[i]));
1209 	} while (--i >= 0);
1210 
1211 	/* Allocate transmit commands. */
1212 	for (i = 0; i < NTXBUF; i++) {
1213 		sc->xmit_cmds[i] = (volatile void *)ptr;
1214 		ptr = Align(ptr + sizeof(*sc->xmit_cmds[i]));
1215 		sc->xmit_cmds[i]->com.ie_cmd_link = SWAP(0xffff);
1216 	}
1217 
1218 	/* Allocate receive frames. */
1219 	for (i = 0; i < sc->nframes; i++) {
1220 		sc->rframes[i] = (volatile void *)ptr;
1221 		ptr = Align(ptr + sizeof(*sc->rframes[i]));
1222 	}
1223 
1224 	/* Link together recv frames and set EOL on last */
1225 	i = sc->nframes - 1;
1226 	sc->rframes[i]->ie_fd_last |= IE_FD_LAST;
1227 	nxt = vtop16sw(sc, __UNVOLATILE(sc->rframes[0]));
1228 	do {
1229 		sc->rframes[i]->ie_fd_next = nxt;
1230 		nxt = vtop16sw(sc, __UNVOLATILE(sc->rframes[i]));
1231 	} while (--i >= 0);
1232 
1233 
1234 	/* Pointers to last packet sent and next available transmit buffer. */
1235 	sc->xchead = sc->xctail = 0;
1236 
1237 	/* Clear transmit-busy flag. */
1238 	sc->xmit_busy = 0;
1239 
1240 	/*
1241 	 * Set the head and tail pointers on receive to keep track of
1242 	 * the order in which RFDs and RBDs are used.   link the
1243 	 * recv frames and buffer into the scb.
1244 	 */
1245 	sc->rfhead = 0;
1246 	sc->rftail = sc->nframes - 1;
1247 	sc->rbhead = 0;
1248 	sc->rbtail = sc->nrxbuf - 1;
1249 
1250 	sc->scb->ie_recv_list =
1251 	    vtop16sw(sc, __UNVOLATILE(sc->rframes[0]));
1252 	sc->rframes[0]->ie_fd_buf_desc =
1253 	    vtop16sw(sc, __UNVOLATILE(sc->rbuffs[0]));
1254 
1255 	i = (ptr - sc->buf_area);
1256 #ifdef IEDEBUG
1257 	printf("IE_DEBUG: used %d of %d bytes\n", i, sc->buf_area_sz);
1258 #endif
1259 	if (i > sc->buf_area_sz)
1260 		panic("ie: iememinit, out of space");
1261 }
1262 
1263 /*
1264  * Run the multicast setup command.
1265  * Called at splnet().
1266  */
1267 static int
1268 mc_setup(struct ie_softc *sc, void *ptr)
1269 {
1270 	struct ie_mcast_cmd *cmd = ptr;	/* XXX - Was volatile */
1271 
1272 	cmd->com.ie_cmd_status = SWAP(0);
1273 	cmd->com.ie_cmd_cmd = IE_CMD_MCAST | IE_CMD_LAST;
1274 	cmd->com.ie_cmd_link = SWAP(0xffff);
1275 
1276 	(sc->sc_memcpy)((void *)cmd->ie_mcast_addrs,
1277 	    (void *)sc->mcast_addrs,
1278 	    sc->mcast_count * sizeof *sc->mcast_addrs);
1279 
1280 	cmd->ie_mcast_bytes =
1281 	    SWAP(sc->mcast_count * ETHER_ADDR_LEN);	/* grrr... */
1282 
1283 	sc->scb->ie_command_list = vtop16sw(sc, cmd);
1284 	if (cmd_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
1285 	    (cmd->com.ie_cmd_status & IE_STAT_OK) == 0) {
1286 		printf("%s: multicast address setup command failed\n",
1287 		    device_xname(sc->sc_dev));
1288 		return 0;
1289 	}
1290 	return 1;
1291 }
1292 
1293 static inline void
1294 ie_setup_config(struct ie_config_cmd *cmd, int promiscuous, int manchester)
1295 {
1296 
1297 	/*
1298 	 * these are all char's so no need to byte-swap
1299 	 */
1300 	cmd->ie_config_count = 0x0c;
1301 	cmd->ie_fifo = 8;
1302 	cmd->ie_save_bad = 0x40;
1303 	cmd->ie_addr_len = 0x2e;
1304 	cmd->ie_priority = 0;
1305 	cmd->ie_ifs = 0x60;
1306 	cmd->ie_slot_low = 0;
1307 	cmd->ie_slot_high = 0xf2;
1308 	cmd->ie_promisc = promiscuous | manchester << 2;
1309 	cmd->ie_crs_cdt = 0;
1310 	cmd->ie_min_len = 64;
1311 	cmd->ie_junk = 0xff;
1312 }
1313 
1314 /*
1315  * This routine inits the ie.
1316  * This includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands,
1317  * starting the receiver unit, and clearing interrupts.
1318  *
1319  * THIS ROUTINE MUST BE CALLED AT splnet() OR HIGHER.
1320  */
1321 static int
1322 ieinit(struct ie_softc *sc)
1323 {
1324 	volatile struct ie_sys_ctl_block *scb = sc->scb;
1325 	void *ptr;
1326 	struct ifnet *ifp;
1327 
1328 	ifp = &sc->sc_if;
1329 	ptr = sc->buf_area;	/* XXX - Use scb instead? */
1330 
1331 	/*
1332 	 * Send the configure command first.
1333 	 */
1334 	{
1335 		struct ie_config_cmd *cmd = ptr;	/* XXX - Was volatile */
1336 
1337 		scb->ie_command_list = vtop16sw(sc, cmd);
1338 		cmd->com.ie_cmd_status = SWAP(0);
1339 		cmd->com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
1340 		cmd->com.ie_cmd_link = SWAP(0xffff);
1341 
1342 		ie_setup_config(cmd, (sc->promisc != 0), 0);
1343 
1344 		if (cmd_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
1345 		    (cmd->com.ie_cmd_status & IE_STAT_OK) == 0) {
1346 			printf("%s: configure command failed\n",
1347 			    device_xname(sc->sc_dev));
1348 			return 0;
1349 		}
1350 	}
1351 
1352 	/*
1353 	 * Now send the Individual Address Setup command.
1354 	 */
1355 	{
1356 		struct ie_iasetup_cmd *cmd = ptr;	/* XXX - Was volatile */
1357 
1358 		scb->ie_command_list = vtop16sw(sc, cmd);
1359 		cmd->com.ie_cmd_status = SWAP(0);
1360 		cmd->com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
1361 		cmd->com.ie_cmd_link = SWAP(0xffff);
1362 
1363 		(sc->sc_memcpy)((void *)&cmd->ie_address,
1364 		    CLLADDR(ifp->if_sadl), sizeof(cmd->ie_address));
1365 
1366 		if (cmd_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
1367 		    (cmd->com.ie_cmd_status & IE_STAT_OK) == 0) {
1368 			printf("%s: individual address setup command failed\n",
1369 			    device_xname(sc->sc_dev));
1370 			return 0;
1371 		}
1372 	}
1373 
1374 	/*
1375 	 * Now run the time-domain reflectometer.
1376 	 */
1377 	if (ie_run_tdr)
1378 		run_tdr(sc, ptr);
1379 
1380 	/*
1381 	 * Acknowledge any interrupts we have generated thus far.
1382 	 */
1383 	ie_ack(sc, IE_ST_WHENCE);
1384 
1385 	/*
1386 	 * Set up the transmit and recv buffers.
1387 	 */
1388 	iememinit(sc);
1389 
1390 	/* tell higher levels that we are here */
1391 	ifp->if_flags |= IFF_RUNNING;
1392 	ifp->if_flags &= ~IFF_OACTIVE;
1393 
1394 	sc->scb->ie_recv_list =
1395 	    vtop16sw(sc, __UNVOLATILE(sc->rframes[0]));
1396 	cmd_and_wait(sc, IE_RU_START, 0, 0);
1397 
1398 	ie_ack(sc, IE_ST_WHENCE);
1399 
1400 	if (sc->run_586)
1401 		(sc->run_586)(sc);
1402 
1403 	return 0;
1404 }
1405 
1406 static void
1407 iestop(struct ie_softc *sc)
1408 {
1409 
1410 	cmd_and_wait(sc, IE_RU_DISABLE, 0, 0);
1411 }
1412 
1413 static int
1414 ieioctl(struct ifnet *ifp, u_long cmd, void *data)
1415 {
1416 	struct ie_softc *sc = ifp->if_softc;
1417 	struct ifaddr *ifa = (struct ifaddr *)data;
1418 	int s, error = 0;
1419 
1420 	s = splnet();
1421 
1422 	switch (cmd) {
1423 
1424 	case SIOCINITIFADDR:
1425 		ifp->if_flags |= IFF_UP;
1426 
1427 		switch (ifa->ifa_addr->sa_family) {
1428 #ifdef INET
1429 		case AF_INET:
1430 			ieinit(sc);
1431 			arp_ifinit(ifp, ifa);
1432 			break;
1433 #endif
1434 		default:
1435 			ieinit(sc);
1436 			break;
1437 		}
1438 		break;
1439 
1440 	case SIOCSIFFLAGS:
1441 		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
1442 			break;
1443 		sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
1444 
1445 		switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
1446 		case IFF_RUNNING:
1447 			/*
1448 			 * If interface is marked down and it is running, then
1449 			 * stop it.
1450 			 */
1451 			iestop(sc);
1452 			ifp->if_flags &= ~IFF_RUNNING;
1453 			break;
1454 		case IFF_UP:
1455 			/*
1456 			 * If interface is marked up and it is stopped, then
1457 			 * start it.
1458 			 */
1459 			ieinit(sc);
1460 			break;
1461 		default:
1462 			/*
1463 			 * Reset the interface to pick up changes in any other
1464 			 * flags that affect hardware registers.
1465 			 */
1466 			iestop(sc);
1467 			ieinit(sc);
1468 			break;
1469 		}
1470 #ifdef IEDEBUG
1471 		if (ifp->if_flags & IFF_DEBUG)
1472 			sc->sc_debug = IED_ALL;
1473 		else
1474 			sc->sc_debug = ie_debug_flags;
1475 #endif
1476 		break;
1477 
1478 	case SIOCADDMULTI:
1479 	case SIOCDELMULTI:
1480 		if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
1481 			/*
1482 			 * Multicast list has changed; set the hardware filter
1483 			 * accordingly.
1484 			 */
1485 			if (ifp->if_flags & IFF_RUNNING)
1486 				mc_reset(sc);
1487 			error = 0;
1488 		}
1489 		break;
1490 
1491 	default:
1492 		error = ether_ioctl(ifp, cmd, data);
1493 		break;
1494 	}
1495 	splx(s);
1496 	return error;
1497 }
1498 
1499 static void
1500 mc_reset(struct ie_softc *sc)
1501 {
1502 	struct ethercom *ec = &sc->sc_ethercom;
1503 	struct ether_multi *enm;
1504 	struct ether_multistep step;
1505 	struct ifnet *ifp;
1506 
1507 	ifp = &sc->sc_if;
1508 
1509 	/*
1510 	 * Step through the list of addresses.
1511 	 */
1512 	sc->mcast_count = 0;
1513 	ETHER_FIRST_MULTI(step, ec, enm);
1514 	while (enm) {
1515 		if (sc->mcast_count >= MAXMCAST ||
1516 		    ether_cmp(enm->enm_addrlo, enm->enm_addrhi) != 0) {
1517 			ifp->if_flags |= IFF_ALLMULTI;
1518 			ieioctl(ifp, SIOCSIFFLAGS, NULL);
1519 			goto setflag;
1520 		}
1521 		memcpy(&sc->mcast_addrs[sc->mcast_count], enm->enm_addrlo,
1522 		    ETHER_ADDR_LEN);
1523 		sc->mcast_count++;
1524 		ETHER_NEXT_MULTI(step, enm);
1525 	}
1526 setflag:
1527 	ETHER_UNLOCK(ec);
1528 	sc->want_mcsetup = 1;
1529 }
1530 
1531 #ifdef IEDEBUG
1532 void
1533 print_rbd(volatile struct ie_recv_buf_desc *rbd)
1534 {
1535 
1536 	printf("RBD at %08lx:\nactual %04x, next %04x, buffer %08x\n"
1537 	    "length %04x, mbz %04x\n", (u_long)rbd, rbd->ie_rbd_actual,
1538 	    rbd->ie_rbd_next, rbd->ie_rbd_buffer, rbd->ie_rbd_length,
1539 	    rbd->mbz);
1540 }
1541 #endif
1542