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