if_el.c revision 1.73.8.1 1 /* $NetBSD: if_el.c,v 1.73.8.1 2006/09/14 12:31:32 yamt Exp $ */
2
3 /*
4 * Copyright (c) 1994, Matthew E. Kimmel. Permission is hereby granted
5 * to use, copy, modify and distribute this software provided that both
6 * the copyright notice and this permission notice appear in all copies
7 * of the software, derivative works or modified versions, and any
8 * portions thereof.
9 */
10
11 /*
12 * 3COM Etherlink 3C501 device driver
13 */
14
15 /*
16 * Bugs/possible improvements:
17 * - Does not currently support DMA
18 * - Does not currently support multicasts
19 */
20
21 #include <sys/cdefs.h>
22 __KERNEL_RCSID(0, "$NetBSD: if_el.c,v 1.73.8.1 2006/09/14 12:31:32 yamt Exp $");
23
24 #include "opt_inet.h"
25 #include "bpfilter.h"
26 #include "rnd.h"
27
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/errno.h>
31 #include <sys/ioctl.h>
32 #include <sys/mbuf.h>
33 #include <sys/socket.h>
34 #include <sys/syslog.h>
35 #include <sys/device.h>
36 #if NRND > 0
37 #include <sys/rnd.h>
38 #endif
39
40 #include <net/if.h>
41 #include <net/if_dl.h>
42 #include <net/if_types.h>
43
44 #include <net/if_ether.h>
45
46 #ifdef INET
47 #include <netinet/in.h>
48 #include <netinet/in_systm.h>
49 #include <netinet/in_var.h>
50 #include <netinet/ip.h>
51 #include <netinet/if_inarp.h>
52 #endif
53
54
55 #if NBPFILTER > 0
56 #include <net/bpf.h>
57 #include <net/bpfdesc.h>
58 #endif
59
60 #include <machine/cpu.h>
61 #include <machine/intr.h>
62 #include <machine/bus.h>
63
64 #include <dev/isa/isavar.h>
65 #include <dev/isa/if_elreg.h>
66
67 /* for debugging convenience */
68 #ifdef EL_DEBUG
69 #define DPRINTF(x) printf x
70 #else
71 #define DPRINTF(x)
72 #endif
73
74 /*
75 * per-line info and status
76 */
77 struct el_softc {
78 struct device sc_dev;
79 void *sc_ih;
80
81 struct ethercom sc_ethercom; /* ethernet common */
82 bus_space_tag_t sc_iot; /* bus space identifier */
83 bus_space_handle_t sc_ioh; /* i/o handle */
84
85 #if NRND > 0
86 rndsource_element_t rnd_source;
87 #endif
88 };
89
90 /*
91 * prototypes
92 */
93 int elintr(void *);
94 void elinit(struct el_softc *);
95 int elioctl(struct ifnet *, u_long, caddr_t);
96 void elstart(struct ifnet *);
97 void elwatchdog(struct ifnet *);
98 void elreset(struct el_softc *);
99 void elstop(struct el_softc *);
100 static int el_xmit(struct el_softc *);
101 void elread(struct el_softc *, int);
102 struct mbuf *elget(struct el_softc *sc, int);
103 static inline void el_hardreset(struct el_softc *);
104
105 int elprobe(struct device *, struct cfdata *, void *);
106 void elattach(struct device *, struct device *, void *);
107
108 CFATTACH_DECL(el, sizeof(struct el_softc),
109 elprobe, elattach, NULL, NULL);
110
111 /*
112 * Probe routine.
113 *
114 * See if the card is there and at the right place.
115 * (XXX - cgd -- needs help)
116 */
117 int
118 elprobe(parent, match, aux)
119 struct device *parent;
120 struct cfdata *match;
121 void *aux;
122 {
123 struct isa_attach_args *ia = aux;
124 bus_space_tag_t iot = ia->ia_iot;
125 bus_space_handle_t ioh;
126 int iobase;
127 u_int8_t station_addr[ETHER_ADDR_LEN];
128 u_int8_t i;
129 int rval;
130
131 rval = 0;
132
133 if (ia->ia_nio < 1)
134 return (0);
135 if (ia->ia_nirq < 1)
136 return (0);
137
138 if (ISA_DIRECT_CONFIG(ia))
139 return (0);
140
141 iobase = ia->ia_io[0].ir_addr;
142
143 if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
144 return (0);
145 if (ia->ia_irq[0].ir_irq == ISA_UNKNOWN_IRQ)
146 return (0);
147
148 /* First check the base. */
149 if (iobase < 0x200 || iobase > 0x3f0)
150 return 0;
151
152 /* Map i/o space. */
153 if (bus_space_map(iot, iobase, 16, 0, &ioh))
154 return 0;
155
156 /*
157 * Now attempt to grab the station address from the PROM and see if it
158 * contains the 3com vendor code.
159 */
160 DPRINTF(("Probing 3c501 at 0x%x...\n", iobase));
161
162 /* Reset the board. */
163 DPRINTF(("Resetting board...\n"));
164 bus_space_write_1(iot, ioh, EL_AC, EL_AC_RESET);
165 delay(5);
166 bus_space_write_1(iot, ioh, EL_AC, 0);
167
168 /* Now read the address. */
169 DPRINTF(("Reading station address...\n"));
170 for (i = 0; i < ETHER_ADDR_LEN; i++) {
171 bus_space_write_1(iot, ioh, EL_GPBL, i);
172 station_addr[i] = bus_space_read_1(iot, ioh, EL_EAW);
173 }
174 DPRINTF(("Address is %s\n", ether_sprintf(station_addr)));
175
176 /*
177 * If the vendor code is ok, return a 1. We'll assume that whoever
178 * configured this system is right about the IRQ.
179 */
180 if (station_addr[0] != 0x02 || station_addr[1] != 0x60 ||
181 station_addr[2] != 0x8c) {
182 DPRINTF(("Bad vendor code.\n"));
183 goto out;
184 }
185 DPRINTF(("Vendor code ok.\n"));
186
187 ia->ia_nio = 1;
188 ia->ia_io[0].ir_size = 16;
189
190 ia->ia_nirq = 1;
191
192 ia->ia_niomem = 0;
193 ia->ia_ndrq = 0;
194
195 rval = 1;
196
197 out:
198 bus_space_unmap(iot, ioh, 16);
199 return rval;
200 }
201
202 /*
203 * Attach the interface to the kernel data structures. By the time this is
204 * called, we know that the card exists at the given I/O address. We still
205 * assume that the IRQ given is correct.
206 */
207 void
208 elattach(parent, self, aux)
209 struct device *parent, *self;
210 void *aux;
211 {
212 struct el_softc *sc = (void *)self;
213 struct isa_attach_args *ia = aux;
214 bus_space_tag_t iot = ia->ia_iot;
215 bus_space_handle_t ioh;
216 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
217 u_int8_t myaddr[ETHER_ADDR_LEN];
218 u_int8_t i;
219
220 printf("\n");
221
222 DPRINTF(("Attaching %s...\n", sc->sc_dev.dv_xname));
223
224 /* Map i/o space. */
225 if (bus_space_map(iot, ia->ia_io[0].ir_addr, 16, 0, &ioh)) {
226 printf("%s: can't map i/o space\n", self->dv_xname);
227 return;
228 }
229
230 sc->sc_iot = iot;
231 sc->sc_ioh = ioh;
232
233 /* Reset the board. */
234 bus_space_write_1(iot, ioh, EL_AC, EL_AC_RESET);
235 delay(5);
236 bus_space_write_1(iot, ioh, EL_AC, 0);
237
238 /* Now read the address. */
239 for (i = 0; i < ETHER_ADDR_LEN; i++) {
240 bus_space_write_1(iot, ioh, EL_GPBL, i);
241 myaddr[i] = bus_space_read_1(iot, ioh, EL_EAW);
242 }
243
244 /* Stop the board. */
245 elstop(sc);
246
247 /* Initialize ifnet structure. */
248 strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
249 ifp->if_softc = sc;
250 ifp->if_start = elstart;
251 ifp->if_ioctl = elioctl;
252 ifp->if_watchdog = elwatchdog;
253 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
254 IFQ_SET_READY(&ifp->if_snd);
255
256 /* Now we can attach the interface. */
257 DPRINTF(("Attaching interface...\n"));
258 if_attach(ifp);
259 ether_ifattach(ifp, myaddr);
260
261 /* Print out some information for the user. */
262 printf("%s: address %s\n", self->dv_xname, ether_sprintf(myaddr));
263
264 sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
265 IST_EDGE, IPL_NET, elintr, sc);
266
267 #if NRND > 0
268 DPRINTF(("Attaching to random...\n"));
269 rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
270 RND_TYPE_NET, 0);
271 #endif
272
273 DPRINTF(("elattach() finished.\n"));
274 }
275
276 /*
277 * Reset interface.
278 */
279 void
280 elreset(sc)
281 struct el_softc *sc;
282 {
283 int s;
284
285 DPRINTF(("elreset()\n"));
286 s = splnet();
287 elstop(sc);
288 elinit(sc);
289 splx(s);
290 }
291
292 /*
293 * Stop interface.
294 */
295 void
296 elstop(sc)
297 struct el_softc *sc;
298 {
299
300 bus_space_write_1(sc->sc_iot, sc->sc_ioh, EL_AC, 0);
301 }
302
303 /*
304 * Do a hardware reset of the board, and upload the ethernet address again in
305 * case the board forgets.
306 */
307 static inline void
308 el_hardreset(sc)
309 struct el_softc *sc;
310 {
311 bus_space_tag_t iot = sc->sc_iot;
312 bus_space_handle_t ioh = sc->sc_ioh;
313 int i;
314
315 bus_space_write_1(iot, ioh, EL_AC, EL_AC_RESET);
316 delay(5);
317 bus_space_write_1(iot, ioh, EL_AC, 0);
318
319 for (i = 0; i < ETHER_ADDR_LEN; i++)
320 bus_space_write_1(iot, ioh, i,
321 LLADDR(sc->sc_ethercom.ec_if.if_sadl)[i]);
322 }
323
324 /*
325 * Initialize interface.
326 */
327 void
328 elinit(sc)
329 struct el_softc *sc;
330 {
331 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
332 bus_space_tag_t iot = sc->sc_iot;
333 bus_space_handle_t ioh = sc->sc_ioh;
334
335 /* First, reset the board. */
336 el_hardreset(sc);
337
338 /* Configure rx. */
339 DPRINTF(("Configuring rx...\n"));
340 if (ifp->if_flags & IFF_PROMISC)
341 bus_space_write_1(iot, ioh, EL_RXC,
342 EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
343 EL_RXC_DOFLOW | EL_RXC_PROMISC);
344 else
345 bus_space_write_1(iot, ioh, EL_RXC,
346 EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
347 EL_RXC_DOFLOW | EL_RXC_ABROAD);
348 bus_space_write_1(iot, ioh, EL_RBC, 0);
349
350 /* Configure TX. */
351 DPRINTF(("Configuring tx...\n"));
352 bus_space_write_1(iot, ioh, EL_TXC, 0);
353
354 /* Start reception. */
355 DPRINTF(("Starting reception...\n"));
356 bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
357
358 /* Set flags appropriately. */
359 ifp->if_flags |= IFF_RUNNING;
360 ifp->if_flags &= ~IFF_OACTIVE;
361
362 /* And start output. */
363 elstart(ifp);
364 }
365
366 /*
367 * Start output on interface. Get datagrams from the queue and output them,
368 * giving the receiver a chance between datagrams. Call only from splnet or
369 * interrupt level!
370 */
371 void
372 elstart(ifp)
373 struct ifnet *ifp;
374 {
375 struct el_softc *sc = ifp->if_softc;
376 bus_space_tag_t iot = sc->sc_iot;
377 bus_space_handle_t ioh = sc->sc_ioh;
378 struct mbuf *m, *m0;
379 int s, i, off, retries;
380
381 DPRINTF(("elstart()...\n"));
382 s = splnet();
383
384 /* Don't do anything if output is active. */
385 if ((ifp->if_flags & IFF_OACTIVE) != 0) {
386 splx(s);
387 return;
388 }
389
390 ifp->if_flags |= IFF_OACTIVE;
391
392 /*
393 * The main loop. They warned me against endless loops, but would I
394 * listen? NOOO....
395 */
396 for (;;) {
397 /* Dequeue the next datagram. */
398 IFQ_DEQUEUE(&ifp->if_snd, m0);
399
400 /* If there's nothing to send, return. */
401 if (m0 == 0)
402 break;
403
404 #if NBPFILTER > 0
405 /* Give the packet to the bpf, if any. */
406 if (ifp->if_bpf)
407 bpf_mtap(ifp->if_bpf, m0);
408 #endif
409
410 /* Disable the receiver. */
411 bus_space_write_1(iot, ioh, EL_AC, EL_AC_HOST);
412 bus_space_write_1(iot, ioh, EL_RBC, 0);
413
414 /* Transfer datagram to board. */
415 DPRINTF(("el: xfr pkt length=%d...\n", m0->m_pkthdr.len));
416 off = EL_BUFSIZ - max(m0->m_pkthdr.len,
417 ETHER_MIN_LEN - ETHER_CRC_LEN);
418 #ifdef DIAGNOSTIC
419 if ((off & 0xffff) != off)
420 printf("%s: bogus off 0x%x\n",
421 sc->sc_dev.dv_xname, off);
422 #endif
423 bus_space_write_1(iot, ioh, EL_GPBL, off & 0xff);
424 bus_space_write_1(iot, ioh, EL_GPBH, (off >> 8) & 0xff);
425
426 /* Copy the datagram to the buffer. */
427 for (m = m0; m != 0; m = m->m_next)
428 bus_space_write_multi_1(iot, ioh, EL_BUF,
429 mtod(m, u_int8_t *), m->m_len);
430 for (i = 0;
431 i < ETHER_MIN_LEN - ETHER_CRC_LEN - m0->m_pkthdr.len; i++)
432 bus_space_write_1(iot, ioh, EL_BUF, 0);
433
434 m_freem(m0);
435
436 /* Now transmit the datagram. */
437 retries = 0;
438 for (;;) {
439 bus_space_write_1(iot, ioh, EL_GPBL, off & 0xff);
440 bus_space_write_1(iot, ioh, EL_GPBH, (off >> 8) & 0xff);
441 if (el_xmit(sc)) {
442 ifp->if_oerrors++;
443 break;
444 }
445 /* Check out status. */
446 i = bus_space_read_1(iot, ioh, EL_TXS);
447 DPRINTF(("tx status=0x%x\n", i));
448 if ((i & EL_TXS_READY) == 0) {
449 DPRINTF(("el: err txs=%x\n", i));
450 if (i & (EL_TXS_COLL | EL_TXS_COLL16)) {
451 ifp->if_collisions++;
452 if ((i & EL_TXC_DCOLL16) == 0 &&
453 retries < 15) {
454 retries++;
455 bus_space_write_1(iot, ioh,
456 EL_AC, EL_AC_HOST);
457 }
458 } else {
459 ifp->if_oerrors++;
460 break;
461 }
462 } else {
463 ifp->if_opackets++;
464 break;
465 }
466 }
467
468 /*
469 * Now give the card a chance to receive.
470 * Gotta love 3c501s...
471 */
472 (void)bus_space_read_1(iot, ioh, EL_AS);
473 bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
474 splx(s);
475 /* Interrupt here. */
476 s = splnet();
477 }
478
479 (void)bus_space_read_1(iot, ioh, EL_AS);
480 bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
481 ifp->if_flags &= ~IFF_OACTIVE;
482 splx(s);
483 }
484
485 /*
486 * This function actually attempts to transmit a datagram downloaded to the
487 * board. Call at splnet or interrupt, after downloading data! Returns 0 on
488 * success, non-0 on failure.
489 */
490 static int
491 el_xmit(sc)
492 struct el_softc *sc;
493 {
494 bus_space_tag_t iot = sc->sc_iot;
495 bus_space_handle_t ioh = sc->sc_ioh;
496 int i;
497
498 /*
499 * XXX
500 * This busy-waits for the tx completion. Can we get an interrupt
501 * instead?
502 */
503
504 DPRINTF(("el: xmit..."));
505 bus_space_write_1(iot, ioh, EL_AC, EL_AC_TXFRX);
506 i = 20000;
507 while ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_TXBUSY) && (i > 0))
508 i--;
509 if (i == 0) {
510 DPRINTF(("tx not ready\n"));
511 return -1;
512 }
513 DPRINTF(("%d cycles.\n", 20000 - i));
514 return 0;
515 }
516
517 /*
518 * Controller interrupt.
519 */
520 int
521 elintr(arg)
522 void *arg;
523 {
524 struct el_softc *sc = arg;
525 bus_space_tag_t iot = sc->sc_iot;
526 bus_space_handle_t ioh = sc->sc_ioh;
527 u_int8_t rxstat;
528 int len;
529
530 DPRINTF(("elintr: "));
531
532 /* Check board status. */
533 if ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_RXBUSY) != 0) {
534 (void)bus_space_read_1(iot, ioh, EL_RXC);
535 bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
536 return 0;
537 }
538
539 for (;;) {
540 rxstat = bus_space_read_1(iot, ioh, EL_RXS);
541 if (rxstat & EL_RXS_STALE)
542 break;
543
544 /* If there's an overflow, reinit the board. */
545 if ((rxstat & EL_RXS_NOFLOW) == 0) {
546 DPRINTF(("overflow.\n"));
547 el_hardreset(sc);
548 /* Put board back into receive mode. */
549 if (sc->sc_ethercom.ec_if.if_flags & IFF_PROMISC)
550 bus_space_write_1(iot, ioh, EL_RXC,
551 EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
552 EL_RXC_DOFLOW | EL_RXC_PROMISC);
553 else
554 bus_space_write_1(iot, ioh, EL_RXC,
555 EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
556 EL_RXC_DOFLOW | EL_RXC_ABROAD);
557 (void)bus_space_read_1(iot, ioh, EL_AS);
558 bus_space_write_1(iot, ioh, EL_RBC, 0);
559 break;
560 }
561
562 /* Incoming packet. */
563 len = bus_space_read_1(iot, ioh, EL_RBL);
564 len |= bus_space_read_1(iot, ioh, EL_RBH) << 8;
565 DPRINTF(("receive len=%d rxstat=%x ", len, rxstat));
566 bus_space_write_1(iot, ioh, EL_AC, EL_AC_HOST);
567
568 /* Pass data up to upper levels. */
569 elread(sc, len);
570
571 /* Is there another packet? */
572 if ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_RXBUSY) != 0)
573 break;
574
575 #if NRND > 0
576 rnd_add_uint32(&sc->rnd_source, rxstat);
577 #endif
578
579 DPRINTF(("<rescan> "));
580 }
581
582 (void)bus_space_read_1(iot, ioh, EL_RXC);
583 bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
584 return 1;
585 }
586
587 /*
588 * Pass a packet to the higher levels.
589 */
590 void
591 elread(sc, len)
592 struct el_softc *sc;
593 int len;
594 {
595 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
596 struct mbuf *m;
597
598 if (len <= sizeof(struct ether_header) ||
599 len > ETHER_MAX_LEN) {
600 printf("%s: invalid packet size %d; dropping\n",
601 sc->sc_dev.dv_xname, len);
602 ifp->if_ierrors++;
603 return;
604 }
605
606 /* Pull packet off interface. */
607 m = elget(sc, len);
608 if (m == 0) {
609 ifp->if_ierrors++;
610 return;
611 }
612
613 ifp->if_ipackets++;
614
615 #if NBPFILTER > 0
616 /*
617 * Check if there's a BPF listener on this interface.
618 * If so, hand off the raw packet to BPF.
619 */
620 if (ifp->if_bpf)
621 bpf_mtap(ifp->if_bpf, m);
622 #endif
623
624 (*ifp->if_input)(ifp, m);
625 }
626
627 /*
628 * Pull read data off a interface. Len is length of data, with local net
629 * header stripped. We copy the data into mbufs. When full cluster sized
630 * units are present we copy into clusters.
631 */
632 struct mbuf *
633 elget(sc, totlen)
634 struct el_softc *sc;
635 int totlen;
636 {
637 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
638 bus_space_tag_t iot = sc->sc_iot;
639 bus_space_handle_t ioh = sc->sc_ioh;
640 struct mbuf *m, *m0, *newm;
641 int len;
642
643 MGETHDR(m0, M_DONTWAIT, MT_DATA);
644 if (m0 == 0)
645 return (0);
646 m0->m_pkthdr.rcvif = ifp;
647 m0->m_pkthdr.len = totlen;
648 len = MHLEN;
649 m = m0;
650
651 bus_space_write_1(iot, ioh, EL_GPBL, 0);
652 bus_space_write_1(iot, ioh, EL_GPBH, 0);
653
654 while (totlen > 0) {
655 if (totlen >= MINCLSIZE) {
656 MCLGET(m, M_DONTWAIT);
657 if ((m->m_flags & M_EXT) == 0)
658 goto bad;
659 len = MCLBYTES;
660 }
661
662 m->m_len = len = min(totlen, len);
663 bus_space_read_multi_1(iot, ioh, EL_BUF, mtod(m, u_int8_t *), len);
664
665 totlen -= len;
666 if (totlen > 0) {
667 MGET(newm, M_DONTWAIT, MT_DATA);
668 if (newm == 0)
669 goto bad;
670 len = MLEN;
671 m = m->m_next = newm;
672 }
673 }
674
675 bus_space_write_1(iot, ioh, EL_RBC, 0);
676 bus_space_write_1(iot, ioh, EL_AC, EL_AC_RX);
677
678 return (m0);
679
680 bad:
681 m_freem(m0);
682 return (0);
683 }
684
685 /*
686 * Process an ioctl request. This code needs some work - it looks pretty ugly.
687 */
688 int
689 elioctl(ifp, cmd, data)
690 struct ifnet *ifp;
691 u_long cmd;
692 caddr_t data;
693 {
694 struct el_softc *sc = ifp->if_softc;
695 struct ifaddr *ifa = (struct ifaddr *)data;
696 int s, error = 0;
697
698 s = splnet();
699
700 switch (cmd) {
701
702 case SIOCSIFADDR:
703 ifp->if_flags |= IFF_UP;
704
705 switch (ifa->ifa_addr->sa_family) {
706 #ifdef INET
707 case AF_INET:
708 elinit(sc);
709 arp_ifinit(ifp, ifa);
710 break;
711 #endif
712 default:
713 elinit(sc);
714 break;
715 }
716 break;
717
718 case SIOCSIFFLAGS:
719 if ((ifp->if_flags & IFF_UP) == 0 &&
720 (ifp->if_flags & IFF_RUNNING) != 0) {
721 /*
722 * If interface is marked down and it is running, then
723 * stop it.
724 */
725 elstop(sc);
726 ifp->if_flags &= ~IFF_RUNNING;
727 } else if ((ifp->if_flags & IFF_UP) != 0 &&
728 (ifp->if_flags & IFF_RUNNING) == 0) {
729 /*
730 * If interface is marked up and it is stopped, then
731 * start it.
732 */
733 elinit(sc);
734 } else {
735 /*
736 * Some other important flag might have changed, so
737 * reset.
738 */
739 elreset(sc);
740 }
741 break;
742
743 default:
744 error = EINVAL;
745 break;
746 }
747
748 splx(s);
749 return error;
750 }
751
752 /*
753 * Device timeout routine.
754 */
755 void
756 elwatchdog(ifp)
757 struct ifnet *ifp;
758 {
759 struct el_softc *sc = ifp->if_softc;
760
761 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
762 sc->sc_ethercom.ec_if.if_oerrors++;
763
764 elreset(sc);
765 }
766