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