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