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