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