1 /* $NetBSD: am79900.c,v 1.17 2005/12/24 20:27:29 perry Exp $ */
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 1992, 1993
34 * The Regents of the University of California. All rights reserved.
36 * This code is derived from software contributed to Berkeley by
37 * Ralph Campbell and Rick Macklem.
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
68 * Matthias Drochner. All rights reserved.
69 * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
71 * This code is derived from software contributed to Berkeley by
72 * Ralph Campbell and Rick Macklem.
74 * Redistribution and use in source and binary forms, with or without
75 * modification, are permitted provided that the following conditions
77 * 1. Redistributions of source code must retain the above copyright
78 * notice, this list of conditions and the following disclaimer.
79 * 2. Redistributions in binary form must reproduce the above copyright
80 * notice, this list of conditions and the following disclaimer in the
81 * documentation and/or other materials provided with the distribution.
82 * 3. All advertising materials mentioning features or use of this software
83 * must display the following acknowledgement:
84 * This product includes software developed by the University of
85 * California, Berkeley and its contributors.
86 * 4. Neither the name of the University nor the names of its contributors
87 * may be used to endorse or promote products derived from this software
88 * without specific prior written permission.
90 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
91 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
92 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
93 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
94 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
95 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
96 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
97 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
98 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
99 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
102 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
105 #include <sys/cdefs.h>
106 __FBSDID("$FreeBSD$");
108 #include <sys/param.h>
110 #include <sys/endian.h>
111 #include <sys/lock.h>
112 #include <sys/mbuf.h>
113 #include <sys/mutex.h>
114 #include <sys/socket.h>
117 #include <net/ethernet.h>
119 #include <net/if_arp.h>
120 #include <net/if_dl.h>
121 #include <net/if_media.h>
122 #include <net/if_var.h>
124 #include <machine/bus.h>
126 #include <dev/le/lancereg.h>
127 #include <dev/le/lancevar.h>
128 #include <dev/le/am79900reg.h>
129 #include <dev/le/am79900var.h>
131 static void am79900_meminit(struct lance_softc *);
132 static void am79900_rint(struct lance_softc *);
133 static void am79900_tint(struct lance_softc *);
134 static void am79900_start_locked(struct lance_softc *sc);
137 static void am79900_recv_print(struct lance_softc *, int);
138 static void am79900_xmit_print(struct lance_softc *, int);
142 am79900_config(struct am79900_softc *sc, const char* name, int unit)
146 sc->lsc.sc_meminit = am79900_meminit;
147 sc->lsc.sc_start_locked = am79900_start_locked;
149 error = lance_config(&sc->lsc, name, unit);
154 sc->lsc.sc_initaddr = mem;
155 mem += sizeof(struct leinit);
156 sc->lsc.sc_rmdaddr = mem;
157 mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf;
158 sc->lsc.sc_tmdaddr = mem;
159 mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf;
160 sc->lsc.sc_rbufaddr = mem;
161 mem += LEBLEN * sc->lsc.sc_nrbuf;
162 sc->lsc.sc_tbufaddr = mem;
163 mem += LEBLEN * sc->lsc.sc_ntbuf;
165 if (mem > sc->lsc.sc_memsize)
166 panic("%s: memsize", __func__);
168 lance_attach(&sc->lsc);
174 am79900_detach(struct am79900_softc *sc)
177 lance_detach(&sc->lsc);
181 * Set up the initialization block and the descriptor rings.
184 am79900_meminit(struct lance_softc *sc)
186 struct ifnet *ifp = sc->sc_ifp;
193 LE_LOCK_ASSERT(sc, MA_OWNED);
195 if (ifp->if_flags & IFF_PROMISC)
196 init.init_mode = LE_HTOLE32(LE_MODE_NORMAL | LE_MODE_PROM);
198 init.init_mode = LE_HTOLE32(LE_MODE_NORMAL);
200 init.init_mode |= LE_HTOLE32(((ffs(sc->sc_ntbuf) - 1) << 28) |
201 ((ffs(sc->sc_nrbuf) - 1) << 20));
203 init.init_padr[0] = LE_HTOLE32(sc->sc_enaddr[0] |
204 (sc->sc_enaddr[1] << 8) | (sc->sc_enaddr[2] << 16) |
205 (sc->sc_enaddr[3] << 24));
206 init.init_padr[1] = LE_HTOLE32(sc->sc_enaddr[4] |
207 (sc->sc_enaddr[5] << 8));
208 lance_setladrf(sc, init.init_ladrf);
211 sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
213 a = sc->sc_addr + LE_RMDADDR(sc, 0);
214 init.init_rdra = LE_HTOLE32(a);
216 a = sc->sc_addr + LE_TMDADDR(sc, 0);
217 init.init_tdra = LE_HTOLE32(a);
219 (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init));
222 * Set up receive ring descriptors.
224 for (bix = 0; bix < sc->sc_nrbuf; bix++) {
225 a = sc->sc_addr + LE_RBUFADDR(sc, bix);
226 rmd.rmd0 = LE_HTOLE32(a);
227 rmd.rmd1 = LE_HTOLE32(LE_R1_OWN | LE_R1_ONES |
231 (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix),
236 * Set up transmit ring descriptors.
238 for (bix = 0; bix < sc->sc_ntbuf; bix++) {
239 a = sc->sc_addr + LE_TBUFADDR(sc, bix);
240 tmd.tmd0 = LE_HTOLE32(a);
241 tmd.tmd1 = LE_HTOLE32(LE_T1_ONES);
244 (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix),
250 am79900_rint(struct lance_softc *sc)
252 struct ifnet *ifp = sc->sc_ifp;
257 #if defined(__i386__) && !defined(PC98)
258 struct ether_header *eh;
261 bix = sc->sc_last_rd;
263 /* Process all buffers with valid data. */
265 rp = LE_RMDADDR(sc, bix);
266 (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));
268 rmd1 = LE_LE32TOH(rmd.rmd1);
269 if (rmd1 & LE_R1_OWN)
273 if ((rmd1 & (LE_R1_ERR | LE_R1_STP | LE_R1_ENP)) !=
274 (LE_R1_STP | LE_R1_ENP)){
275 if (rmd1 & LE_R1_ERR) {
277 if (rmd1 & LE_R1_ENP) {
278 if ((rmd1 & LE_R1_OFLO) == 0) {
279 if (rmd1 & LE_R1_FRAM)
282 if (rmd1 & LE_R1_CRC)
287 if (rmd1 & LE_R1_OFLO)
288 if_printf(ifp, "overflow\n");
290 if (rmd1 & LE_R1_BUFF)
292 "receive buffer error\n");
293 } else if ((rmd1 & (LE_R1_STP | LE_R1_ENP)) !=
294 (LE_R1_STP | LE_R1_ENP))
295 if_printf(ifp, "dropping chained buffer\n");
298 if (sc->sc_flags & LE_DEBUG)
299 am79900_recv_print(sc, bix);
301 /* Pull the packet off the interface. */
302 m = lance_get(sc, LE_RBUFADDR(sc, bix),
303 (LE_LE32TOH(rmd.rmd2) & 0xfff) - ETHER_CRC_LEN);
306 rmd.rmd1 = LE_HTOLE32(LE_R1_OWN | LE_R1_ONES |
310 (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
312 if (++bix == sc->sc_nrbuf)
318 #if defined(__i386__) && !defined(PC98)
320 * The VMware LANCE does not present IFF_SIMPLEX
321 * behavior on multicast packets. Thus drop the
322 * packet if it is from ourselves.
324 eh = mtod(m, struct ether_header *);
325 if (!ether_cmp(eh->ether_shost, sc->sc_enaddr)) {
331 /* Pass the packet up. */
333 (*ifp->if_input)(ifp, m);
339 sc->sc_last_rd = bix;
343 am79900_tint(struct lance_softc *sc)
345 struct ifnet *ifp = sc->sc_ifp;
350 bix = sc->sc_first_td;
353 if (sc->sc_no_td <= 0)
356 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
359 tmd1 = LE_LE32TOH(tmd.tmd1);
362 if (sc->sc_flags & LE_DEBUG)
363 if_printf(ifp, "trans tmd: "
364 "adr %08x, flags/blen %08x\n",
365 LE_LE32TOH(tmd.tmd0), tmd1);
368 if (tmd1 & LE_T1_OWN)
371 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
373 if (tmd1 & LE_T1_ERR) {
374 tmd2 = LE_LE32TOH(tmd.tmd2);
375 if (tmd2 & LE_T2_BUFF)
376 if_printf(ifp, "transmit buffer error\n");
377 else if (tmd2 & LE_T2_UFLO)
378 if_printf(ifp, "underflow\n");
379 if (tmd2 & (LE_T2_BUFF | LE_T2_UFLO)) {
380 lance_init_locked(sc);
383 if (tmd2 & LE_T2_LCAR) {
384 if (sc->sc_flags & LE_CARRIER)
385 if_link_state_change(ifp,
387 sc->sc_flags &= ~LE_CARRIER;
388 if (sc->sc_nocarrier)
389 (*sc->sc_nocarrier)(sc);
391 if_printf(ifp, "lost carrier\n");
393 if (tmd2 & LE_T2_LCOL)
394 ifp->if_collisions++;
395 if (tmd2 & LE_T2_RTRY) {
397 if_printf(ifp, "excessive collisions\n");
399 ifp->if_collisions += 16;
403 if (tmd1 & LE_T1_ONE)
404 ifp->if_collisions++;
405 else if (tmd1 & LE_T1_MORE)
406 /* Real number is unknown. */
407 ifp->if_collisions += 2;
411 if (++bix == sc->sc_ntbuf)
417 sc->sc_first_td = bix;
419 sc->sc_wdog_timer = sc->sc_no_td > 0 ? 5 : 0;
423 * Controller interrupt
426 am79900_intr(void *arg)
428 struct lance_softc *sc = arg;
429 struct ifnet *ifp = sc->sc_ifp;
434 if (sc->sc_hwintr && (*sc->sc_hwintr)(sc) == -1) {
436 lance_init_locked(sc);
441 isr = (*sc->sc_rdcsr)(sc, LE_CSR0);
442 #if defined(LEDEBUG) && LEDEBUG > 1
443 if (sc->sc_flags & LE_DEBUG)
444 if_printf(ifp, "%s: entering with isr=%04x\n", __func__, isr);
446 if ((isr & LE_C0_INTR) == 0) {
452 * Clear interrupt source flags and turn off interrupts. If we
453 * don't clear these flags before processing their sources we
454 * could completely miss some interrupt events as the NIC can
455 * change these flags while we're in this handler. We toggle
456 * the interrupt enable bit in order to keep receiving them
457 * (some chips work without this, some don't).
459 (*sc->sc_wrcsr)(sc, LE_CSR0, isr & ~(LE_C0_INEA | LE_C0_TDMD |
460 LE_C0_STOP | LE_C0_STRT | LE_C0_INIT));
462 if (isr & LE_C0_ERR) {
463 if (isr & LE_C0_BABL) {
465 if_printf(ifp, "babble\n");
470 if (isr & LE_C0_CERR) {
471 if_printf(ifp, "collision error\n");
472 ifp->if_collisions++;
475 if (isr & LE_C0_MISS) {
477 if_printf(ifp, "missed packet\n");
481 if (isr & LE_C0_MERR) {
482 if_printf(ifp, "memory error\n");
483 lance_init_locked(sc);
489 if ((isr & LE_C0_RXON) == 0) {
490 if_printf(ifp, "receiver disabled\n");
492 lance_init_locked(sc);
496 if ((isr & LE_C0_TXON) == 0) {
497 if_printf(ifp, "transmitter disabled\n");
499 lance_init_locked(sc);
505 * Pretend we have carrier; if we don't this will be cleared shortly.
507 if (!(sc->sc_flags & LE_CARRIER))
508 if_link_state_change(ifp, LINK_STATE_UP);
509 sc->sc_flags |= LE_CARRIER;
511 if (isr & LE_C0_RINT)
513 if (isr & LE_C0_TINT)
516 /* Enable interrupts again. */
517 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA);
519 if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
520 am79900_start_locked(sc);
526 * Set up output on interface.
527 * Get another datagram to send off of the interface queue, and map it to the
528 * interface before starting the output.
531 am79900_start_locked(struct lance_softc *sc)
533 struct ifnet *ifp = sc->sc_ifp;
536 int bix, enq, len, rp;
538 LE_LOCK_ASSERT(sc, MA_OWNED);
540 if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
544 bix = sc->sc_last_td;
547 for (; sc->sc_no_td < sc->sc_ntbuf &&
548 !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) {
549 rp = LE_TMDADDR(sc, bix);
550 (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd));
552 if (LE_LE32TOH(tmd.tmd1) & LE_T1_OWN) {
553 ifp->if_drv_flags |= IFF_DRV_OACTIVE;
555 "missing buffer, no_td = %d, last_td = %d\n",
556 sc->sc_no_td, sc->sc_last_td);
559 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
564 * If BPF is listening on this interface, let it see the packet
565 * before we commit it to the wire.
570 * Copy the mbuf chain into the transmit buffer.
572 len = lance_put(sc, LE_TBUFADDR(sc, bix), m);
575 if (len > ETHERMTU + ETHER_HDR_LEN)
576 if_printf(ifp, "packet length %d\n", len);
580 * Init transmit registers, and set transmit start flag.
582 tmd.tmd1 = LE_HTOLE32(LE_T1_OWN | LE_T1_STP | LE_T1_ENP |
583 LE_T1_ONES | (-len & 0xfff));
587 (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));
590 if (sc->sc_flags & LE_DEBUG)
591 am79900_xmit_print(sc, bix);
594 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
597 if (++bix == sc->sc_ntbuf)
600 if (++sc->sc_no_td == sc->sc_ntbuf) {
601 ifp->if_drv_flags |= IFF_DRV_OACTIVE;
606 sc->sc_last_td = bix;
609 sc->sc_wdog_timer = 5;
614 am79900_recv_print(struct lance_softc *sc, int no)
616 struct ifnet *ifp = sc->sc_ifp;
617 struct ether_header eh;
621 (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd));
622 len = LE_LE32TOH(rmd.rmd2) & 0xfff;
623 if_printf(ifp, "receive buffer %d, len = %d\n", no, len);
624 if_printf(ifp, "status %04x\n", (*sc->sc_rdcsr)(sc, LE_CSR0));
625 if_printf(ifp, "adr %08x, flags/blen %08x\n", LE_LE32TOH(rmd.rmd0),
626 LE_LE32TOH(rmd.rmd1));
627 if (len - ETHER_CRC_LEN >= sizeof(eh)) {
628 (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
629 if_printf(ifp, "dst %s", ether_sprintf(eh.ether_dhost));
630 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
631 ntohs(eh.ether_type));
636 am79900_xmit_print(struct lance_softc *sc, int no)
638 struct ifnet *ifp = sc->sc_ifp;
639 struct ether_header eh;
643 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd));
644 len = -(LE_LE32TOH(tmd.tmd1) & 0xfff);
645 if_printf(ifp, "transmit buffer %d, len = %d\n", no, len);
646 if_printf(ifp, "status %04x\n", (*sc->sc_rdcsr)(sc, LE_CSR0));
647 if_printf(ifp, "adr %08x, flags/blen %08x\n", LE_LE32TOH(tmd.tmd0),
648 LE_LE32TOH(tmd.tmd1));
649 if (len >= sizeof(eh)) {
650 (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
651 if_printf(ifp, "dst %s", ether_sprintf(eh.ether_dhost));
652 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
653 ntohs(eh.ether_type));