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