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.5 2008/05/14 11:59:20 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
))
524 * Set up output on interface.
525 * Get another datagram to send off of the interface queue, and map it to the
526 * interface before starting the output.
529 am79900_start_locked(struct lance_softc
*sc
)
531 struct ifnet
*ifp
= sc
->ifp
;
534 int bix
, enq
, len
, rp
;
536 if ((ifp
->if_flags
& (IFF_RUNNING
| IFF_OACTIVE
)) !=
540 bix
= sc
->sc_last_td
;
543 for (; sc
->sc_no_td
< sc
->sc_ntbuf
&&
544 !ifq_is_empty(&ifp
->if_snd
);) {
545 rp
= LE_TMDADDR(sc
, bix
);
546 (*sc
->sc_copyfromdesc
)(sc
, &tmd
, rp
, sizeof(tmd
));
548 if (LE_LE32TOH(tmd
.tmd1
) & LE_T1_OWN
) {
549 ifp
->if_flags
|= IFF_OACTIVE
;
551 "missing buffer, no_td = %d, last_td = %d\n",
552 sc
->sc_no_td
, sc
->sc_last_td
);
555 m
= ifq_dequeue(&ifp
->if_snd
, NULL
);
560 * If BPF is listening on this interface, let it see the packet
561 * before we commit it to the wire.
566 * Copy the mbuf chain into the transmit buffer.
568 len
= lance_put(sc
, LE_TBUFADDR(sc
, bix
), m
);
571 if (len
> ETHERMTU
+ ETHER_HDR_LEN
)
572 if_printf(ifp
, "packet length %d\n", len
);
576 * Init transmit registers, and set transmit start flag.
578 tmd
.tmd1
= LE_HTOLE32(LE_T1_OWN
| LE_T1_STP
| LE_T1_ENP
|
579 LE_T1_ONES
| (-len
& 0xfff));
583 (*sc
->sc_copytodesc
)(sc
, &tmd
, rp
, sizeof(tmd
));
586 if (sc
->sc_flags
& LE_DEBUG
)
587 am79900_xmit_print(sc
, bix
);
590 (*sc
->sc_wrcsr
)(sc
, LE_CSR0
, LE_C0_INEA
| LE_C0_TDMD
);
593 if (++bix
== sc
->sc_ntbuf
)
596 if (++sc
->sc_no_td
== sc
->sc_ntbuf
) {
597 ifp
->if_flags
|= IFF_OACTIVE
;
602 sc
->sc_last_td
= bix
;
610 am79900_recv_print(struct lance_softc
*sc
, int no
)
612 struct ifnet
*ifp
= sc
->ifp
;
613 struct ether_header eh
;
617 (*sc
->sc_copyfromdesc
)(sc
, &rmd
, LE_RMDADDR(sc
, no
), sizeof(rmd
));
618 len
= LE_LE32TOH(rmd
.rmd2
) & 0xfff;
619 if_printf(ifp
, "receive buffer %d, len = %d\n", no
, len
);
620 if_printf(ifp
, "status %04x\n", (*sc
->sc_rdcsr
)(sc
, LE_CSR0
));
621 if_printf(ifp
, "adr %08x, flags/blen %08x\n", LE_LE32TOH(rmd
.rmd0
),
622 LE_LE32TOH(rmd
.rmd1
));
623 if (len
- ETHER_CRC_LEN
>= sizeof(eh
)) {
624 (*sc
->sc_copyfrombuf
)(sc
, &eh
, LE_RBUFADDR(sc
, no
), sizeof(eh
));
625 if_printf(ifp
, "dst %s", ether_sprintf(eh
.ether_dhost
));
626 kprintf(" src %s type %04x\n", ether_sprintf(eh
.ether_shost
),
627 ntohs(eh
.ether_type
));
632 am79900_xmit_print(struct lance_softc
*sc
, int no
)
634 struct ifnet
*ifp
= sc
->ifp
;
635 struct ether_header eh
;
639 (*sc
->sc_copyfromdesc
)(sc
, &tmd
, LE_TMDADDR(sc
, no
), sizeof(tmd
));
640 len
= -(LE_LE32TOH(tmd
.tmd1
) & 0xfff);
641 if_printf(ifp
, "transmit buffer %d, len = %d\n", no
, len
);
642 if_printf(ifp
, "status %04x\n", (*sc
->sc_rdcsr
)(sc
, LE_CSR0
));
643 if_printf(ifp
, "adr %08x, flags/blen %08x\n", LE_LE32TOH(tmd
.tmd0
),
644 LE_LE32TOH(tmd
.tmd1
));
645 if (len
>= sizeof(eh
)) {
646 (*sc
->sc_copyfrombuf
)(sc
, &eh
, LE_TBUFADDR(sc
, no
), sizeof(eh
));
647 if_printf(ifp
, "dst %s", ether_sprintf(eh
.ether_dhost
));
648 kprintf(" src %s type %04x\n", ether_sprintf(eh
.ether_shost
),
649 ntohs(eh
.ether_type
));