1 /* $NetBSD: am7990.c,v 1.75 2015/04/13 16:33:24 riastradh 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.75 2015/04/13 16:33:24 riastradh Exp $");
69
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/mbuf.h>
73 #include <sys/syslog.h>
74 #include <sys/socket.h>
75 #include <sys/device.h>
76 #include <sys/malloc.h>
77 #include <sys/ioctl.h>
78 #include <sys/errno.h>
79 #include <sys/rndsource.h>
80
81 #include <net/if.h>
82 #include <net/if_dl.h>
83 #include <net/if_ether.h>
84 #include <net/if_media.h>
85
86 #include <net/bpf.h>
87 #include <net/bpfdesc.h>
88
89 #include <dev/ic/lancereg.h>
90 #include <dev/ic/lancevar.h>
91 #include <dev/ic/am7990reg.h>
92 #include <dev/ic/am7990var.h>
93
94 static void am7990_meminit(struct lance_softc *);
95 static void am7990_start(struct ifnet *);
96
97 #if defined(_KERNEL_OPT)
98 #include "opt_ddb.h"
99 #endif
100
101 #ifdef LEDEBUG
102 static void am7990_recv_print(struct lance_softc *, int);
103 static void am7990_xmit_print(struct lance_softc *, int);
104 #endif
105
106 #define ifp (&sc->sc_ethercom.ec_if)
107
108 void
am7990_config(struct am7990_softc * sc)109 am7990_config(struct am7990_softc *sc)
110 {
111 int mem, i;
112
113 sc->lsc.sc_meminit = am7990_meminit;
114 sc->lsc.sc_start = am7990_start;
115
116 lance_config(&sc->lsc);
117
118 mem = 0;
119 sc->lsc.sc_initaddr = mem;
120 mem += sizeof(struct leinit);
121 sc->lsc.sc_rmdaddr = mem;
122 mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf;
123 sc->lsc.sc_tmdaddr = mem;
124 mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf;
125 for (i = 0; i < sc->lsc.sc_nrbuf; i++, mem += LEBLEN)
126 sc->lsc.sc_rbufaddr[i] = mem;
127 for (i = 0; i < sc->lsc.sc_ntbuf; i++, mem += LEBLEN)
128 sc->lsc.sc_tbufaddr[i] = mem;
129 #ifdef notyet
130 if (mem > ...)
131 panic(...);
132 #endif
133 }
134
135 /*
136 * Set up the initialization block and the descriptor rings.
137 */
138 static void
am7990_meminit(struct lance_softc * sc)139 am7990_meminit(struct lance_softc *sc)
140 {
141 u_long a;
142 int bix;
143 struct leinit init;
144 struct lermd rmd;
145 struct letmd tmd;
146 uint8_t *myaddr;
147
148 if (ifp->if_flags & IFF_PROMISC)
149 init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM;
150 else
151 init.init_mode = LE_MODE_NORMAL;
152 if (sc->sc_initmodemedia == 1)
153 init.init_mode |= LE_MODE_PSEL0;
154
155 /*
156 * Update our private copy of the Ethernet address.
157 * We NEED the copy so we can ensure its alignment!
158 */
159 memcpy(sc->sc_enaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
160 myaddr = sc->sc_enaddr;
161
162 init.init_padr[0] = (myaddr[1] << 8) | myaddr[0];
163 init.init_padr[1] = (myaddr[3] << 8) | myaddr[2];
164 init.init_padr[2] = (myaddr[5] << 8) | myaddr[4];
165 lance_setladrf(&sc->sc_ethercom, init.init_ladrf);
166
167 sc->sc_last_rd = 0;
168 sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
169
170 a = sc->sc_addr + LE_RMDADDR(sc, 0);
171 init.init_rdra = a;
172 init.init_rlen = (a >> 16) | ((ffs(sc->sc_nrbuf) - 1) << 13);
173
174 a = sc->sc_addr + LE_TMDADDR(sc, 0);
175 init.init_tdra = a;
176 init.init_tlen = (a >> 16) | ((ffs(sc->sc_ntbuf) - 1) << 13);
177
178 (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init));
179
180 /*
181 * Set up receive ring descriptors.
182 */
183 for (bix = 0; bix < sc->sc_nrbuf; bix++) {
184 a = sc->sc_addr + LE_RBUFADDR(sc, bix);
185 rmd.rmd0 = a;
186 rmd.rmd1_hadr = a >> 16;
187 rmd.rmd1_bits = LE_R1_OWN;
188 rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
189 rmd.rmd3 = 0;
190 (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix),
191 sizeof(rmd));
192 }
193
194 /*
195 * Set up transmit ring descriptors.
196 */
197 for (bix = 0; bix < sc->sc_ntbuf; bix++) {
198 a = sc->sc_addr + LE_TBUFADDR(sc, bix);
199 tmd.tmd0 = a;
200 tmd.tmd1_hadr = a >> 16;
201 tmd.tmd1_bits = 0;
202 tmd.tmd2 = 0 | LE_XMD2_ONES;
203 tmd.tmd3 = 0;
204 (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix),
205 sizeof(tmd));
206 }
207 }
208
209 static void
am7990_rint(struct lance_softc * sc)210 am7990_rint(struct lance_softc *sc)
211 {
212 int bix;
213 int rp;
214 struct lermd rmd;
215
216 bix = sc->sc_last_rd;
217
218 /* Process all buffers with valid data. */
219 for (;;) {
220 rp = LE_RMDADDR(sc, bix);
221 (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));
222
223 if (rmd.rmd1_bits & LE_R1_OWN)
224 break;
225
226 if (rmd.rmd1_bits & LE_R1_ERR) {
227 if (rmd.rmd1_bits & LE_R1_ENP) {
228 #ifdef LEDEBUG
229 if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) {
230 if (rmd.rmd1_bits & LE_R1_FRAM)
231 printf("%s: framing error\n",
232 device_xname(sc->sc_dev));
233 if (rmd.rmd1_bits & LE_R1_CRC)
234 printf("%s: crc mismatch\n",
235 device_xname(sc->sc_dev));
236 }
237 #endif
238 } else {
239 if (rmd.rmd1_bits & LE_R1_OFLO)
240 printf("%s: overflow\n",
241 device_xname(sc->sc_dev));
242 }
243 if (rmd.rmd1_bits & LE_R1_BUFF)
244 printf("%s: receive buffer error\n",
245 device_xname(sc->sc_dev));
246 ifp->if_ierrors++;
247 } else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) !=
248 (LE_R1_STP | LE_R1_ENP)) {
249 printf("%s: dropping chained buffer\n",
250 device_xname(sc->sc_dev));
251 ifp->if_ierrors++;
252 } else {
253 #ifdef LEDEBUG
254 if (sc->sc_debug > 1)
255 am7990_recv_print(sc, sc->sc_last_rd);
256 #endif
257 lance_read(sc, LE_RBUFADDR(sc, bix),
258 (int)rmd.rmd3 - 4);
259 }
260
261 rmd.rmd1_bits = LE_R1_OWN;
262 rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
263 rmd.rmd3 = 0;
264 (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
265
266 #ifdef LEDEBUG
267 if (sc->sc_debug)
268 printf("sc->sc_last_rd = %x, rmd: "
269 "ladr %04x, hadr %02x, flags %02x, "
270 "bcnt %04x, mcnt %04x\n",
271 sc->sc_last_rd,
272 rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits,
273 rmd.rmd2, rmd.rmd3);
274 #endif
275
276 if (++bix == sc->sc_nrbuf)
277 bix = 0;
278 }
279
280 sc->sc_last_rd = bix;
281 }
282
283 static void
am7990_tint(struct lance_softc * sc)284 am7990_tint(struct lance_softc *sc)
285 {
286 int bix;
287 struct letmd tmd;
288
289 bix = sc->sc_first_td;
290
291 for (;;) {
292 if (sc->sc_no_td <= 0)
293 break;
294
295 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
296 sizeof(tmd));
297
298 #ifdef LEDEBUG
299 if (sc->sc_debug)
300 printf("trans tmd: "
301 "ladr %04x, hadr %02x, flags %02x, "
302 "bcnt %04x, mcnt %04x\n",
303 tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits,
304 tmd.tmd2, tmd.tmd3);
305 #endif
306
307 if (tmd.tmd1_bits & LE_T1_OWN)
308 break;
309
310 ifp->if_flags &= ~IFF_OACTIVE;
311
312 if (tmd.tmd1_bits & LE_T1_ERR) {
313 if (tmd.tmd3 & LE_T3_BUFF)
314 printf("%s: transmit buffer error\n",
315 device_xname(sc->sc_dev));
316 else if (tmd.tmd3 & LE_T3_UFLO)
317 printf("%s: underflow\n",
318 device_xname(sc->sc_dev));
319 if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) {
320 lance_reset(sc);
321 return;
322 }
323 if (tmd.tmd3 & LE_T3_LCAR) {
324 sc->sc_havecarrier = 0;
325 if (sc->sc_nocarrier)
326 (*sc->sc_nocarrier)(sc);
327 else
328 printf("%s: lost carrier\n",
329 device_xname(sc->sc_dev));
330 }
331 if (tmd.tmd3 & LE_T3_LCOL)
332 ifp->if_collisions++;
333 if (tmd.tmd3 & LE_T3_RTRY) {
334 #ifdef LEDEBUG
335 printf("%s: excessive collisions, tdr %d\n",
336 device_xname(sc->sc_dev),
337 tmd.tmd3 & LE_T3_TDR_MASK);
338 #endif
339 ifp->if_collisions += 16;
340 }
341 ifp->if_oerrors++;
342 } else {
343 if (tmd.tmd1_bits & LE_T1_ONE)
344 ifp->if_collisions++;
345 else if (tmd.tmd1_bits & LE_T1_MORE)
346 /* Real number is unknown. */
347 ifp->if_collisions += 2;
348 ifp->if_opackets++;
349 }
350
351 if (++bix == sc->sc_ntbuf)
352 bix = 0;
353
354 --sc->sc_no_td;
355 }
356
357 sc->sc_first_td = bix;
358
359 am7990_start(ifp);
360
361 if (sc->sc_no_td == 0)
362 ifp->if_timer = 0;
363 }
364
365 /*
366 * Controller interrupt.
367 */
368 int
am7990_intr(void * arg)369 am7990_intr(void *arg)
370 {
371 struct lance_softc *sc = arg;
372 uint16_t isr;
373
374 isr = (*sc->sc_rdcsr)(sc, LE_CSR0) | sc->sc_saved_csr0;
375 sc->sc_saved_csr0 = 0;
376 #if defined(LEDEBUG) && LEDEBUG > 1
377 if (sc->sc_debug)
378 printf("%s: am7990_intr entering with isr=%04x\n",
379 device_xname(sc->sc_dev), isr);
380 #endif
381 if ((isr & LE_C0_INTR) == 0)
382 return (0);
383
384 #ifdef __vax__
385 /*
386 * DEC needs this write order to the registers, don't know
387 * the results on other arch's. Ragge 991029
388 */
389 isr &= ~LE_C0_INEA;
390 (*sc->sc_wrcsr)(sc, LE_CSR0, isr);
391 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA);
392 #else
393 (*sc->sc_wrcsr)(sc, LE_CSR0,
394 isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR |
395 LE_C0_RINT | LE_C0_TINT | LE_C0_IDON));
396 #endif
397 if (isr & LE_C0_ERR) {
398 if (isr & LE_C0_BABL) {
399 #ifdef LEDEBUG
400 printf("%s: babble\n", device_xname(sc->sc_dev));
401 #endif
402 ifp->if_oerrors++;
403 }
404 #if 0
405 if (isr & LE_C0_CERR) {
406 printf("%s: collision error\n",
407 device_xname(sc->sc_dev));
408 ifp->if_collisions++;
409 }
410 #endif
411 if (isr & LE_C0_MISS) {
412 #ifdef LEDEBUG
413 printf("%s: missed packet\n", device_xname(sc->sc_dev));
414 #endif
415 ifp->if_ierrors++;
416 }
417 if (isr & LE_C0_MERR) {
418 printf("%s: memory error\n", device_xname(sc->sc_dev));
419 lance_reset(sc);
420 return (1);
421 }
422 }
423
424 if ((isr & LE_C0_RXON) == 0) {
425 printf("%s: receiver disabled\n", device_xname(sc->sc_dev));
426 ifp->if_ierrors++;
427 lance_reset(sc);
428 return (1);
429 }
430 if ((isr & LE_C0_TXON) == 0) {
431 printf("%s: transmitter disabled\n", device_xname(sc->sc_dev));
432 ifp->if_oerrors++;
433 lance_reset(sc);
434 return (1);
435 }
436
437 /*
438 * Pretend we have carrier; if we don't this will be cleared
439 * shortly.
440 */
441 sc->sc_havecarrier = 1;
442
443 if (isr & LE_C0_RINT)
444 am7990_rint(sc);
445 if (isr & LE_C0_TINT)
446 am7990_tint(sc);
447
448 rnd_add_uint32(&sc->rnd_source, isr);
449
450 return (1);
451 }
452
453 #undef ifp
454
455 /*
456 * Setup output on interface.
457 * Get another datagram to send off of the interface queue, and map it to the
458 * interface before starting the output.
459 * Called only at splnet or interrupt level.
460 */
461 static void
am7990_start(struct ifnet * ifp)462 am7990_start(struct ifnet *ifp)
463 {
464 struct lance_softc *sc = ifp->if_softc;
465 int bix;
466 struct mbuf *m;
467 struct letmd tmd;
468 int rp;
469 int len;
470
471 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
472 return;
473
474 bix = sc->sc_last_td;
475
476 for (;;) {
477 rp = LE_TMDADDR(sc, bix);
478 (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd));
479
480 if (tmd.tmd1_bits & LE_T1_OWN) {
481 ifp->if_flags |= IFF_OACTIVE;
482 printf("missing buffer, no_td = %d, last_td = %d\n",
483 sc->sc_no_td, sc->sc_last_td);
484 }
485
486 IFQ_DEQUEUE(&ifp->if_snd, m);
487 if (m == 0)
488 break;
489
490 /*
491 * If BPF is listening on this interface, let it see the packet
492 * before we commit it to the wire.
493 */
494 bpf_mtap(ifp, m);
495
496 /*
497 * Copy the mbuf chain into the transmit buffer.
498 */
499 len = lance_put(sc, LE_TBUFADDR(sc, bix), m);
500
501 #ifdef LEDEBUG
502 if (len > ETHERMTU + sizeof(struct ether_header))
503 printf("packet length %d\n", len);
504 #endif
505
506 ifp->if_timer = 5;
507
508 /*
509 * Init transmit registers, and set transmit start flag.
510 */
511 tmd.tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP;
512 tmd.tmd2 = -len | LE_XMD2_ONES;
513 tmd.tmd3 = 0;
514
515 (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));
516
517 #ifdef LEDEBUG
518 if (sc->sc_debug > 1)
519 am7990_xmit_print(sc, sc->sc_last_td);
520 #endif
521
522 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
523
524 if (++bix == sc->sc_ntbuf)
525 bix = 0;
526
527 if (++sc->sc_no_td == sc->sc_ntbuf) {
528 ifp->if_flags |= IFF_OACTIVE;
529 break;
530 }
531
532 }
533
534 sc->sc_last_td = bix;
535 }
536
537 #ifdef LEDEBUG
538 static void
am7990_recv_print(struct lance_softc * sc,int no)539 am7990_recv_print(struct lance_softc *sc, int no)
540 {
541 struct lermd rmd;
542 uint16_t len;
543 struct ether_header eh;
544
545 (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd));
546 len = rmd.rmd3;
547 printf("%s: receive buffer %d, len = %d\n",
548 device_xname(sc->sc_dev), no, len);
549 printf("%s: status %04x\n", device_xname(sc->sc_dev),
550 (*sc->sc_rdcsr)(sc, LE_CSR0));
551 printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
552 device_xname(sc->sc_dev),
553 rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3);
554 if (len >= sizeof(eh)) {
555 (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
556 printf("%s: dst %s", device_xname(sc->sc_dev),
557 ether_sprintf(eh.ether_dhost));
558 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
559 ntohs(eh.ether_type));
560 }
561 }
562
563 static void
am7990_xmit_print(struct lance_softc * sc,int no)564 am7990_xmit_print(struct lance_softc *sc, int no)
565 {
566 struct letmd tmd;
567 uint16_t len;
568 struct ether_header eh;
569
570 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd));
571 len = -tmd.tmd2;
572 printf("%s: transmit buffer %d, len = %d\n",
573 device_xname(sc->sc_dev), no, len);
574 printf("%s: status %04x\n", device_xname(sc->sc_dev),
575 (*sc->sc_rdcsr)(sc, LE_CSR0));
576 printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
577 device_xname(sc->sc_dev),
578 tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3);
579 if (len >= sizeof(eh)) {
580 (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
581 printf("%s: dst %s", device_xname(sc->sc_dev),
582 ether_sprintf(eh.ether_dhost));
583 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
584 ntohs(eh.ether_type));
585 }
586 }
587 #endif /* LEDEBUG */
588