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