1 /* $NetBSD: am79900.c,v 1.17 2005/12/24 20:27:29 perry Exp $ */
2 /* $FreeBSD: src/sys/dev/le/am79900.c,v 1.3 2006/05/16 21:04:01 marius Exp $ */
3 /* $DragonFly: src/sys/dev/netif/lnc/am79900.c,v 1.4 2007/03/24 08:29:57 sephe Exp $ */
7 * Copyright (c) 1997 The NetBSD Foundation, Inc.
10 * This code is derived from software contributed to The NetBSD Foundation
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgement:
23 * This product includes software developed by the NetBSD
24 * Foundation, Inc. and its contributors.
25 * 4. Neither the name of The NetBSD Foundation nor the names of its
26 * contributors may be used to endorse or promote products derived
27 * from this software without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
30 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
31 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
33 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
35 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
36 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39 * POSSIBILITY OF SUCH DAMAGE.
43 * Copyright (c) 1992, 1993
44 * The Regents of the University of California. All rights reserved.
46 * This code is derived from software contributed to Berkeley by
47 * Ralph Campbell and Rick Macklem.
49 * Redistribution and use in source and binary forms, with or without
50 * modification, are permitted provided that the following conditions
52 * 1. Redistributions of source code must retain the above copyright
53 * notice, this list of conditions and the following disclaimer.
54 * 2. Redistributions in binary form must reproduce the above copyright
55 * notice, this list of conditions and the following disclaimer in the
56 * documentation and/or other materials provided with the distribution.
57 * 3. Neither the name of the University nor the names of its contributors
58 * may be used to endorse or promote products derived from this software
59 * without specific prior written permission.
61 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
62 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
63 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
65 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
66 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
67 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
68 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
69 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
70 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
73 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
78 * Matthias Drochner. All rights reserved.
79 * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
81 * This code is derived from software contributed to Berkeley by
82 * Ralph Campbell and Rick Macklem.
84 * Redistribution and use in source and binary forms, with or without
85 * modification, are permitted provided that the following conditions
87 * 1. Redistributions of source code must retain the above copyright
88 * notice, this list of conditions and the following disclaimer.
89 * 2. Redistributions in binary form must reproduce the above copyright
90 * notice, this list of conditions and the following disclaimer in the
91 * documentation and/or other materials provided with the distribution.
92 * 3. All advertising materials mentioning features or use of this software
93 * must display the following acknowledgement:
94 * This product includes software developed by the University of
95 * California, Berkeley and its contributors.
96 * 4. Neither the name of the University nor the names of its contributors
97 * may be used to endorse or promote products derived from this software
98 * without specific prior written permission.
100 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
101 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
102 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
103 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
104 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
105 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
106 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
107 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
108 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
109 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
112 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
115 #include <sys/param.h>
117 #include <sys/endian.h>
118 #include <sys/lock.h>
119 #include <sys/mbuf.h>
120 #include <sys/socket.h>
124 #include <net/ethernet.h>
126 #include <net/if_arp.h>
127 #include <net/if_dl.h>
128 #include <net/if_media.h>
129 #include <net/if_var.h>
130 #include <net/ifq_var.h>
132 #include <dev/netif/lnc/lancereg.h>
133 #include <dev/netif/lnc/lancevar.h>
134 #include <dev/netif/lnc/am79900reg.h>
135 #include <dev/netif/lnc/am79900var.h>
137 static void am79900_meminit(struct lance_softc
*);
138 static void am79900_rint(struct lance_softc
*);
139 static void am79900_tint(struct lance_softc
*);
140 static void am79900_start_locked(struct lance_softc
*sc
);
143 static void am79900_recv_print(struct lance_softc
*, int);
144 static void am79900_xmit_print(struct lance_softc
*, int);
148 am79900_config(struct am79900_softc
*sc
, const char* name
, int unit
)
152 sc
->lsc
.sc_meminit
= am79900_meminit
;
153 sc
->lsc
.sc_start_locked
= am79900_start_locked
;
155 error
= lance_config(&sc
->lsc
, name
, unit
);
160 sc
->lsc
.sc_initaddr
= mem
;
161 mem
+= sizeof(struct leinit
);
162 sc
->lsc
.sc_rmdaddr
= mem
;
163 mem
+= sizeof(struct lermd
) * sc
->lsc
.sc_nrbuf
;
164 sc
->lsc
.sc_tmdaddr
= mem
;
165 mem
+= sizeof(struct letmd
) * sc
->lsc
.sc_ntbuf
;
166 sc
->lsc
.sc_rbufaddr
= mem
;
167 mem
+= LEBLEN
* sc
->lsc
.sc_nrbuf
;
168 sc
->lsc
.sc_tbufaddr
= mem
;
169 mem
+= LEBLEN
* sc
->lsc
.sc_ntbuf
;
171 if (mem
> sc
->lsc
.sc_memsize
)
172 panic("%s: memsize", __func__
);
174 lance_attach(&sc
->lsc
);
180 am79900_detach(struct am79900_softc
*sc
)
183 ether_ifdetach(sc
->lsc
.ifp
);
187 * Set up the initialization block and the descriptor rings.
190 am79900_meminit(struct lance_softc
*sc
)
192 struct ifnet
*ifp
= sc
->ifp
;
199 if (ifp
->if_flags
& IFF_PROMISC
)
200 init
.init_mode
= LE_HTOLE32(LE_MODE_NORMAL
| LE_MODE_PROM
);
202 init
.init_mode
= LE_HTOLE32(LE_MODE_NORMAL
);
204 init
.init_mode
|= LE_HTOLE32(((ffs(sc
->sc_ntbuf
) - 1) << 28) |
205 ((ffs(sc
->sc_nrbuf
) - 1) << 20));
207 init
.init_padr
[0] = LE_HTOLE32(sc
->sc_enaddr
[0] |
208 (sc
->sc_enaddr
[1] << 8) | (sc
->sc_enaddr
[2] << 16) |
209 (sc
->sc_enaddr
[3] << 24));
210 init
.init_padr
[1] = LE_HTOLE32(sc
->sc_enaddr
[4] |
211 (sc
->sc_enaddr
[5] << 8));
212 lance_setladrf(sc
, init
.init_ladrf
);
215 sc
->sc_first_td
= sc
->sc_last_td
= sc
->sc_no_td
= 0;
217 a
= sc
->sc_addr
+ LE_RMDADDR(sc
, 0);
218 init
.init_rdra
= LE_HTOLE32(a
);
220 a
= sc
->sc_addr
+ LE_TMDADDR(sc
, 0);
221 init
.init_tdra
= LE_HTOLE32(a
);
223 (*sc
->sc_copytodesc
)(sc
, &init
, LE_INITADDR(sc
), sizeof(init
));
226 * Set up receive ring descriptors.
228 for (bix
= 0; bix
< sc
->sc_nrbuf
; bix
++) {
229 a
= sc
->sc_addr
+ LE_RBUFADDR(sc
, bix
);
230 rmd
.rmd0
= LE_HTOLE32(a
);
231 rmd
.rmd1
= LE_HTOLE32(LE_R1_OWN
| LE_R1_ONES
|
235 (*sc
->sc_copytodesc
)(sc
, &rmd
, LE_RMDADDR(sc
, bix
),
240 * Set up transmit ring descriptors.
242 for (bix
= 0; bix
< sc
->sc_ntbuf
; bix
++) {
243 a
= sc
->sc_addr
+ LE_TBUFADDR(sc
, bix
);
244 tmd
.tmd0
= LE_HTOLE32(a
);
245 tmd
.tmd1
= LE_HTOLE32(LE_T1_ONES
);
248 (*sc
->sc_copytodesc
)(sc
, &tmd
, LE_TMDADDR(sc
, bix
),
254 am79900_rint(struct lance_softc
*sc
)
256 struct ifnet
*ifp
= sc
->ifp
;
261 #if defined(__i386__) && !defined(PC98)
262 struct ether_header
*eh
;
265 bix
= sc
->sc_last_rd
;
267 /* Process all buffers with valid data. */
269 rp
= LE_RMDADDR(sc
, bix
);
270 (*sc
->sc_copyfromdesc
)(sc
, &rmd
, rp
, sizeof(rmd
));
272 rmd1
= LE_LE32TOH(rmd
.rmd1
);
273 if (rmd1
& LE_R1_OWN
)
277 if ((rmd1
& (LE_R1_ERR
| LE_R1_STP
| LE_R1_ENP
)) !=
278 (LE_R1_STP
| LE_R1_ENP
)){
279 if (rmd1
& LE_R1_ERR
) {
281 if (rmd1
& LE_R1_ENP
) {
282 if ((rmd1
& LE_R1_OFLO
) == 0) {
283 if (rmd1
& LE_R1_FRAM
)
286 if (rmd1
& LE_R1_CRC
)
291 if (rmd1
& LE_R1_OFLO
)
292 if_printf(ifp
, "overflow\n");
294 if (rmd1
& LE_R1_BUFF
)
296 "receive buffer error\n");
297 } else if ((rmd1
& (LE_R1_STP
| LE_R1_ENP
)) !=
298 (LE_R1_STP
| LE_R1_ENP
))
299 if_printf(ifp
, "dropping chained buffer\n");
302 if (sc
->sc_flags
& LE_DEBUG
)
303 am79900_recv_print(sc
, bix
);
305 /* Pull the packet off the interface. */
306 m
= lance_get(sc
, LE_RBUFADDR(sc
, bix
),
307 (LE_LE32TOH(rmd
.rmd2
) & 0xfff) - ETHER_CRC_LEN
);
310 rmd
.rmd1
= LE_HTOLE32(LE_R1_OWN
| LE_R1_ONES
|
314 (*sc
->sc_copytodesc
)(sc
, &rmd
, rp
, sizeof(rmd
));
316 if (++bix
== sc
->sc_nrbuf
)
324 * The VMware LANCE does not present IFF_SIMPLEX
325 * behavior on multicast packets. Thus drop the
326 * packet if it is from ourselves.
328 eh
= mtod(m
, struct ether_header
*);
329 if (memcmp(eh
->ether_shost
, sc
->sc_enaddr
,
330 ETHER_ADDR_LEN
) == 0) {
336 /* Pass the packet up. */
337 (*ifp
->if_input
)(ifp
, m
);
342 sc
->sc_last_rd
= bix
;
346 am79900_tint(struct lance_softc
*sc
)
348 struct ifnet
*ifp
= sc
->ifp
;
353 bix
= sc
->sc_first_td
;
356 if (sc
->sc_no_td
<= 0)
359 (*sc
->sc_copyfromdesc
)(sc
, &tmd
, LE_TMDADDR(sc
, bix
),
362 tmd1
= LE_LE32TOH(tmd
.tmd1
);
365 if (sc
->sc_flags
& LE_DEBUG
)
366 if_printf(ifp
, "trans tmd: "
367 "adr %08x, flags/blen %08x\n",
368 LE_LE32TOH(tmd
.tmd0
), tmd1
);
371 if (tmd1
& LE_T1_OWN
)
374 ifp
->if_flags
&= ~IFF_OACTIVE
;
376 if (tmd1
& LE_T1_ERR
) {
377 tmd2
= LE_LE32TOH(tmd
.tmd2
);
378 if (tmd2
& LE_T2_BUFF
)
379 if_printf(ifp
, "transmit buffer error\n");
380 else if (tmd2
& LE_T2_UFLO
)
381 if_printf(ifp
, "underflow\n");
382 if (tmd2
& (LE_T2_BUFF
| LE_T2_UFLO
)) {
383 lance_init_locked(sc
);
386 if (tmd2
& LE_T2_LCAR
) {
387 if (sc
->sc_flags
& LE_CARRIER
) {
388 ifp
->if_link_state
= LINK_STATE_DOWN
;
389 if_link_state_change(ifp
);
391 sc
->sc_flags
&= ~LE_CARRIER
;
392 if (sc
->sc_nocarrier
)
393 (*sc
->sc_nocarrier
)(sc
);
395 if_printf(ifp
, "lost carrier\n");
397 if (tmd2
& LE_T2_LCOL
)
398 ifp
->if_collisions
++;
399 if (tmd2
& LE_T2_RTRY
) {
401 if_printf(ifp
, "excessive collisions\n");
403 ifp
->if_collisions
+= 16;
407 if (tmd1
& LE_T1_ONE
)
408 ifp
->if_collisions
++;
409 else if (tmd1
& LE_T1_MORE
)
410 /* Real number is unknown. */
411 ifp
->if_collisions
+= 2;
415 if (++bix
== sc
->sc_ntbuf
)
421 sc
->sc_first_td
= bix
;
423 ifp
->if_timer
= sc
->sc_no_td
> 0 ? 5 : 0;
427 * Controller interrupt
430 am79900_intr(void *arg
)
432 struct lance_softc
*sc
= arg
;
433 struct ifnet
*ifp
= sc
->ifp
;
436 if (sc
->sc_hwintr
&& (*sc
->sc_hwintr
)(sc
) == -1) {
438 lance_init_locked(sc
);
442 isr
= (*sc
->sc_rdcsr
)(sc
, LE_CSR0
);
443 #if defined(LEDEBUG) && LEDEBUG > 1
444 if (sc
->sc_flags
& LE_DEBUG
)
445 if_printf(ifp
, "%s: entering with isr=%04x\n", __func__
, isr
);
447 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 turn off
456 * interrupts so we don't get another RX interrupt while still
457 * processing the previous one in ifp->if_input() with the
458 * driver lock dropped.
460 (*sc
->sc_wrcsr
)(sc
, LE_CSR0
, isr
& ~(LE_C0_INEA
| LE_C0_TDMD
|
461 LE_C0_STOP
| LE_C0_STRT
| LE_C0_INIT
));
463 if (isr
& LE_C0_ERR
) {
464 if (isr
& LE_C0_BABL
) {
466 if_printf(ifp
, "babble\n");
471 if (isr
& LE_C0_CERR
) {
472 if_printf(ifp
, "collision error\n");
473 ifp
->if_collisions
++;
476 if (isr
& LE_C0_MISS
) {
478 if_printf(ifp
, "missed packet\n");
482 if (isr
& LE_C0_MERR
) {
483 if_printf(ifp
, "memory error\n");
484 lance_init_locked(sc
);
489 if ((isr
& LE_C0_RXON
) == 0) {
490 if_printf(ifp
, "receiver disabled\n");
492 lance_init_locked(sc
);
495 if ((isr
& LE_C0_TXON
) == 0) {
496 if_printf(ifp
, "transmitter disabled\n");
498 lance_init_locked(sc
);
503 * Pretend we have carrier; if we don't this will be cleared shortly.
505 if (!(sc
->sc_flags
& LE_CARRIER
)) {
506 ifp
->if_link_state
= LINK_STATE_UP
;
507 if_link_state_change(ifp
);
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_is_empty(&ifp
->if_snd
))
520 am79900_start_locked(sc
);
525 * Set up output on interface.
526 * Get another datagram to send off of the interface queue, and map it to the
527 * interface before starting the output.
530 am79900_start_locked(struct lance_softc
*sc
)
532 struct ifnet
*ifp
= sc
->ifp
;
535 int bix
, enq
, len
, rp
;
537 if ((ifp
->if_flags
& (IFF_RUNNING
| IFF_OACTIVE
)) !=
541 bix
= sc
->sc_last_td
;
544 for (; sc
->sc_no_td
< sc
->sc_ntbuf
&&
545 !ifq_is_empty(&ifp
->if_snd
);) {
546 m
= ifq_poll(&ifp
->if_snd
);
547 rp
= LE_TMDADDR(sc
, bix
);
548 (*sc
->sc_copyfromdesc
)(sc
, &tmd
, rp
, sizeof(tmd
));
550 if (LE_LE32TOH(tmd
.tmd1
) & LE_T1_OWN
) {
551 ifp
->if_flags
|= IFF_OACTIVE
;
553 "missing buffer, no_td = %d, last_td = %d\n",
554 sc
->sc_no_td
, sc
->sc_last_td
);
557 ifq_dequeue(&ifp
->if_snd
, m
);
562 * If BPF is listening on this interface, let it see the packet
563 * before we commit it to the wire.
568 * Copy the mbuf chain into the transmit buffer.
570 len
= lance_put(sc
, LE_TBUFADDR(sc
, bix
), m
);
573 if (len
> ETHERMTU
+ ETHER_HDR_LEN
)
574 if_printf(ifp
, "packet length %d\n", len
);
578 * Init transmit registers, and set transmit start flag.
580 tmd
.tmd1
= LE_HTOLE32(LE_T1_OWN
| LE_T1_STP
| LE_T1_ENP
|
581 LE_T1_ONES
| (-len
& 0xfff));
585 (*sc
->sc_copytodesc
)(sc
, &tmd
, rp
, sizeof(tmd
));
588 if (sc
->sc_flags
& LE_DEBUG
)
589 am79900_xmit_print(sc
, bix
);
592 (*sc
->sc_wrcsr
)(sc
, LE_CSR0
, LE_C0_INEA
| LE_C0_TDMD
);
595 if (++bix
== sc
->sc_ntbuf
)
598 if (++sc
->sc_no_td
== sc
->sc_ntbuf
) {
599 ifp
->if_flags
|= IFF_OACTIVE
;
604 sc
->sc_last_td
= bix
;
612 am79900_recv_print(struct lance_softc
*sc
, int no
)
614 struct ifnet
*ifp
= sc
->ifp
;
615 struct ether_header eh
;
619 (*sc
->sc_copyfromdesc
)(sc
, &rmd
, LE_RMDADDR(sc
, no
), sizeof(rmd
));
620 len
= LE_LE32TOH(rmd
.rmd2
) & 0xfff;
621 if_printf(ifp
, "receive buffer %d, len = %d\n", no
, len
);
622 if_printf(ifp
, "status %04x\n", (*sc
->sc_rdcsr
)(sc
, LE_CSR0
));
623 if_printf(ifp
, "adr %08x, flags/blen %08x\n", LE_LE32TOH(rmd
.rmd0
),
624 LE_LE32TOH(rmd
.rmd1
));
625 if (len
- ETHER_CRC_LEN
>= sizeof(eh
)) {
626 (*sc
->sc_copyfrombuf
)(sc
, &eh
, LE_RBUFADDR(sc
, no
), sizeof(eh
));
627 if_printf(ifp
, "dst %s", ether_sprintf(eh
.ether_dhost
));
628 kprintf(" src %s type %04x\n", ether_sprintf(eh
.ether_shost
),
629 ntohs(eh
.ether_type
));
634 am79900_xmit_print(struct lance_softc
*sc
, int no
)
636 struct ifnet
*ifp
= sc
->ifp
;
637 struct ether_header eh
;
641 (*sc
->sc_copyfromdesc
)(sc
, &tmd
, LE_TMDADDR(sc
, no
), sizeof(tmd
));
642 len
= -(LE_LE32TOH(tmd
.tmd1
) & 0xfff);
643 if_printf(ifp
, "transmit buffer %d, len = %d\n", no
, len
);
644 if_printf(ifp
, "status %04x\n", (*sc
->sc_rdcsr
)(sc
, LE_CSR0
));
645 if_printf(ifp
, "adr %08x, flags/blen %08x\n", LE_LE32TOH(tmd
.tmd0
),
646 LE_LE32TOH(tmd
.tmd1
));
647 if (len
>= sizeof(eh
)) {
648 (*sc
->sc_copyfrombuf
)(sc
, &eh
, LE_TBUFADDR(sc
, no
), sizeof(eh
));
649 if_printf(ifp
, "dst %s", ether_sprintf(eh
.ether_dhost
));
650 kprintf(" src %s type %04x\n", ether_sprintf(eh
.ether_shost
),
651 ntohs(eh
.ether_type
));