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