am79900.c revision 1.12 1 /* $NetBSD: am79900.c,v 1.12 2003/08/07 16:30:58 agc Exp $ */
2
3 /*-
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Ralph Campbell and Rick Macklem.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
35 */
36
37 /*-
38 * Copyright (c) 1998
39 * Matthias Drochner. All rights reserved.
40 * Copyright (c) 1997 Jason R. Thorpe. All rights reserved.
41 * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
42 *
43 * This code is derived from software contributed to Berkeley by
44 * Ralph Campbell and Rick Macklem.
45 *
46 * Redistribution and use in source and binary forms, with or without
47 * modification, are permitted provided that the following conditions
48 * are met:
49 * 1. Redistributions of source code must retain the above copyright
50 * notice, this list of conditions and the following disclaimer.
51 * 2. Redistributions in binary form must reproduce the above copyright
52 * notice, this list of conditions and the following disclaimer in the
53 * documentation and/or other materials provided with the distribution.
54 * 3. All advertising materials mentioning features or use of this software
55 * must display the following acknowledgement:
56 * This product includes software developed by the University of
57 * California, Berkeley and its contributors.
58 * 4. Neither the name of the University nor the names of its contributors
59 * may be used to endorse or promote products derived from this software
60 * without specific prior written permission.
61 *
62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72 * SUCH DAMAGE.
73 *
74 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
75 */
76
77 #include <sys/cdefs.h>
78 __KERNEL_RCSID(0, "$NetBSD: am79900.c,v 1.12 2003/08/07 16:30:58 agc Exp $");
79
80 #include "bpfilter.h"
81 #include "rnd.h"
82
83 #include <sys/param.h>
84 #include <sys/systm.h>
85 #include <sys/mbuf.h>
86 #include <sys/syslog.h>
87 #include <sys/socket.h>
88 #include <sys/device.h>
89 #include <sys/malloc.h>
90 #include <sys/ioctl.h>
91 #include <sys/errno.h>
92 #if NRND > 0
93 #include <sys/rnd.h>
94 #endif
95
96 #include <net/if.h>
97 #include <net/if_dl.h>
98 #include <net/if_ether.h>
99 #include <net/if_media.h>
100
101 #if NBPFILTER > 0
102 #include <net/bpf.h>
103 #include <net/bpfdesc.h>
104 #endif
105
106 #include <dev/ic/lancereg.h>
107 #include <dev/ic/lancevar.h>
108 #include <dev/ic/am79900reg.h>
109 #include <dev/ic/am79900var.h>
110
111 void am79900_meminit __P((struct lance_softc *));
112 void am79900_start __P((struct ifnet *));
113
114 #if defined(_KERNEL_OPT)
115 #include "opt_ddb.h"
116 #endif
117
118 #ifdef DDB
119 #define integrate
120 #define hide
121 #else
122 #define integrate static __inline
123 #define hide static
124 #endif
125
126 integrate void am79900_rint __P((struct lance_softc *));
127 integrate void am79900_tint __P((struct lance_softc *));
128
129 #ifdef LEDEBUG
130 void am79900_recv_print __P((struct lance_softc *, int));
131 void am79900_xmit_print __P((struct lance_softc *, int));
132 #endif
133
134 #define ifp (&sc->sc_ethercom.ec_if)
135
136 void
137 am79900_config(sc)
138 struct am79900_softc *sc;
139 {
140 int mem, i;
141
142 sc->lsc.sc_meminit = am79900_meminit;
143 sc->lsc.sc_start = am79900_start;
144
145 lance_config(&sc->lsc);
146
147 mem = 0;
148 sc->lsc.sc_initaddr = mem;
149 mem += sizeof(struct leinit);
150 sc->lsc.sc_rmdaddr = mem;
151 mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf;
152 sc->lsc.sc_tmdaddr = mem;
153 mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf;
154 for (i = 0; i < sc->lsc.sc_nrbuf; i++, mem += LEBLEN)
155 sc->lsc.sc_rbufaddr[i] = mem;
156 for (i = 0; i < sc->lsc.sc_ntbuf; i++, mem += LEBLEN)
157 sc->lsc.sc_tbufaddr[i] = mem;
158
159 if (mem > sc->lsc.sc_memsize)
160 panic("%s: memsize", sc->lsc.sc_dev.dv_xname);
161 }
162
163 /*
164 * Set up the initialization block and the descriptor rings.
165 */
166 void
167 am79900_meminit(sc)
168 struct lance_softc *sc;
169 {
170 u_long a;
171 int bix;
172 struct leinit init;
173 struct lermd rmd;
174 struct letmd tmd;
175 u_int8_t *myaddr;
176
177 #if NBPFILTER > 0
178 if (ifp->if_flags & IFF_PROMISC)
179 init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM;
180 else
181 #endif
182 init.init_mode = LE_MODE_NORMAL;
183 if (sc->sc_initmodemedia == 1)
184 init.init_mode |= LE_MODE_PSEL0;
185
186 init.init_mode |= ((ffs(sc->sc_ntbuf) - 1) << 28)
187 | ((ffs(sc->sc_nrbuf) - 1) << 20);
188
189 /*
190 * Update our private copy of the Ethernet address.
191 * We NEED the copy so we can ensure its alignment!
192 */
193 memcpy(sc->sc_enaddr, LLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
194 myaddr = sc->sc_enaddr;
195
196 init.init_padr[0] = myaddr[0] | (myaddr[1] << 8)
197 | (myaddr[2] << 16) | (myaddr[3] << 24);
198 init.init_padr[1] = myaddr[4] | (myaddr[5] << 8);
199 lance_setladrf(&sc->sc_ethercom, init.init_ladrf);
200
201 sc->sc_last_rd = 0;
202 sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
203
204 a = sc->sc_addr + LE_RMDADDR(sc, 0);
205 init.init_rdra = a;
206
207 a = sc->sc_addr + LE_TMDADDR(sc, 0);
208 init.init_tdra = a;
209
210 (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init));
211
212 /*
213 * Set up receive ring descriptors.
214 */
215 for (bix = 0; bix < sc->sc_nrbuf; bix++) {
216 a = sc->sc_addr + LE_RBUFADDR(sc, bix);
217 rmd.rmd0 = a;
218 rmd.rmd1 = LE_R1_OWN | LE_R1_ONES | (-LEBLEN & 0xfff);
219 rmd.rmd2 = 0;
220 rmd.rmd3 = 0;
221 (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix),
222 sizeof(rmd));
223 }
224
225 /*
226 * Set up transmit ring descriptors.
227 */
228 for (bix = 0; bix < sc->sc_ntbuf; bix++) {
229 a = sc->sc_addr + LE_TBUFADDR(sc, bix);
230 tmd.tmd0 = a;
231 tmd.tmd1 = LE_T1_ONES;
232 tmd.tmd2 = 0;
233 tmd.tmd3 = 0;
234 (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix),
235 sizeof(tmd));
236 }
237 }
238
239 integrate void
240 am79900_rint(sc)
241 struct lance_softc *sc;
242 {
243 int bix;
244 int rp;
245 struct lermd rmd;
246
247 bix = sc->sc_last_rd;
248
249 /* Process all buffers with valid data. */
250 for (;;) {
251 rp = LE_RMDADDR(sc, bix);
252 (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));
253
254 if (rmd.rmd1 & LE_R1_OWN)
255 break;
256
257 if (rmd.rmd1 & LE_R1_ERR) {
258 if (rmd.rmd1 & LE_R1_ENP) {
259 #ifdef LEDEBUG
260 if ((rmd.rmd1 & LE_R1_OFLO) == 0) {
261 if (rmd.rmd1 & LE_R1_FRAM)
262 printf("%s: framing error\n",
263 sc->sc_dev.dv_xname);
264 if (rmd.rmd1 & LE_R1_CRC)
265 printf("%s: crc mismatch\n",
266 sc->sc_dev.dv_xname);
267 }
268 #endif
269 } else {
270 if (rmd.rmd1 & LE_R1_OFLO)
271 printf("%s: overflow\n",
272 sc->sc_dev.dv_xname);
273 }
274 if (rmd.rmd1 & LE_R1_BUFF)
275 printf("%s: receive buffer error\n",
276 sc->sc_dev.dv_xname);
277 ifp->if_ierrors++;
278 } else if ((rmd.rmd1 & (LE_R1_STP | LE_R1_ENP)) !=
279 (LE_R1_STP | LE_R1_ENP)) {
280 printf("%s: dropping chained buffer\n",
281 sc->sc_dev.dv_xname);
282 ifp->if_ierrors++;
283 } else {
284 #ifdef LEDEBUG
285 if (sc->sc_debug)
286 am79900_recv_print(sc, sc->sc_last_rd);
287 #endif
288 lance_read(sc, LE_RBUFADDR(sc, bix),
289 (rmd.rmd2 & 0xfff) - 4);
290 }
291
292 rmd.rmd1 = LE_R1_OWN | LE_R1_ONES | (-LEBLEN & 0xfff);
293 rmd.rmd2 = 0;
294 rmd.rmd3 = 0;
295 (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
296
297 #ifdef LEDEBUG
298 if (sc->sc_debug)
299 printf("sc->sc_last_rd = %x, rmd: "
300 "adr %08x, flags/blen %08x\n",
301 sc->sc_last_rd,
302 rmd.rmd0, rmd.rmd1);
303 #endif
304
305 if (++bix == sc->sc_nrbuf)
306 bix = 0;
307 }
308
309 sc->sc_last_rd = bix;
310 }
311
312 integrate void
313 am79900_tint(sc)
314 struct lance_softc *sc;
315 {
316 int bix;
317 struct letmd tmd;
318
319 bix = sc->sc_first_td;
320
321 for (;;) {
322 if (sc->sc_no_td <= 0)
323 break;
324
325 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
326 sizeof(tmd));
327
328 #ifdef LEDEBUG
329 if (sc->sc_debug)
330 printf("trans tmd: "
331 "adr %08x, flags/blen %08x\n",
332 tmd.tmd0, tmd.tmd1);
333 #endif
334
335 if (tmd.tmd1 & LE_T1_OWN)
336 break;
337
338 ifp->if_flags &= ~IFF_OACTIVE;
339
340 if (tmd.tmd1 & LE_T1_ERR) {
341 if (tmd.tmd2 & LE_T2_BUFF)
342 printf("%s: transmit buffer error\n",
343 sc->sc_dev.dv_xname);
344 else if (tmd.tmd2 & LE_T2_UFLO)
345 printf("%s: underflow\n", sc->sc_dev.dv_xname);
346 if (tmd.tmd2 & (LE_T2_BUFF | LE_T2_UFLO)) {
347 lance_reset(sc);
348 return;
349 }
350 if (tmd.tmd2 & LE_T2_LCAR) {
351 sc->sc_havecarrier = 0;
352 if (sc->sc_nocarrier)
353 (*sc->sc_nocarrier)(sc);
354 else
355 printf("%s: lost carrier\n",
356 sc->sc_dev.dv_xname);
357 }
358 if (tmd.tmd2 & LE_T2_LCOL)
359 ifp->if_collisions++;
360 if (tmd.tmd2 & LE_T2_RTRY) {
361 #ifdef LEDEBUG
362 printf("%s: excessive collisions\n",
363 sc->sc_dev.dv_xname);
364 #endif
365 ifp->if_collisions += 16;
366 }
367 ifp->if_oerrors++;
368 } else {
369 if (tmd.tmd1 & LE_T1_ONE)
370 ifp->if_collisions++;
371 else if (tmd.tmd1 & LE_T1_MORE)
372 /* Real number is unknown. */
373 ifp->if_collisions += 2;
374 ifp->if_opackets++;
375 }
376
377 if (++bix == sc->sc_ntbuf)
378 bix = 0;
379
380 --sc->sc_no_td;
381 }
382
383 sc->sc_first_td = bix;
384
385 am79900_start(ifp);
386
387 if (sc->sc_no_td == 0)
388 ifp->if_timer = 0;
389 }
390
391 /*
392 * Controller interrupt.
393 */
394 int
395 am79900_intr(arg)
396 void *arg;
397 {
398 struct lance_softc *sc = arg;
399 u_int16_t isr;
400
401 isr = (*sc->sc_rdcsr)(sc, LE_CSR0) | sc->sc_saved_csr0;
402 sc->sc_saved_csr0 = 0;
403 #if defined(LEDEBUG) && LEDEBUG > 1
404 if (sc->sc_debug)
405 printf("%s: am79900_intr entering with isr=%04x\n",
406 sc->sc_dev.dv_xname, isr);
407 #endif
408 if ((isr & LE_C0_INTR) == 0)
409 return (0);
410
411 (*sc->sc_wrcsr)(sc, LE_CSR0,
412 isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR |
413 LE_C0_RINT | LE_C0_TINT | LE_C0_IDON));
414 if (isr & LE_C0_ERR) {
415 if (isr & LE_C0_BABL) {
416 #ifdef LEDEBUG
417 printf("%s: babble\n", sc->sc_dev.dv_xname);
418 #endif
419 ifp->if_oerrors++;
420 }
421 #if 0
422 if (isr & LE_C0_CERR) {
423 printf("%s: collision error\n", sc->sc_dev.dv_xname);
424 ifp->if_collisions++;
425 }
426 #endif
427 if (isr & LE_C0_MISS) {
428 #ifdef LEDEBUG
429 printf("%s: missed packet\n", sc->sc_dev.dv_xname);
430 #endif
431 ifp->if_ierrors++;
432 }
433 if (isr & LE_C0_MERR) {
434 printf("%s: memory error\n", sc->sc_dev.dv_xname);
435 lance_reset(sc);
436 return (1);
437 }
438 }
439
440 if ((isr & LE_C0_RXON) == 0) {
441 printf("%s: receiver disabled\n", sc->sc_dev.dv_xname);
442 ifp->if_ierrors++;
443 lance_reset(sc);
444 return (1);
445 }
446 if ((isr & LE_C0_TXON) == 0) {
447 printf("%s: transmitter disabled\n", sc->sc_dev.dv_xname);
448 ifp->if_oerrors++;
449 lance_reset(sc);
450 return (1);
451 }
452
453 /*
454 * Pretend we have carrier; if we don't this will be cleared
455 * shortly.
456 */
457 sc->sc_havecarrier = 1;
458
459 if (isr & LE_C0_RINT)
460 am79900_rint(sc);
461 if (isr & LE_C0_TINT)
462 am79900_tint(sc);
463
464 #if NRND > 0
465 rnd_add_uint32(&sc->rnd_source, isr);
466 #endif
467
468 return (1);
469 }
470
471 #undef ifp
472
473 /*
474 * Setup output on interface.
475 * Get another datagram to send off of the interface queue, and map it to the
476 * interface before starting the output.
477 * Called only at splnet or interrupt level.
478 */
479 void
480 am79900_start(ifp)
481 struct ifnet *ifp;
482 {
483 struct lance_softc *sc = ifp->if_softc;
484 int bix;
485 struct mbuf *m;
486 struct letmd tmd;
487 int rp;
488 int len;
489
490 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
491 return;
492
493 bix = sc->sc_last_td;
494
495 for (;;) {
496 rp = LE_TMDADDR(sc, bix);
497 (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd));
498
499 if (tmd.tmd1 & LE_T1_OWN) {
500 ifp->if_flags |= IFF_OACTIVE;
501 printf("missing buffer, no_td = %d, last_td = %d\n",
502 sc->sc_no_td, sc->sc_last_td);
503 }
504
505 IFQ_DEQUEUE(&ifp->if_snd, m);
506 if (m == 0)
507 break;
508
509 #if NBPFILTER > 0
510 /*
511 * If BPF is listening on this interface, let it see the packet
512 * before we commit it to the wire.
513 */
514 if (ifp->if_bpf)
515 bpf_mtap(ifp->if_bpf, m);
516 #endif
517
518 /*
519 * Copy the mbuf chain into the transmit buffer.
520 */
521 len = lance_put(sc, LE_TBUFADDR(sc, bix), m);
522
523 #ifdef LEDEBUG
524 if (len > ETHERMTU + sizeof(struct ether_header))
525 printf("packet length %d\n", len);
526 #endif
527
528 ifp->if_timer = 5;
529
530 /*
531 * Init transmit registers, and set transmit start flag.
532 */
533 tmd.tmd1 = LE_T1_OWN | LE_T1_STP | LE_T1_ENP | LE_T1_ONES | (-len & 0xfff);
534 tmd.tmd2 = 0;
535 tmd.tmd3 = 0;
536
537 (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));
538
539 #ifdef LEDEBUG
540 if (sc->sc_debug)
541 am79900_xmit_print(sc, sc->sc_last_td);
542 #endif
543
544 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
545
546 if (++bix == sc->sc_ntbuf)
547 bix = 0;
548
549 if (++sc->sc_no_td == sc->sc_ntbuf) {
550 ifp->if_flags |= IFF_OACTIVE;
551 break;
552 }
553
554 }
555
556 sc->sc_last_td = bix;
557 }
558
559 #ifdef LEDEBUG
560 void
561 am79900_recv_print(sc, no)
562 struct lance_softc *sc;
563 int no;
564 {
565 struct lermd rmd;
566 u_int16_t len;
567 struct ether_header eh;
568
569 (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd));
570 len = (rmd.rmd2 & 0xfff) - 4;
571 printf("%s: receive buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
572 len);
573 printf("%s: status %04x\n", sc->sc_dev.dv_xname,
574 (*sc->sc_rdcsr)(sc, LE_CSR0));
575 printf("%s: adr %08x, flags/blen %08x\n",
576 sc->sc_dev.dv_xname, rmd.rmd0, rmd.rmd1);
577 if (len >= sizeof(eh)) {
578 (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
579 printf("%s: dst %s", sc->sc_dev.dv_xname,
580 ether_sprintf(eh.ether_dhost));
581 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
582 ntohs(eh.ether_type));
583 }
584 }
585
586 void
587 am79900_xmit_print(sc, no)
588 struct lance_softc *sc;
589 int no;
590 {
591 struct letmd tmd;
592 u_int16_t len;
593 struct ether_header eh;
594
595 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd));
596 len = -(tmd.tmd1 & 0xfff);
597 printf("%s: transmit buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
598 len);
599 printf("%s: status %04x\n", sc->sc_dev.dv_xname,
600 (*sc->sc_rdcsr)(sc, LE_CSR0));
601 printf("%s: adr %08x, flags/blen %08x\n",
602 sc->sc_dev.dv_xname, tmd.tmd0, tmd.tmd1);
603 if (len >= sizeof(eh)) {
604 (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
605 printf("%s: dst %s", sc->sc_dev.dv_xname,
606 ether_sprintf(eh.ether_dhost));
607 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
608 ntohs(eh.ether_type));
609 }
610 }
611 #endif /* LEDEBUG */
612