if_el.c revision 1.66.10.1 1 /* $NetBSD: if_el.c,v 1.66.10.1 2003/01/27 04:54:01 jmc 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.10.1 2003/01/27 04:54:01 jmc 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 for (i = 0;
437 i < ETHER_MIN_LEN - ETHER_CRC_LEN - m0->m_pkthdr.len; i++)
438 bus_space_write_1(iot, ioh, EL_BUF, 0);
439
440 m_freem(m0);
441
442 /* Now transmit the datagram. */
443 retries = 0;
444 for (;;) {
445 bus_space_write_1(iot, ioh, EL_GPBL, off & 0xff);
446 bus_space_write_1(iot, ioh, EL_GPBH, (off >> 8) & 0xff);
447 if (el_xmit(sc)) {
448 ifp->if_oerrors++;
449 break;
450 }
451 /* Check out status. */
452 i = bus_space_read_1(iot, ioh, EL_TXS);
453 DPRINTF(("tx status=0x%x\n", i));
454 if ((i & EL_TXS_READY) == 0) {
455 DPRINTF(("el: err txs=%x\n", i));
456 if (i & (EL_TXS_COLL | EL_TXS_COLL16)) {
457 ifp->if_collisions++;
458 if ((i & EL_TXC_DCOLL16) == 0 &&
459 retries < 15) {
460 retries++;
461 bus_space_write_1(iot, ioh,
462 EL_AC, EL_AC_HOST);
463 }
464 } else {
465 ifp->if_oerrors++;
466 break;
467 }
468 } else {
469 ifp->if_opackets++;
470 break;
471 }
472 }
473
474 /*
475 * Now give the card a chance to receive.
476 * Gotta love 3c501s...
477 */
478 (void)bus_space_read_1(iot, ioh, EL_AS);
479 bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
480 splx(s);
481 /* Interrupt here. */
482 s = splnet();
483 }
484
485 (void)bus_space_read_1(iot, ioh, EL_AS);
486 bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
487 ifp->if_flags &= ~IFF_OACTIVE;
488 splx(s);
489 }
490
491 /*
492 * This function actually attempts to transmit a datagram downloaded to the
493 * board. Call at splnet or interrupt, after downloading data! Returns 0 on
494 * success, non-0 on failure.
495 */
496 static int
497 el_xmit(sc)
498 struct el_softc *sc;
499 {
500 bus_space_tag_t iot = sc->sc_iot;
501 bus_space_handle_t ioh = sc->sc_ioh;
502 int i;
503
504 /*
505 * XXX
506 * This busy-waits for the tx completion. Can we get an interrupt
507 * instead?
508 */
509
510 DPRINTF(("el: xmit..."));
511 bus_space_write_1(iot, ioh, EL_AC, EL_AC_TXFRX);
512 i = 20000;
513 while ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_TXBUSY) && (i > 0))
514 i--;
515 if (i == 0) {
516 DPRINTF(("tx not ready\n"));
517 return -1;
518 }
519 DPRINTF(("%d cycles.\n", 20000 - i));
520 return 0;
521 }
522
523 /*
524 * Controller interrupt.
525 */
526 int
527 elintr(arg)
528 void *arg;
529 {
530 struct el_softc *sc = arg;
531 bus_space_tag_t iot = sc->sc_iot;
532 bus_space_handle_t ioh = sc->sc_ioh;
533 u_int8_t rxstat;
534 int len;
535
536 DPRINTF(("elintr: "));
537
538 /* Check board status. */
539 if ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_RXBUSY) != 0) {
540 (void)bus_space_read_1(iot, ioh, EL_RXC);
541 bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
542 return 0;
543 }
544
545 for (;;) {
546 rxstat = bus_space_read_1(iot, ioh, EL_RXS);
547 if (rxstat & EL_RXS_STALE)
548 break;
549
550 /* If there's an overflow, reinit the board. */
551 if ((rxstat & EL_RXS_NOFLOW) == 0) {
552 DPRINTF(("overflow.\n"));
553 el_hardreset(sc);
554 /* Put board back into receive mode. */
555 if (sc->sc_ethercom.ec_if.if_flags & IFF_PROMISC)
556 bus_space_write_1(iot, ioh, EL_RXC,
557 EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
558 EL_RXC_DOFLOW | EL_RXC_PROMISC);
559 else
560 bus_space_write_1(iot, ioh, EL_RXC,
561 EL_RXC_AGF | EL_RXC_DSHORT | EL_RXC_DDRIB |
562 EL_RXC_DOFLOW | EL_RXC_ABROAD);
563 (void)bus_space_read_1(iot, ioh, EL_AS);
564 bus_space_write_1(iot, ioh, EL_RBC, 0);
565 break;
566 }
567
568 /* Incoming packet. */
569 len = bus_space_read_1(iot, ioh, EL_RBL);
570 len |= bus_space_read_1(iot, ioh, EL_RBH) << 8;
571 DPRINTF(("receive len=%d rxstat=%x ", len, rxstat));
572 bus_space_write_1(iot, ioh, EL_AC, EL_AC_HOST);
573
574 /* Pass data up to upper levels. */
575 elread(sc, len);
576
577 /* Is there another packet? */
578 if ((bus_space_read_1(iot, ioh, EL_AS) & EL_AS_RXBUSY) != 0)
579 break;
580
581 #if NRND > 0
582 rnd_add_uint32(&sc->rnd_source, rxstat);
583 #endif
584
585 DPRINTF(("<rescan> "));
586 }
587
588 (void)bus_space_read_1(iot, ioh, EL_RXC);
589 bus_space_write_1(iot, ioh, EL_AC, EL_AC_IRQE | EL_AC_RX);
590 return 1;
591 }
592
593 /*
594 * Pass a packet to the higher levels.
595 */
596 void
597 elread(sc, len)
598 struct el_softc *sc;
599 int len;
600 {
601 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
602 struct mbuf *m;
603
604 if (len <= sizeof(struct ether_header) ||
605 len > ETHER_MAX_LEN) {
606 printf("%s: invalid packet size %d; dropping\n",
607 sc->sc_dev.dv_xname, len);
608 ifp->if_ierrors++;
609 return;
610 }
611
612 /* Pull packet off interface. */
613 m = elget(sc, len);
614 if (m == 0) {
615 ifp->if_ierrors++;
616 return;
617 }
618
619 ifp->if_ipackets++;
620
621 #if NBPFILTER > 0
622 /*
623 * Check if there's a BPF listener on this interface.
624 * If so, hand off the raw packet to BPF.
625 */
626 if (ifp->if_bpf)
627 bpf_mtap(ifp->if_bpf, m);
628 #endif
629
630 (*ifp->if_input)(ifp, m);
631 }
632
633 /*
634 * Pull read data off a interface. Len is length of data, with local net
635 * header stripped. We copy the data into mbufs. When full cluster sized
636 * units are present we copy into clusters.
637 */
638 struct mbuf *
639 elget(sc, totlen)
640 struct el_softc *sc;
641 int totlen;
642 {
643 struct ifnet *ifp = &sc->sc_ethercom.ec_if;
644 bus_space_tag_t iot = sc->sc_iot;
645 bus_space_handle_t ioh = sc->sc_ioh;
646 struct mbuf *m, *m0, *newm;
647 int len;
648
649 MGETHDR(m0, M_DONTWAIT, MT_DATA);
650 if (m0 == 0)
651 return (0);
652 m0->m_pkthdr.rcvif = ifp;
653 m0->m_pkthdr.len = totlen;
654 len = MHLEN;
655 m = m0;
656
657 bus_space_write_1(iot, ioh, EL_GPBL, 0);
658 bus_space_write_1(iot, ioh, EL_GPBH, 0);
659
660 while (totlen > 0) {
661 if (totlen >= MINCLSIZE) {
662 MCLGET(m, M_DONTWAIT);
663 if ((m->m_flags & M_EXT) == 0)
664 goto bad;
665 len = MCLBYTES;
666 }
667
668 m->m_len = len = min(totlen, len);
669 bus_space_read_multi_1(iot, ioh, EL_BUF, mtod(m, u_int8_t *), len);
670
671 totlen -= len;
672 if (totlen > 0) {
673 MGET(newm, M_DONTWAIT, MT_DATA);
674 if (newm == 0)
675 goto bad;
676 len = MLEN;
677 m = m->m_next = newm;
678 }
679 }
680
681 bus_space_write_1(iot, ioh, EL_RBC, 0);
682 bus_space_write_1(iot, ioh, EL_AC, EL_AC_RX);
683
684 return (m0);
685
686 bad:
687 m_freem(m0);
688 return (0);
689 }
690
691 /*
692 * Process an ioctl request. This code needs some work - it looks pretty ugly.
693 */
694 int
695 elioctl(ifp, cmd, data)
696 struct ifnet *ifp;
697 u_long cmd;
698 caddr_t data;
699 {
700 struct el_softc *sc = ifp->if_softc;
701 struct ifaddr *ifa = (struct ifaddr *)data;
702 int s, error = 0;
703
704 s = splnet();
705
706 switch (cmd) {
707
708 case SIOCSIFADDR:
709 ifp->if_flags |= IFF_UP;
710
711 switch (ifa->ifa_addr->sa_family) {
712 #ifdef INET
713 case AF_INET:
714 elinit(sc);
715 arp_ifinit(ifp, ifa);
716 break;
717 #endif
718 #ifdef NS
719 /* XXX - This code is probably wrong. */
720 case AF_NS:
721 {
722 struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
723
724 if (ns_nullhost(*ina))
725 ina->x_host =
726 *(union ns_host *)LLADDR(ifp->if_sadl);
727 else
728 memcpy(LLADDR(ifp->if_sadl), ina->x_host.c_host,
729 ETHER_ADDR_LEN);
730 /* Set new address. */
731 elinit(sc);
732 break;
733 }
734 #endif
735 default:
736 elinit(sc);
737 break;
738 }
739 break;
740
741 case SIOCSIFFLAGS:
742 if ((ifp->if_flags & IFF_UP) == 0 &&
743 (ifp->if_flags & IFF_RUNNING) != 0) {
744 /*
745 * If interface is marked down and it is running, then
746 * stop it.
747 */
748 elstop(sc);
749 ifp->if_flags &= ~IFF_RUNNING;
750 } else if ((ifp->if_flags & IFF_UP) != 0 &&
751 (ifp->if_flags & IFF_RUNNING) == 0) {
752 /*
753 * If interface is marked up and it is stopped, then
754 * start it.
755 */
756 elinit(sc);
757 } else {
758 /*
759 * Some other important flag might have changed, so
760 * reset.
761 */
762 elreset(sc);
763 }
764 break;
765
766 default:
767 error = EINVAL;
768 break;
769 }
770
771 splx(s);
772 return error;
773 }
774
775 /*
776 * Device timeout routine.
777 */
778 void
779 elwatchdog(ifp)
780 struct ifnet *ifp;
781 {
782 struct el_softc *sc = ifp->if_softc;
783
784 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
785 sc->sc_ethercom.ec_if.if_oerrors++;
786
787 elreset(sc);
788 }
789