xref: /netbsd-src/sys/arch/sun2/dev/if_ec.c (revision 001c68bd94f75ce9270b69227c4199fbf34ee396)
1 /*	$NetBSD: if_ec.c,v 1.7 2003/01/20 15:03:03 bouyer Exp $	*/
2 
3 /*
4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Matthew Fredette.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * 3Com 3C400 device driver
41  */
42 
43 #include "opt_inet.h"
44 #include "opt_ns.h"
45 #include "bpfilter.h"
46 #include "rnd.h"
47 
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/errno.h>
51 #include <sys/ioctl.h>
52 #include <sys/mbuf.h>
53 #include <sys/socket.h>
54 #include <sys/syslog.h>
55 #include <sys/device.h>
56 #include <sys/endian.h>
57 #if NRND > 0
58 #include <sys/rnd.h>
59 #endif
60 
61 #include <net/if.h>
62 #include <net/if_dl.h>
63 #include <net/if_types.h>
64 
65 #include <net/if_ether.h>
66 #include <net/if_media.h>
67 
68 #ifdef INET
69 #include <netinet/in.h>
70 #include <netinet/in_systm.h>
71 #include <netinet/in_var.h>
72 #include <netinet/ip.h>
73 #include <netinet/if_inarp.h>
74 #endif
75 
76 #ifdef NS
77 #include <netns/ns.h>
78 #include <netns/ns_if.h>
79 #endif
80 
81 #if NBPFILTER > 0
82 #include <net/bpf.h>
83 #include <net/bpfdesc.h>
84 #endif
85 
86 #include <machine/cpu.h>
87 #include <machine/autoconf.h>
88 #include <machine/idprom.h>
89 #include <machine/bus.h>
90 #include <machine/intr.h>
91 
92 #include <sun2/dev/if_ecreg.h>
93 
94 /*
95  * Interface softc.
96  */
97 struct ec_softc {
98 	struct device sc_dev;
99 	void *sc_ih;
100 
101 	struct ethercom sc_ethercom;	/* ethernet common */
102 	struct ifmedia sc_media;	/* our supported media */
103 
104 	bus_space_tag_t sc_iot;	/* bus space tag */
105 	bus_space_handle_t sc_ioh;	/* bus space handle */
106 
107 	u_char sc_jammed;	/* nonzero if the net is jammed */
108 	u_char sc_colliding;	/* nonzero if the net is colliding */
109 	u_int32_t sc_backoff_seed;	/* seed for the backoff PRNG */
110 
111 #if NRND > 0
112 	rndsource_element_t rnd_source;
113 #endif
114 };
115 
116 /* Macros to read and write the CSR. */
117 #define	ECREG_CSR_RD bus_space_read_2(sc->sc_iot, sc->sc_ioh, ECREG_CSR)
118 #define	ECREG_CSR_WR(val) bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECREG_CSR, val)
119 
120 /* After this many collisions, the packet is dropped. */
121 #define	EC_COLLISIONS_JAMMED		16
122 
123 /*
124  * Various constants used in the backoff pseudorandom
125  * number generator.
126  */
127 #define	EC_BACKOFF_PRNG_COLL_MAX	10
128 #define	EC_BACKOFF_PRNG_MUL		1103515245
129 #define	EC_BACKOFF_PRNG_ADD		12345
130 #define	EC_BACKOFF_PRNG_MASK		0x7fffffff
131 
132 /*
133  * Prototypes
134  */
135 int ec_intr __P((void *));
136 void ec_reset __P((struct ifnet *));
137 int ec_init __P((struct ifnet *));
138 int ec_ioctl __P((struct ifnet *, u_long, caddr_t));
139 void ec_watchdog __P((struct ifnet *));
140 void ec_start __P((struct ifnet *));
141 
142 void ec_recv __P((struct ec_softc *, int));
143 void ec_coll __P((struct ec_softc *));
144 void ec_copyin __P((struct ec_softc *, void *, int, size_t));
145 void ec_copyout __P((struct ec_softc *, const void *, int, size_t));
146 
147 int ec_mediachange __P((struct ifnet *));
148 void ec_mediastatus __P((struct ifnet *, struct ifmediareq *));
149 
150 int ec_match __P((struct device *, struct cfdata *, void *));
151 void ec_attach __P((struct device *, struct device *, void *));
152 
153 CFATTACH_DECL(ec, sizeof(struct ec_softc),
154     ec_match, ec_attach, NULL, NULL);
155 
156 /*
157  * Copy board memory to kernel.
158  */
159 void
160 ec_copyin(sc, p, offset, size)
161 	struct ec_softc *sc;
162 	void *p;
163 	int offset;
164 	size_t size;
165 {
166 	bus_space_copyin(sc->sc_iot, sc->sc_ioh, offset, p, size);
167 }
168 
169 /*
170  * Copy from kernel space to board memory.
171  */
172 void
173 ec_copyout(sc, p, offset, size)
174 	struct ec_softc *sc;
175 	const void *p;
176 	int offset;
177 	size_t size;
178 {
179 	bus_space_copyout(sc->sc_iot, sc->sc_ioh, offset, p, size);
180 }
181 
182 int
183 ec_match(parent, match, aux)
184 	struct device *parent;
185 	struct cfdata *match;
186 	void *aux;
187 {
188 	struct mbmem_attach_args *mbma = aux;
189 	bus_space_handle_t bh;
190 	int matched;
191 
192 	/* No default Multibus address. */
193 	if (mbma->mbma_paddr == -1)
194 		return (0);
195 
196 	/* Make sure there is something there... */
197 	if (bus_space_map(mbma->mbma_bustag, mbma->mbma_paddr, ECREG_BANK_SZ,
198 			  0, &bh))
199 		return (0);
200 	matched = (bus_space_peek_2(mbma->mbma_bustag, bh, 0, NULL) == 0);
201 	bus_space_unmap(mbma->mbma_bustag, bh, ECREG_BANK_SZ);
202 	if (!matched)
203 		return (0);
204 
205 	/* Default interrupt priority. */
206 	if (mbma->mbma_pri == -1)
207 		mbma->mbma_pri = 3;
208 
209 	return (1);
210 }
211 
212 void
213 ec_attach(parent, self, aux)
214 	struct device *parent, *self;
215 	void *aux;
216 {
217 	struct ec_softc *sc = (void *) self;
218 	struct mbmem_attach_args *mbma = aux;
219 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
220 	u_int8_t myaddr[ETHER_ADDR_LEN];
221 
222 	printf("\n");
223 
224 	/* Map in the board control regs. */
225 	sc->sc_iot = mbma->mbma_bustag;
226 	if (bus_space_map(mbma->mbma_bustag, mbma->mbma_paddr, ECREG_BANK_SZ,
227 		0, &sc->sc_ioh))
228 		panic("ec_attach: can't map regs");
229 
230 	/* Reset the board. */
231 	ECREG_CSR_WR(EC_CSR_RESET);
232 	delay(160);
233 
234 	/*
235 	 * Copy out the board ROM Ethernet address,
236 	 * and use the non-vendor-ID part to seed
237 	 * our backoff pseudorandom number generator.
238 	 */
239 	bus_space_read_region_1(sc->sc_iot, sc->sc_ioh, ECREG_AROM, myaddr, ETHER_ADDR_LEN);
240 	sc->sc_backoff_seed = (myaddr[3] << 16) | (myaddr[4] << 8) | (myaddr[5]) | 1;
241 
242 	/* Initialize ifnet structure. */
243 	bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
244 	ifp->if_softc = sc;
245 	ifp->if_start = ec_start;
246 	ifp->if_ioctl = ec_ioctl;
247 	ifp->if_init = ec_init;
248 	ifp->if_watchdog = ec_watchdog;
249 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
250 	IFQ_SET_READY(&ifp->if_snd);
251 
252         /* Initialize ifmedia structures. */
253 	ifmedia_init(&sc->sc_media, 0, ec_mediachange, ec_mediastatus);
254 	ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
255 	ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
256 
257 	/* Now we can attach the interface. */
258 	if_attach(ifp);
259 	idprom_etheraddr(myaddr);
260 	ether_ifattach(ifp, myaddr);
261 	printf("%s: address %s\n", self->dv_xname, ether_sprintf(myaddr));
262 
263 	bus_intr_establish(mbma->mbma_bustag, mbma->mbma_pri, IPL_NET, 0,
264 	    ec_intr, sc);
265 
266 #if NRND > 0
267 	rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
268 	    RND_TYPE_NET, 0);
269 #endif
270 }
271 
272 /*
273  * Reset interface.
274  */
275 void
276 ec_reset(ifp)
277         struct ifnet *ifp;
278 {
279         int s;
280 
281         s = splnet();
282         ec_init(ifp);
283         splx(s);
284 }
285 
286 
287 /*
288  * Initialize interface.
289  */
290 int
291 ec_init(ifp)
292 	struct ifnet *ifp;
293 {
294 	struct ec_softc *sc = ifp->if_softc;
295 
296 	/* Reset the board. */
297 	ECREG_CSR_WR(EC_CSR_RESET);
298 	delay(160);
299 
300 	/* Set the Ethernet address. */
301 	bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, ECREG_ARAM, LLADDR(sc->sc_ethercom.ec_if.if_sadl), ETHER_ADDR_LEN);
302 	ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | EC_CSR_AMSW);
303 	ECREG_CSR_WR(ECREG_CSR_RD & 0);
304 
305 	/* Enable interrupts. */
306 	ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | EC_CSR_BBSW | EC_CSR_ABSW | EC_CSR_BINT | EC_CSR_AINT | (ifp->if_flags & IFF_PROMISC ? EC_CSR_PROMISC : EC_CSR_PA));
307 
308 	/* Set flags appropriately. */
309 	ifp->if_flags |= IFF_RUNNING;
310 	ifp->if_flags &= ~IFF_OACTIVE;
311 
312 	/* Start output. */
313 	ec_start(ifp);
314 
315 	return (0);
316 }
317 
318 /*
319  * Start output on interface.
320  */
321 void
322 ec_start(ifp)
323 	struct ifnet *ifp;
324 {
325 	struct ec_softc *sc = ifp->if_softc;
326 	struct mbuf *m, *m0;
327 	int s;
328 	u_int count, realcount;
329 	bus_size_t off;
330 
331 	s = splnet();
332 
333 	/* Don't do anything if output is active. */
334 	if ((ifp->if_flags & IFF_OACTIVE) != 0) {
335 		splx(s);
336 		return;
337 	}
338 	/* Don't do anything if the output queue is empty. */
339 	IFQ_DEQUEUE(&ifp->if_snd, m0);
340 	if (m0 == NULL) {
341 		splx(s);
342 		return;
343 	}
344 
345 #if NBPFILTER > 0
346 	/* The BPF tap. */
347 	if (ifp->if_bpf)
348 		bpf_mtap(ifp->if_bpf, m0);
349 #endif
350 
351 	/* Size the packet. */
352 	for (count = EC_BUF_SZ, m = m0; m != NULL; m = m->m_next)
353 		count -= m->m_len;
354 
355 	/* Copy the packet into the xmit buffer. */
356 	realcount = MIN(count, EC_PKT_MAXTDOFF);
357 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECREG_TBUF, realcount);
358 	for (off = realcount, m = m0; m != 0; off += m->m_len, m = m->m_next)
359 		ec_copyout(sc, mtod(m, u_int8_t *), ECREG_TBUF + off, m->m_len);
360 	m_freem(m0);
361 #if 0
362 	bus_space_set_region_1(sc->sc_iot, sc->sc_ioh, ECREG_TBUF + off, 0,
363 	    count - realcount);
364 #endif
365 	w16zero((u_int8_t *)(ECREG_TBUF + off), count - realcount);
366 
367 	/* Enable the transmitter. */
368 	ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_PA) | EC_CSR_TBSW | EC_CSR_TINT | EC_CSR_JINT);
369 	ifp->if_flags |= IFF_OACTIVE;
370 
371 	/* Done. */
372 	splx(s);
373 }
374 
375 /*
376  * Controller interrupt.
377  */
378 int
379 ec_intr(arg)
380 	void *arg;
381 {
382 	struct ec_softc *sc = arg;
383 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
384 	int recv_first;
385 	int recv_second;
386 	int retval;
387 	struct mbuf *m0;
388 
389 	retval = 0;
390 
391 	/* Check for received packet(s). */
392 	recv_first = recv_second = 0;
393 	switch (ECREG_CSR_RD & (EC_CSR_BBSW | EC_CSR_ABSW | EC_CSR_RBBA)) {
394 
395 	case (EC_CSR_BBSW | EC_CSR_ABSW):
396 	case (EC_CSR_BBSW | EC_CSR_ABSW | EC_CSR_RBBA):
397 		/* Neither buffer is full.  Is this a transmit interrupt?
398 		 * Acknowledge the interrupt ourselves. */
399 		ECREG_CSR_WR(ECREG_CSR_RD & (EC_CSR_TINT | EC_CSR_JINT | EC_CSR_PAMASK));
400 		ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | EC_CSR_BINT | EC_CSR_AINT);
401 		break;
402 
403 	case EC_CSR_BBSW:
404 	case (EC_CSR_BBSW | EC_CSR_RBBA):
405 		/* Only the A buffer is full. */
406 		recv_first = EC_CSR_AINT;
407 		break;
408 
409 	case EC_CSR_ABSW:
410 	case (EC_CSR_ABSW | EC_CSR_RBBA):
411 		/* Only the B buffer is full. */
412 		recv_first = EC_CSR_BINT;
413 		break;
414 
415 	case 0:
416 		/* Both the A buffer and the B buffer are full, and the A
417 		 * buffer is older than the B buffer. */
418 		recv_first = EC_CSR_AINT;
419 		recv_second = EC_CSR_BINT;
420 		break;
421 
422 	case EC_CSR_RBBA:
423 		/* Both the A buffer and the B buffer are full, and the B
424 		 * buffer is older than the A buffer. */
425 		recv_first = EC_CSR_BINT;
426 		recv_second = EC_CSR_AINT;
427 		break;
428 	}
429 
430 	/* Receive packets. */
431 	if (recv_first) {
432 
433 		/* Acknowledge the interrupt. */
434 		ECREG_CSR_WR(ECREG_CSR_RD & ((EC_CSR_BINT | EC_CSR_AINT | EC_CSR_TINT | EC_CSR_JINT | EC_CSR_PAMASK) ^ (recv_first | recv_second)));
435 
436 		/* Receive a packet. */
437 		ec_recv(sc, recv_first);
438 
439 		/* Receive a packet. */
440 		if (recv_second)
441 			ec_recv(sc, recv_second);
442 
443 		retval++;
444 	}
445 	/* Check for a transmitted packet. */
446 	if (ifp->if_flags & IFF_OACTIVE) {
447 
448 		/* If we got a collision. */
449 		if (ECREG_CSR_RD & EC_CSR_JAM) {
450 			ECREG_CSR_WR(ECREG_CSR_RD & (EC_CSR_BINT | EC_CSR_AINT | EC_CSR_PAMASK));
451 			sc->sc_ethercom.ec_if.if_collisions++;
452 			retval++;
453 			ec_coll(sc);
454 
455 		}
456 		/* If we transmitted a packet. */
457 		else if ((ECREG_CSR_RD & EC_CSR_TBSW) == 0) {
458 			ECREG_CSR_WR(ECREG_CSR_RD & (EC_CSR_BINT | EC_CSR_AINT | EC_CSR_PAMASK));
459 			retval++;
460 			sc->sc_ethercom.ec_if.if_opackets++;
461 			sc->sc_jammed = 0;
462 			ifp->if_flags &= ~IFF_OACTIVE;
463 			IFQ_POLL(&ifp->if_snd, m0);
464 			if (m0 != NULL)
465 				ec_start(ifp);
466 		}
467 	} else {
468 
469 		/* Make sure we disable transmitter interrupts. */
470 		ECREG_CSR_WR(ECREG_CSR_RD & (EC_CSR_BINT | EC_CSR_AINT | EC_CSR_PAMASK));
471 	}
472 
473 	return retval;
474 }
475 
476 /*
477  * Read in a packet from the board.
478  */
479 void
480 ec_recv(sc, intbit)
481 	struct ec_softc *sc;
482 	int intbit;
483 {
484 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
485 	struct mbuf *m0, *m, *newm;
486 	bus_size_t buf;
487 	u_int16_t status;
488 	u_int16_t doff;
489 	int length, total_length;
490 
491 	buf = EC_CSR_INT_BUF(intbit);
492 
493 	/* Read in the packet status. */
494 	status = bus_space_read_2(sc->sc_iot, sc->sc_ioh, buf);
495 	doff = status & EC_PKT_DOFF;
496 
497 	for (total_length = -1, m0 = 0;;) {
498 
499 		/* Check for an error. */
500 		if (status & (EC_PKT_FCSERR | EC_PKT_RGERR | EC_PKT_FRERR) ||
501 		    doff < EC_PKT_MINRDOFF ||
502 		    doff > EC_PKT_MAXRDOFF) {
503 			printf("%s: garbled packet, status 0x%04x; dropping\n",
504 			    sc->sc_dev.dv_xname, (unsigned int) status);
505 			break;
506 		}
507 
508 		/* Adjust for the header. */
509 		total_length = doff - EC_PKT_RDOFF;
510 		buf += EC_PKT_RDOFF;
511 
512 		/* XXX - sometimes the card reports a large data offset. */
513 		if (total_length > (ETHER_MAX_LEN - ETHER_CRC_LEN)) {
514 #ifdef DEBUG
515 			printf("%s: fixing too-large length of %d\n",
516 			    sc->sc_dev.dv_xname, total_length);
517 #endif
518 			total_length = (ETHER_MAX_LEN - ETHER_CRC_LEN);
519 		}
520 
521 		MGETHDR(m0, M_DONTWAIT, MT_DATA);
522 		if (m0 == 0)
523 			break;
524 		m0->m_pkthdr.rcvif = ifp;
525 		m0->m_pkthdr.len = total_length;
526 		length = MHLEN;
527 		m = m0;
528 
529 		while (total_length > 0) {
530 			if (total_length >= MINCLSIZE) {
531 				MCLGET(m, M_DONTWAIT);
532 				if ((m->m_flags & M_EXT) == 0)
533 					break;
534 				length = MCLBYTES;
535 			}
536 			m->m_len = length = min(total_length, length);
537 			ec_copyin(sc, mtod(m, u_int8_t *), buf, length);
538 			total_length -= length;
539 			buf += length;
540 
541 			if (total_length > 0) {
542 				MGET(newm, M_DONTWAIT, MT_DATA);
543 				if (newm == 0)
544 					break;
545 				length = MLEN;
546 				m = m->m_next = newm;
547 			}
548 		}
549 		break;
550 	}
551 
552 	if (total_length == 0) {
553 		ifp->if_ipackets++;
554 
555 #if NBPFILTER > 0
556 		/*
557 	 	* Check if there's a BPF listener on this interface.
558 	 	* If so, hand off the raw packet to BPF.
559 	 	*/
560 		if (ifp->if_bpf)
561 			bpf_mtap(ifp->if_bpf, m0);
562 #endif
563 
564 		/* Pass the packet up. */
565 		(*ifp->if_input) (ifp, m0);
566 
567 	} else {
568 		/* Something went wrong. */
569 		if (m0)
570 			m_freem(m0);
571 		ifp->if_ierrors++;
572 	}
573 
574 	/* Give the receive buffer back to the card. */
575 	buf = EC_CSR_INT_BUF(intbit);
576 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, buf, 0);
577 	ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | EC_CSR_INT_BSW(intbit) | intbit);
578 }
579 
580 int
581 ec_mediachange(ifp)
582 	struct ifnet *ifp;
583 {
584 	return (0);
585 }
586 
587 void
588 ec_mediastatus(ifp, ifmr)
589 	struct ifnet *ifp;
590 	struct ifmediareq *ifmr;
591 {
592 	if ((ifp->if_flags & IFF_UP) == 0)
593 		return;
594 
595 	ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE;
596 }
597 
598 /*
599  * Process an ioctl request. This code needs some work - it looks pretty ugly.
600  */
601 int
602 ec_ioctl(ifp, cmd, data)
603 	struct ifnet *ifp;
604 	u_long cmd;
605 	caddr_t data;
606 {
607 	struct ifaddr *ifa = (struct ifaddr *) data;
608 	struct ifreq *ifr = (struct ifreq *)data;
609 	struct ec_softc *sc = ifp->if_softc;
610 	int s, error = 0;
611 
612 	s = splnet();
613 
614 	switch (cmd) {
615 
616 	case SIOCSIFADDR:
617 		ifp->if_flags |= IFF_UP;
618 
619 		switch (ifa->ifa_addr->sa_family) {
620 #ifdef INET
621 		case AF_INET:
622 			ec_init(ifp);
623 			arp_ifinit(ifp, ifa);
624 			break;
625 #endif
626 #ifdef NS
627 			/* XXX - This code is probably wrong. */
628 		case AF_NS:
629 			{
630 				struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
631 
632 				if (ns_nullhost(*ina))
633 					ina->x_host =
634 					    *(union ns_host *) LLADDR(ifp->if_sadl);
635 				else
636 					bcopy(ina->x_host.c_host, LLADDR(ifp->if_sadl),
637 					    ETHER_ADDR_LEN);
638 				/* Set new address. */
639 				ec_init(ifp);
640 				break;
641 			}
642 #endif
643 		default:
644 			ec_init(ifp);
645 			break;
646 		}
647 		break;
648 
649 	case SIOCSIFFLAGS:
650 		if ((ifp->if_flags & IFF_UP) == 0 &&
651 		    (ifp->if_flags & IFF_RUNNING) != 0) {
652 			/*
653 			 * If interface is marked down and it is running, then
654 			 * stop it.
655 			 */
656 			ifp->if_flags &= ~IFF_RUNNING;
657 		} else if ((ifp->if_flags & IFF_UP) != 0 &&
658 		    (ifp->if_flags & IFF_RUNNING) == 0) {
659 			/*
660 			 * If interface is marked up and it is stopped, then
661 			 * start it.
662 			 */
663 			ec_init(ifp);
664 		} else {
665 			/*
666 			 * Some other important flag might have changed, so
667 			 * reset.
668 			 */
669 			ec_reset(ifp);
670 		}
671 		break;
672 
673 	case SIOCGIFMEDIA:
674 	case SIOCSIFMEDIA:
675 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
676 		break;
677 
678 	default:
679 		error = EINVAL;
680 		break;
681 	}
682 
683 	splx(s);
684 	return error;
685 }
686 
687 /*
688  * Collision routine.
689  */
690 void
691 ec_coll(sc)
692 	struct ec_softc *sc;
693 {
694 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
695 	u_short jams;
696 	struct mbuf *m0;
697 
698 	if ((++sc->sc_colliding) >= EC_COLLISIONS_JAMMED) {
699 		sc->sc_ethercom.ec_if.if_oerrors++;
700 		if (!sc->sc_jammed)
701 			printf("%s: ethernet jammed\n",
702 			    sc->sc_dev.dv_xname);
703 		sc->sc_jammed = 1;
704 		sc->sc_colliding = 0;
705 		ifp->if_flags &= ~IFF_OACTIVE;
706 		IFQ_POLL(&ifp->if_snd, m0);
707 		if (m0 != NULL)
708 			ec_start(ifp);
709 	} else {
710 		jams = MAX(sc->sc_colliding, EC_BACKOFF_PRNG_COLL_MAX);
711 		sc->sc_backoff_seed = ((sc->sc_backoff_seed * EC_BACKOFF_PRNG_MUL) + EC_BACKOFF_PRNG_ADD) & EC_BACKOFF_PRNG_MASK;
712 		bus_space_write_2(sc->sc_iot, sc->sc_ioh, ECREG_BACKOFF, -(((sc->sc_backoff_seed >> 8) & ~(-1 << jams)) + 1));
713 		ECREG_CSR_WR((ECREG_CSR_RD & EC_CSR_INTPA) | EC_CSR_JAM | EC_CSR_TINT | EC_CSR_JINT);
714 	}
715 }
716 
717 /*
718  * Device timeout routine.
719  */
720 void
721 ec_watchdog(ifp)
722 	struct ifnet *ifp;
723 {
724 	struct ec_softc *sc = ifp->if_softc;
725 
726 	log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
727 	sc->sc_ethercom.ec_if.if_oerrors++;
728 
729 	ec_reset(ifp);
730 }
731