xref: /netbsd-src/sys/arch/sun3/dev/if_ie.c (revision 2e2322c9c07009df921d11b1268f8506affbb8ba)
1 /*	$NetBSD: if_ie.c,v 1.60 2016/12/06 07:49:25 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.60 2016/12/06 07:49:25 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 	/* Pass it up. */
924 	bpf_mtap(&sc->sc_if, m);
925 
926 	/*
927 	 * Finally pass this packet up to higher layers.
928 	 */
929 	if_percpuq_enqueue((&sc->sc_if)->if_percpuq, m);
930 	sc->sc_if.if_ipackets++;
931 }
932 
933 static void
934 ie_drop_packet_buffer(struct ie_softc *sc)
935 {
936 	int i;
937 
938 	do {
939 		/*
940 		 * This means we are somehow out of sync.  So, we reset the
941 		 * adapter.
942 		 */
943 		if ((sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_USED)
944 		    == 0) {
945 #ifdef IEDEBUG
946 			print_rbd(sc->rbuffs[sc->rbhead]);
947 #endif
948 			log(LOG_ERR,
949 			    "%s: receive descriptors out of sync at %d\n",
950 			    device_xname(sc->sc_dev), sc->rbhead);
951 			iereset(sc);
952 			return;
953 		}
954 
955 		i = sc->rbuffs[sc->rbhead]->ie_rbd_actual & IE_RBD_LAST;
956 
957 		sc->rbuffs[sc->rbhead]->ie_rbd_length |= IE_RBD_LAST;
958 		sc->rbuffs[sc->rbhead]->ie_rbd_actual = SWAP(0);
959 		sc->rbhead = (sc->rbhead + 1) % sc->nrxbuf;
960 		sc->rbuffs[sc->rbtail]->ie_rbd_length &= ~IE_RBD_LAST;
961 		sc->rbtail = (sc->rbtail + 1) % sc->nrxbuf;
962 	} while (i == 0);
963 }
964 
965 /*
966  * Start transmission on an interface.
967  */
968 static void
969 iestart(struct ifnet *ifp)
970 {
971 	struct ie_softc *sc = ifp->if_softc;
972 	struct mbuf *m0, *m;
973 	uint8_t *buffer;
974 	uint16_t len;
975 
976 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
977 		return;
978 
979 	for (;;) {
980 		if (sc->xmit_busy == sc->ntxbuf) {
981 			ifp->if_flags |= IFF_OACTIVE;
982 			break;
983 		}
984 
985 		IF_DEQUEUE(&ifp->if_snd, m0);
986 		if (m0 == 0)
987 			break;
988 
989 		/* We need to use m->m_pkthdr.len, so require the header */
990 		if ((m0->m_flags & M_PKTHDR) == 0)
991 			panic("%s: no header mbuf", __func__);
992 
993 		/* Tap off here if there is a BPF listener. */
994 		bpf_mtap(ifp, m0);
995 
996 #ifdef IEDEBUG
997 		if (sc->sc_debug & IED_ENQ)
998 			printf("%s: fill buffer %d\n", device_xname(sc->sc_dev),
999 			    sc->xchead);
1000 #endif
1001 
1002 		buffer = sc->xmit_cbuffs[sc->xchead];
1003 		for (m = m0; m != 0; m = m->m_next) {
1004 			(sc->sc_memcpy)(buffer, mtod(m, void *), m->m_len);
1005 			buffer += m->m_len;
1006 		}
1007 		if (m0->m_pkthdr.len < ETHER_MIN_LEN - ETHER_CRC_LEN) {
1008 			sc->sc_memset(buffer, 0,
1009 			    ETHER_MIN_LEN - ETHER_CRC_LEN - m0->m_pkthdr.len);
1010 			len = ETHER_MIN_LEN - ETHER_CRC_LEN;
1011 		} else
1012 			len = m0->m_pkthdr.len;
1013 
1014 		m_freem(m0);
1015 		sc->xmit_buffs[sc->xchead]->ie_xmit_flags = SWAP(len);
1016 
1017 		/* Start the first packet transmitting. */
1018 		if (sc->xmit_busy == 0)
1019 			iexmit(sc);
1020 
1021 		sc->xchead = (sc->xchead + 1) % sc->ntxbuf;
1022 		sc->xmit_busy++;
1023 	}
1024 }
1025 
1026 static void
1027 iereset(struct ie_softc *sc)
1028 {
1029 	int s;
1030 
1031 	s = splnet();
1032 
1033 	/* No message here.  The caller does that. */
1034 	iestop(sc);
1035 
1036 	/*
1037 	 * Stop i82586 dead in its tracks.
1038 	 */
1039 	if (cmd_and_wait(sc, IE_RU_ABORT | IE_CU_ABORT, 0, 0))
1040 		printf("%s: abort commands timed out\n",
1041 		    device_xname(sc->sc_dev));
1042 
1043 	if (cmd_and_wait(sc, IE_RU_DISABLE | IE_CU_STOP, 0, 0))
1044 		printf("%s: disable commands timed out\n",
1045 		    device_xname(sc->sc_dev));
1046 
1047 	ieinit(sc);
1048 
1049 	splx(s);
1050 }
1051 
1052 /*
1053  * Send a command to the controller and wait for it to either
1054  * complete or be accepted, depending on the command.  If the
1055  * command pointer is null, then pretend that the command is
1056  * not an action command.  If the command pointer is not null,
1057  * and the command is an action command, wait for
1058  * ((volatile struct ie_cmd_common *)pcmd)->ie_cmd_status & MASK
1059  * to become true.
1060  */
1061 static int
1062 cmd_and_wait(struct ie_softc *sc, int cmd, void *pcmd, int mask)
1063 {
1064 	volatile struct ie_cmd_common *cc = pcmd;
1065 	volatile struct ie_sys_ctl_block *scb = sc->scb;
1066 	int tmo;
1067 
1068 	scb->ie_command = (uint16_t)cmd;
1069 	(sc->chan_attn)(sc);
1070 
1071 	/* Wait for the command to be accepted by the CU. */
1072 	tmo = 10;
1073 	while (scb->ie_command && --tmo)
1074 		delay(10);
1075 	if (scb->ie_command) {
1076 #ifdef	IEDEBUG
1077 		printf("%s: cmd_and_wait, CU stuck (1)\n",
1078 		    device_xname(sc->sc_dev));
1079 #endif
1080 		return -1;	/* timed out */
1081 	}
1082 
1083 	/*
1084 	 * If asked, also wait for it to finish.
1085 	 */
1086 	if (IE_ACTION_COMMAND(cmd) && pcmd) {
1087 
1088 		/*
1089 		 * According to the packet driver, the minimum timeout should
1090 		 * be .369 seconds, which we round up to .4.
1091 		 */
1092 		tmo = 36900;
1093 
1094 		/*
1095 		 * Now spin-lock waiting for status.  This is not a very nice
1096 		 * thing to do, but I haven't figured out how, or indeed if, we
1097 		 * can put the process waiting for action to sleep.  (We may
1098 		 * be getting called through some other timeout running in the
1099 		 * kernel.)
1100 		 */
1101 		while (((cc->ie_cmd_status & mask) == 0) && --tmo)
1102 			delay(10);
1103 
1104 		if ((cc->ie_cmd_status & mask) == 0) {
1105 #ifdef	IEDEBUG
1106 			printf("%s: cmd_and_wait, CU stuck (2)\n",
1107 			    device_xname(sc->sc_dev));
1108 #endif
1109 			return -1;	/* timed out */
1110 		}
1111 	}
1112 	return 0;
1113 }
1114 
1115 /*
1116  * Run the time-domain reflectometer.
1117  */
1118 static void
1119 run_tdr(struct ie_softc *sc, struct ie_tdr_cmd *cmd)
1120 {
1121 	int result;
1122 
1123 	cmd->com.ie_cmd_status = SWAP(0);
1124 	cmd->com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST;
1125 	cmd->com.ie_cmd_link = SWAP(0xffff);
1126 
1127 	sc->scb->ie_command_list = vtop16sw(sc, cmd);
1128 	cmd->ie_tdr_time = SWAP(0);
1129 
1130 	if (cmd_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
1131 	    (cmd->com.ie_cmd_status & IE_STAT_OK) == 0)
1132 		result = 0x10000;	/* impossible value */
1133 	else
1134 		result = cmd->ie_tdr_time;
1135 
1136 	ie_ack(sc, IE_ST_WHENCE);
1137 
1138 	if (result & IE_TDR_SUCCESS)
1139 		return;
1140 
1141 	if (result & 0x10000) {
1142 		printf("%s: TDR command failed\n", device_xname(sc->sc_dev));
1143 	} else if (result & IE_TDR_XCVR) {
1144 		printf("%s: transceiver problem\n", device_xname(sc->sc_dev));
1145 	} else if (result & IE_TDR_OPEN) {
1146 		printf("%s: TDR detected an open %d clocks away\n",
1147 		    device_xname(sc->sc_dev), SWAP(result & IE_TDR_TIME));
1148 	} else if (result & IE_TDR_SHORT) {
1149 		printf("%s: TDR detected a short %d clocks away\n",
1150 		    device_xname(sc->sc_dev), SWAP(result & IE_TDR_TIME));
1151 	} else {
1152 		printf("%s: TDR returned unknown status 0x%x\n",
1153 		    device_xname(sc->sc_dev), result);
1154 	}
1155 }
1156 
1157 /*
1158  * iememinit: set up the buffers
1159  *
1160  * we have a block of KVA at sc->buf_area which is of size sc->buf_area_sz.
1161  * this is to be used for the buffers.  the chip indexs its control data
1162  * structures with 16 bit offsets, and it indexes actual buffers with
1163  * 24 bit addresses.   so we should allocate control buffers first so that
1164  * we don't overflow the 16 bit offset field.   The number of transmit
1165  * buffers is fixed at compile time.
1166  *
1167  * note: this function was written to be easy to understand, rather than
1168  *       highly efficient (it isn't in the critical path).
1169  *
1170  * The memory layout is: tbufs, rbufs, (gap), control blocks
1171  * [tbuf0, tbuf1] [rbuf0,...rbufN] gap [rframes] [tframes]
1172  * XXX - This needs review...
1173  */
1174 static void
1175 iememinit(struct ie_softc *sc)
1176 {
1177 	uint8_t *ptr;
1178 	int i;
1179 	uint16_t nxt;
1180 
1181 	/* First, zero all the memory. */
1182 	ptr = sc->buf_area;
1183 	(sc->sc_memset)(ptr, 0, sc->buf_area_sz);
1184 
1185 	/* Allocate tx/rx buffers. */
1186 	for (i = 0; i < NTXBUF; i++) {
1187 		sc->xmit_cbuffs[i] = ptr;
1188 		ptr += IE_TBUF_SIZE;
1189 	}
1190 	for (i = 0; i < sc->nrxbuf; i++) {
1191 		sc->cbuffs[i] = ptr;
1192 		ptr += IE_RBUF_SIZE;
1193 	}
1194 
1195 	/* Small pad (Don't trust the chip...) */
1196 	ptr += 16;
1197 
1198 	/* Allocate and fill in xmit buffer descriptors. */
1199 	for (i = 0; i < NTXBUF; i++) {
1200 		sc->xmit_buffs[i] = (volatile void *)ptr;
1201 		ptr = Align(ptr + sizeof(*sc->xmit_buffs[i]));
1202 		sc->xmit_buffs[i]->ie_xmit_buf =
1203 		    Swap32(vtop24(sc, sc->xmit_cbuffs[i]));
1204 		sc->xmit_buffs[i]->ie_xmit_next = SWAP(0xffff);
1205 	}
1206 
1207 	/* Allocate and fill in recv buffer descriptors. */
1208 	for (i = 0; i < sc->nrxbuf; i++) {
1209 		sc->rbuffs[i] = (volatile void *)ptr;
1210 		ptr = Align(ptr + sizeof(*sc->rbuffs[i]));
1211 		sc->rbuffs[i]->ie_rbd_buffer =
1212 		    Swap32(vtop24(sc, sc->cbuffs[i]));
1213 		sc->rbuffs[i]->ie_rbd_length = SWAP(IE_RBUF_SIZE);
1214 	}
1215 
1216 	/* link together recv bufs and set EOL on last */
1217 	i = sc->nrxbuf - 1;
1218 	sc->rbuffs[i]->ie_rbd_length |= IE_RBD_LAST;
1219 	nxt = vtop16sw(sc, __UNVOLATILE(sc->rbuffs[0]));
1220 	do {
1221 		sc->rbuffs[i]->ie_rbd_next = nxt;
1222 		nxt = vtop16sw(sc, __UNVOLATILE(sc->rbuffs[i]));
1223 	} while (--i >= 0);
1224 
1225 	/* Allocate transmit commands. */
1226 	for (i = 0; i < NTXBUF; i++) {
1227 		sc->xmit_cmds[i] = (volatile void *)ptr;
1228 		ptr = Align(ptr + sizeof(*sc->xmit_cmds[i]));
1229 		sc->xmit_cmds[i]->com.ie_cmd_link = SWAP(0xffff);
1230 	}
1231 
1232 	/* Allocate receive frames. */
1233 	for (i = 0; i < sc->nframes; i++) {
1234 		sc->rframes[i] = (volatile void *)ptr;
1235 		ptr = Align(ptr + sizeof(*sc->rframes[i]));
1236 	}
1237 
1238 	/* Link together recv frames and set EOL on last */
1239 	i = sc->nframes - 1;
1240 	sc->rframes[i]->ie_fd_last |= IE_FD_LAST;
1241 	nxt = vtop16sw(sc, __UNVOLATILE(sc->rframes[0]));
1242 	do {
1243 		sc->rframes[i]->ie_fd_next = nxt;
1244 		nxt = vtop16sw(sc, __UNVOLATILE(sc->rframes[i]));
1245 	} while (--i >= 0);
1246 
1247 
1248 	/* Pointers to last packet sent and next available transmit buffer. */
1249 	sc->xchead = sc->xctail = 0;
1250 
1251 	/* Clear transmit-busy flag. */
1252 	sc->xmit_busy = 0;
1253 
1254 	/*
1255 	 * Set the head and tail pointers on receive to keep track of
1256 	 * the order in which RFDs and RBDs are used.   link the
1257 	 * recv frames and buffer into the scb.
1258 	 */
1259 	sc->rfhead = 0;
1260 	sc->rftail = sc->nframes - 1;
1261 	sc->rbhead = 0;
1262 	sc->rbtail = sc->nrxbuf - 1;
1263 
1264 	sc->scb->ie_recv_list =
1265 	    vtop16sw(sc, __UNVOLATILE(sc->rframes[0]));
1266 	sc->rframes[0]->ie_fd_buf_desc =
1267 	    vtop16sw(sc, __UNVOLATILE(sc->rbuffs[0]));
1268 
1269 	i = (ptr - sc->buf_area);
1270 #ifdef IEDEBUG
1271 	printf("IE_DEBUG: used %d of %d bytes\n", i, sc->buf_area_sz);
1272 #endif
1273 	if (i > sc->buf_area_sz)
1274 		panic("ie: iememinit, out of space");
1275 }
1276 
1277 /*
1278  * Run the multicast setup command.
1279  * Called at splnet().
1280  */
1281 static int
1282 mc_setup(struct ie_softc *sc, void *ptr)
1283 {
1284 	struct ie_mcast_cmd *cmd = ptr;	/* XXX - Was volatile */
1285 
1286 	cmd->com.ie_cmd_status = SWAP(0);
1287 	cmd->com.ie_cmd_cmd = IE_CMD_MCAST | IE_CMD_LAST;
1288 	cmd->com.ie_cmd_link = SWAP(0xffff);
1289 
1290 	(sc->sc_memcpy)((void *)cmd->ie_mcast_addrs,
1291 	    (void *)sc->mcast_addrs,
1292 	    sc->mcast_count * sizeof *sc->mcast_addrs);
1293 
1294 	cmd->ie_mcast_bytes =
1295 	    SWAP(sc->mcast_count * ETHER_ADDR_LEN);	/* grrr... */
1296 
1297 	sc->scb->ie_command_list = vtop16sw(sc, cmd);
1298 	if (cmd_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
1299 	    (cmd->com.ie_cmd_status & IE_STAT_OK) == 0) {
1300 		printf("%s: multicast address setup command failed\n",
1301 		    device_xname(sc->sc_dev));
1302 		return 0;
1303 	}
1304 	return 1;
1305 }
1306 
1307 static inline void
1308 ie_setup_config(struct ie_config_cmd *cmd, int promiscuous, int manchester)
1309 {
1310 
1311 	/*
1312 	 * these are all char's so no need to byte-swap
1313 	 */
1314 	cmd->ie_config_count = 0x0c;
1315 	cmd->ie_fifo = 8;
1316 	cmd->ie_save_bad = 0x40;
1317 	cmd->ie_addr_len = 0x2e;
1318 	cmd->ie_priority = 0;
1319 	cmd->ie_ifs = 0x60;
1320 	cmd->ie_slot_low = 0;
1321 	cmd->ie_slot_high = 0xf2;
1322 	cmd->ie_promisc = promiscuous | manchester << 2;
1323 	cmd->ie_crs_cdt = 0;
1324 	cmd->ie_min_len = 64;
1325 	cmd->ie_junk = 0xff;
1326 }
1327 
1328 /*
1329  * This routine inits the ie.
1330  * This includes executing the CONFIGURE, IA-SETUP, and MC-SETUP commands,
1331  * starting the receiver unit, and clearing interrupts.
1332  *
1333  * THIS ROUTINE MUST BE CALLED AT splnet() OR HIGHER.
1334  */
1335 static int
1336 ieinit(struct ie_softc *sc)
1337 {
1338 	volatile struct ie_sys_ctl_block *scb = sc->scb;
1339 	void *ptr;
1340 	struct ifnet *ifp;
1341 
1342 	ifp = &sc->sc_if;
1343 	ptr = sc->buf_area;	/* XXX - Use scb instead? */
1344 
1345 	/*
1346 	 * Send the configure command first.
1347 	 */
1348 	{
1349 		struct ie_config_cmd *cmd = ptr;	/* XXX - Was volatile */
1350 
1351 		scb->ie_command_list = vtop16sw(sc, cmd);
1352 		cmd->com.ie_cmd_status = SWAP(0);
1353 		cmd->com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
1354 		cmd->com.ie_cmd_link = SWAP(0xffff);
1355 
1356 		ie_setup_config(cmd, (sc->promisc != 0), 0);
1357 
1358 		if (cmd_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
1359 		    (cmd->com.ie_cmd_status & IE_STAT_OK) == 0) {
1360 			printf("%s: configure command failed\n",
1361 			    device_xname(sc->sc_dev));
1362 			return 0;
1363 		}
1364 	}
1365 
1366 	/*
1367 	 * Now send the Individual Address Setup command.
1368 	 */
1369 	{
1370 		struct ie_iasetup_cmd *cmd = ptr;	/* XXX - Was volatile */
1371 
1372 		scb->ie_command_list = vtop16sw(sc, cmd);
1373 		cmd->com.ie_cmd_status = SWAP(0);
1374 		cmd->com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
1375 		cmd->com.ie_cmd_link = SWAP(0xffff);
1376 
1377 		(sc->sc_memcpy)((void *)&cmd->ie_address,
1378 		    CLLADDR(ifp->if_sadl), sizeof(cmd->ie_address));
1379 
1380 		if (cmd_and_wait(sc, IE_CU_START, cmd, IE_STAT_COMPL) ||
1381 		    (cmd->com.ie_cmd_status & IE_STAT_OK) == 0) {
1382 			printf("%s: individual address setup command failed\n",
1383 			    device_xname(sc->sc_dev));
1384 			return 0;
1385 		}
1386 	}
1387 
1388 	/*
1389 	 * Now run the time-domain reflectometer.
1390 	 */
1391 	if (ie_run_tdr)
1392 		run_tdr(sc, ptr);
1393 
1394 	/*
1395 	 * Acknowledge any interrupts we have generated thus far.
1396 	 */
1397 	ie_ack(sc, IE_ST_WHENCE);
1398 
1399 	/*
1400 	 * Set up the transmit and recv buffers.
1401 	 */
1402 	iememinit(sc);
1403 
1404 	/* tell higher levels that we are here */
1405 	ifp->if_flags |= IFF_RUNNING;
1406 	ifp->if_flags &= ~IFF_OACTIVE;
1407 
1408 	sc->scb->ie_recv_list =
1409 	    vtop16sw(sc, __UNVOLATILE(sc->rframes[0]));
1410 	cmd_and_wait(sc, IE_RU_START, 0, 0);
1411 
1412 	ie_ack(sc, IE_ST_WHENCE);
1413 
1414 	if (sc->run_586)
1415 		(sc->run_586)(sc);
1416 
1417 	return 0;
1418 }
1419 
1420 static void
1421 iestop(struct ie_softc *sc)
1422 {
1423 
1424 	cmd_and_wait(sc, IE_RU_DISABLE, 0, 0);
1425 }
1426 
1427 static int
1428 ieioctl(struct ifnet *ifp, u_long cmd, void *data)
1429 {
1430 	struct ie_softc *sc = ifp->if_softc;
1431 	struct ifaddr *ifa = (struct ifaddr *)data;
1432 	int s, error = 0;
1433 
1434 	s = splnet();
1435 
1436 	switch (cmd) {
1437 
1438 	case SIOCINITIFADDR:
1439 		ifp->if_flags |= IFF_UP;
1440 
1441 		switch (ifa->ifa_addr->sa_family) {
1442 #ifdef INET
1443 		case AF_INET:
1444 			ieinit(sc);
1445 			arp_ifinit(ifp, ifa);
1446 			break;
1447 #endif
1448 		default:
1449 			ieinit(sc);
1450 			break;
1451 		}
1452 		break;
1453 
1454 	case SIOCSIFFLAGS:
1455 		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
1456 			break;
1457 		sc->promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
1458 
1459 		switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
1460 		case IFF_RUNNING:
1461 			/*
1462 			 * If interface is marked down and it is running, then
1463 			 * stop it.
1464 			 */
1465 			iestop(sc);
1466 			ifp->if_flags &= ~IFF_RUNNING;
1467 			break;
1468 		case IFF_UP:
1469 			/*
1470 			 * If interface is marked up and it is stopped, then
1471 			 * start it.
1472 			 */
1473 			ieinit(sc);
1474 			break;
1475 		default:
1476 			/*
1477 			 * Reset the interface to pick up changes in any other
1478 			 * flags that affect hardware registers.
1479 			 */
1480 			iestop(sc);
1481 			ieinit(sc);
1482 			break;
1483 		}
1484 #ifdef IEDEBUG
1485 		if (ifp->if_flags & IFF_DEBUG)
1486 			sc->sc_debug = IED_ALL;
1487 		else
1488 			sc->sc_debug = ie_debug_flags;
1489 #endif
1490 		break;
1491 
1492 	case SIOCADDMULTI:
1493 	case SIOCDELMULTI:
1494 		if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
1495 			/*
1496 			 * Multicast list has changed; set the hardware filter
1497 			 * accordingly.
1498 			 */
1499 			if (ifp->if_flags & IFF_RUNNING)
1500 				mc_reset(sc);
1501 			error = 0;
1502 		}
1503 		break;
1504 
1505 	default:
1506 		error = ether_ioctl(ifp, cmd, data);
1507 		break;
1508 	}
1509 	splx(s);
1510 	return error;
1511 }
1512 
1513 static void
1514 mc_reset(struct ie_softc *sc)
1515 {
1516 	struct ether_multi *enm;
1517 	struct ether_multistep step;
1518 	struct ifnet *ifp;
1519 
1520 	ifp = &sc->sc_if;
1521 
1522 	/*
1523 	 * Step through the list of addresses.
1524 	 */
1525 	sc->mcast_count = 0;
1526 	ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm);
1527 	while (enm) {
1528 		if (sc->mcast_count >= MAXMCAST ||
1529 		    ether_cmp(enm->enm_addrlo, enm->enm_addrhi) != 0) {
1530 			ifp->if_flags |= IFF_ALLMULTI;
1531 			ieioctl(ifp, SIOCSIFFLAGS, NULL);
1532 			goto setflag;
1533 		}
1534 		memcpy(&sc->mcast_addrs[sc->mcast_count], enm->enm_addrlo,
1535 		    ETHER_ADDR_LEN);
1536 		sc->mcast_count++;
1537 		ETHER_NEXT_MULTI(step, enm);
1538 	}
1539 setflag:
1540 	sc->want_mcsetup = 1;
1541 }
1542 
1543 #ifdef IEDEBUG
1544 void
1545 print_rbd(volatile struct ie_recv_buf_desc *rbd)
1546 {
1547 
1548 	printf("RBD at %08lx:\nactual %04x, next %04x, buffer %08x\n"
1549 	    "length %04x, mbz %04x\n", (u_long)rbd, rbd->ie_rbd_actual,
1550 	    rbd->ie_rbd_next, rbd->ie_rbd_buffer, rbd->ie_rbd_length,
1551 	    rbd->mbz);
1552 }
1553 #endif
1554