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