summaryrefslogtreecommitdiffstats
path: root/sys/alpha/tc/am7990.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/alpha/tc/am7990.c')
-rw-r--r--sys/alpha/tc/am7990.c1441
1 files changed, 0 insertions, 1441 deletions
diff --git a/sys/alpha/tc/am7990.c b/sys/alpha/tc/am7990.c
deleted file mode 100644
index bbb7c06..0000000
--- a/sys/alpha/tc/am7990.c
+++ /dev/null
@@ -1,1441 +0,0 @@
-/* $FreeBSD$ */
-/* $NetBSD: am7990.c,v 1.43 1998/03/29 22:36:42 mycroft Exp $ */
-
-/*-
- * Copyright (c) 1997 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * This code is derived from software contributed to The NetBSD Foundation
- * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
- * NASA Ames Research Center.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the NetBSD
- * Foundation, Inc. and its contributors.
- * 4. Neither the name of The NetBSD Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*-
- * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ralph Campbell and Rick Macklem.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)if_le.c 8.2 (Berkeley) 11/16/93
- */
-
-#include "opt_inet.h"
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/module.h>
-#include <sys/bus.h>
-#include <sys/mbuf.h>
-#include <sys/syslog.h>
-#include <sys/socket.h>
-#include <sys/malloc.h>
-#include <sys/sockio.h>
-#include <net/if.h>
-#include <net/netisr.h>
-
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/in_var.h>
-#include <netinet/ip.h>
-#include <netinet/if_ether.h>
-#include <net/if_media.h>
-
-#ifdef INET
-#include <netinet/in.h>
-#endif
-#include <net/bpf.h>
-#include <net/ethernet.h>
-#include <net/if_arp.h>
-
-#include <machine/clock.h>
-
-#include <alpha/tc/am7990reg.h>
-#include <alpha/tc/am7990var.h>
-
-#ifdef LEDEBUG
-void am7990_recv_print(struct am7990_softc *, int);
-void am7990_xmit_print(struct am7990_softc *, int);
-#endif
-
-integrate void am7990_rint(struct am7990_softc *);
-integrate void am7990_tint(struct am7990_softc *);
-
-integrate int am7990_put(struct am7990_softc *, int, struct mbuf *);
-integrate struct mbuf *am7990_get(struct am7990_softc *, int, int);
-integrate void am7990_read(struct am7990_softc *, int, int);
-
-/*
-hide void am7990_shutdown(void *);
-*/
-
-int am7990_mediachange(struct ifnet *);
-void am7990_mediastatus(struct ifnet *, struct ifmediareq *);
-
-#define ifp (&sc->sc_ethercom.ac_if)
-
-static __inline u_int16_t ether_cmp(void *, void *);
- char * ether_sprintf(u_char *ap);
-/*
- * Compare two Ether/802 addresses for equality, inlined and
- * unrolled for speed. Use this like bcmp().
- *
- * XXX: Add <machine/inlines.h> for stuff like this?
- * XXX: or maybe add it to libkern.h instead?
- *
- * "I'd love to have an inline assembler version of this."
- * XXX: Who wanted that? mycroft? I wrote one, but this
- * version in C is as good as hand-coded assembly. -gwr
- *
- * Please do NOT tweak this without looking at the actual
- * assembly code generated before and after your tweaks!
- */
-static __inline u_int16_t
-ether_cmp(one, two)
- void *one, *two;
-{
- register u_int16_t *a = (u_short *) one;
- register u_int16_t *b = (u_short *) two;
- register u_int16_t diff;
-
-#ifdef m68k
- /*
- * The post-increment-pointer form produces the best
- * machine code for m68k. This was carefully tuned
- * so it compiles to just 8 short (2-byte) op-codes!
- */
- diff = *a++ - *b++;
- diff |= *a++ - *b++;
- diff |= *a++ - *b++;
-#else
- /*
- * Most modern CPUs do better with a single expresion.
- * Note that short-cut evaluation is NOT helpful here,
- * because it just makes the code longer, not faster!
- */
- diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
-#endif
-
- return (diff);
-}
-
-#define ETHER_CMP ether_cmp
-
-#ifdef LANCE_REVC_BUG
-/* Make sure this is short-aligned, for ether_cmp(). */
-static u_int16_t bcast_enaddr[3] = { ~0, ~0, ~0 };
-#endif
-
-void
-am7990_config(sc)
- struct am7990_softc *sc;
-{
- int mem, i;
-
- /* Make sure the chip is stopped. */
- am7990_stop(sc);
-
- /* Initialize ifnet structure. */
- ifp->if_unit = sc->unit;
- ifp->if_name = "le";
- ifp->if_softc = sc;
- ifp->if_start = am7990_start;
- ifp->if_ioctl = am7990_ioctl;
- ifp->if_output = ether_output;
- ifp->if_watchdog = am7990_watchdog;
- ifp->if_flags =
- IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
-#ifdef LANCE_REVC_BUG
- ifp->if_flags &= ~IFF_MULTICAST;
-#endif
-
- /* Initialize ifmedia structures. */
- ifmedia_init(&sc->sc_media, 0, am7990_mediachange, am7990_mediastatus);
- if (sc->sc_supmedia != NULL) {
- for (i = 0; i < sc->sc_nsupmedia; i++)
- ifmedia_add(&sc->sc_media, sc->sc_supmedia[i],
- 0, NULL);
- ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);
- } else {
- ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
- ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
- }
-
- /* Attach the interface. */
- bcopy(sc->sc_enaddr,((struct arpcom *)ifp)->ac_enaddr, 6);
- printf("%s: address %s\n", device_get_nameunit(sc->sc_dev),
- ether_sprintf(sc->sc_enaddr));
-
- ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
-
- switch (sc->sc_memsize) {
- case 8192:
- sc->sc_nrbuf = 4;
- sc->sc_ntbuf = 1;
- break;
- case 16384:
- sc->sc_nrbuf = 8;
- sc->sc_ntbuf = 2;
- break;
- case 32768:
- sc->sc_nrbuf = 16;
- sc->sc_ntbuf = 4;
- break;
- case 65536:
- sc->sc_nrbuf = 32;
- sc->sc_ntbuf = 8;
- break;
- case 131072:
- sc->sc_nrbuf = 64;
- sc->sc_ntbuf = 16;
- break;
- default:
- panic("am7990_config: weird memory size");
- }
-
- printf("%s: %d receive buffers, %d transmit buffers\n",
- device_get_nameunit(sc->sc_dev), sc->sc_nrbuf, sc->sc_ntbuf);
-
-/*
- sc->sc_sh = shutdownhook_establish(am7990_shutdown, sc);
- if (sc->sc_sh == NULL)
- panic("am7990_config: can't establish shutdownhook");
-*/
- sc->sc_rbufaddr = malloc(sc->sc_nrbuf * sizeof(int), M_DEVBUF,
- M_WAITOK);
- sc->sc_tbufaddr = malloc(sc->sc_ntbuf * sizeof(int), M_DEVBUF,
- M_WAITOK);
-
- mem = 0;
- sc->sc_initaddr = mem;
- mem += sizeof(struct leinit);
- sc->sc_rmdaddr = mem;
- mem += sizeof(struct lermd) * sc->sc_nrbuf;
- sc->sc_tmdaddr = mem;
- mem += sizeof(struct letmd) * sc->sc_ntbuf;
- for (i = 0; i < sc->sc_nrbuf; i++, mem += LEBLEN)
- sc->sc_rbufaddr[i] = mem;
- for (i = 0; i < sc->sc_ntbuf; i++, mem += LEBLEN)
- sc->sc_tbufaddr[i] = mem;
-#ifdef notyet
- if (mem > ...)
- panic(...);
-#endif
-
-#if NRND > 0
- rnd_attach_source(&sc->rnd_source, device_get_nameunit(sc->sc_dev),
- RND_TYPE_NET);
-#endif
-}
-
-void
-am7990_reset(sc)
- struct am7990_softc *sc;
-{
- int s;
-
- s = splimp();
- am7990_init(sc);
- splx(s);
-}
-
-/*
- * Set up the initialization block and the descriptor rings.
- */
-void
-am7990_meminit(sc)
- register struct am7990_softc *sc;
-{
- u_long a;
- int bix;
- struct leinit init;
- struct lermd rmd;
- struct letmd tmd;
- u_int8_t *myaddr;
-
- if (ifp->if_flags & IFF_PROMISC)
- init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM;
- else
- init.init_mode = LE_MODE_NORMAL;
- if (sc->sc_initmodemedia == 1)
- init.init_mode |= LE_MODE_PSEL0;
-
- /*
- * Update our private copy of the Ethernet address.
- * We NEED the copy so we can ensure its alignment!
- */
- bcopy(((struct arpcom *)ifp)->ac_enaddr, sc->sc_enaddr, 6);
- myaddr = sc->sc_enaddr;
-
- init.init_padr[0] = (myaddr[1] << 8) | myaddr[0];
- init.init_padr[1] = (myaddr[3] << 8) | myaddr[2];
- init.init_padr[2] = (myaddr[5] << 8) | myaddr[4];
- am7990_setladrf(&sc->sc_ethercom, init.init_ladrf);
-
- sc->sc_last_rd = 0;
- sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
-
- a = sc->sc_addr + LE_RMDADDR(sc, 0);
- init.init_rdra = a;
- init.init_rlen = (a >> 16) | ((ffs(sc->sc_nrbuf) - 1) << 13);
-
- a = sc->sc_addr + LE_TMDADDR(sc, 0);
- init.init_tdra = a;
- init.init_tlen = (a >> 16) | ((ffs(sc->sc_ntbuf) - 1) << 13);
-
- (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init));
-
- /*
- * Set up receive ring descriptors.
- */
- for (bix = 0; bix < sc->sc_nrbuf; bix++) {
- a = sc->sc_addr + LE_RBUFADDR(sc, bix);
- rmd.rmd0 = a;
- rmd.rmd1_hadr = a >> 16;
- rmd.rmd1_bits = LE_R1_OWN;
- rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
- rmd.rmd3 = 0;
- (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix),
- sizeof(rmd));
- }
-
- /*
- * Set up transmit ring descriptors.
- */
- for (bix = 0; bix < sc->sc_ntbuf; bix++) {
- a = sc->sc_addr + LE_TBUFADDR(sc, bix);
- tmd.tmd0 = a;
- tmd.tmd1_hadr = a >> 16;
- tmd.tmd1_bits = 0;
- tmd.tmd2 = 0 | LE_XMD2_ONES;
- tmd.tmd3 = 0;
- (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix),
- sizeof(tmd));
- }
-}
-
-void
-am7990_stop(sc)
- struct am7990_softc *sc;
-{
-
- (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
-}
-
-/*
- * Initialization of interface; set up initialization block
- * and transmit/receive descriptor rings.
- */
-void
-am7990_init(sc)
- register struct am7990_softc *sc;
-{
- register int timo;
- u_long a;
-
- (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
- DELAY(100);
-
- /* Newer LANCE chips have a reset register */
- if (sc->sc_hwreset)
- (*sc->sc_hwreset)(sc);
-
- /* Set the correct byte swapping mode, etc. */
- (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
-
- /* Set up LANCE init block. */
- am7990_meminit(sc);
-
- /* Give LANCE the physical address of its init block. */
- a = sc->sc_addr + LE_INITADDR(sc);
- (*sc->sc_wrcsr)(sc, LE_CSR1, a);
- (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
-
- /* Try to initialize the LANCE. */
- DELAY(100);
- (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
-
- /* Wait for initialization to finish. */
- for (timo = 100000; timo; timo--)
- if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
- break;
-
- if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
- /* Start the LANCE. */
- (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT |
- LE_C0_IDON);
- ifp->if_flags |= IFF_RUNNING;
- ifp->if_flags &= ~IFF_OACTIVE;
- ifp->if_timer = 0;
- am7990_start(ifp);
- } else
- printf("%s: card failed to initialize\n",
- device_get_nameunit(sc->sc_dev));
- if (sc->sc_hwinit)
- (*sc->sc_hwinit)(sc);
-}
-
-/*
- * Routine to copy from mbuf chain to transmit buffer in
- * network buffer memory.
- */
-
-integrate int
-am7990_put(sc, boff, m)
- struct am7990_softc *sc;
- int boff;
- register struct mbuf *m;
-{
- register struct mbuf *n;
- register int len, tlen = 0;
-
- for (; m; m = n) {
- len = m->m_len;
- if (len == 0) {
- n = m_free(m);
- m = NULL;
- continue;
- }
- (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
- boff += len;
- tlen += len;
- n = m_free(m);
- m = NULL;
- }
- if (tlen < LEMINSIZE) {
- (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
- tlen = LEMINSIZE;
- }
- return (tlen);
-}
-
-/*
- * Pull data off an interface.
- * Len is length of data, with local net header stripped.
- * We copy the data into mbufs. When full cluster sized units are present
- * we copy into clusters.
- */
-integrate struct mbuf *
-am7990_get(sc, boff, totlen)
- struct am7990_softc *sc;
- int boff, totlen;
-{
- register struct mbuf *m;
- struct mbuf *top, **mp;
- int len;
-
- MGETHDR(m, M_DONTWAIT, MT_DATA);
- if (m == 0)
- return (0);
- m->m_pkthdr.rcvif = ifp;
- m->m_pkthdr.len = totlen;
- len = MHLEN;
- top = 0;
- mp = &top;
-
- while (totlen > 0) {
- if (top) {
- MGET(m, M_DONTWAIT, MT_DATA);
- if (m == 0) {
- m_freem(top);
- return 0;
- }
- len = MLEN;
- }
- if (totlen >= MINCLSIZE) {
- MCLGET(m, M_DONTWAIT);
- if ((m->m_flags & M_EXT) == 0) {
- m_free(m);
- m_freem(top);
- return 0;
- }
- len = MCLBYTES;
- }
- if (!top) {
- register int pad =
- ALIGN(sizeof(struct ether_header)) -
- sizeof(struct ether_header);
- m->m_data += pad;
- len -= pad;
- }
- m->m_len = len = min(totlen, len);
- (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
- boff += len;
- totlen -= len;
- *mp = m;
- mp = &m->m_next;
- }
-
- return (top);
-}
-
-/*
- * Pass a packet to the higher levels.
- */
-integrate void
-am7990_read(sc, boff, len)
- register struct am7990_softc *sc;
- int boff, len;
-{
- struct mbuf *m;
- struct ether_header *eh;
-
- if (len <= sizeof(struct ether_header) ||
- len > ETHERMTU + sizeof(struct ether_header)) {
-#ifdef LEDEBUG
- printf("%s: invalid packet size %d; dropping\n",
- device_get_nameunit(sc->sc_dev), len);
-#endif
- ifp->if_ierrors++;
- return;
- }
-
- /* Pull packet off interface. */
- m = am7990_get(sc, boff, len);
- if (m == 0) {
- ifp->if_ierrors++;
- return;
- }
-
- ifp->if_ipackets++;
-
- /* We assume that the header fit entirely in one mbuf. */
- eh = mtod(m, struct ether_header *);
-
-#ifdef LANCE_REVC_BUG
- /*
- * The old LANCE (Rev. C) chips have a bug which causes
- * garbage to be inserted in front of the received packet.
- * The work-around is to ignore packets with an invalid
- * destination address (garbage will usually not match).
- * Of course, this precludes multicast support...
- */
- if (ETHER_CMP(eh->ether_dhost, sc->sc_enaddr) &&
- ETHER_CMP(eh->ether_dhost, bcast_enaddr)) {
- m_freem(m);
- return;
- }
-#endif
-
- /* Pass the packet up, with the ether header sort-of removed. */
- m_adj(m, sizeof(struct ether_header));
- ether_input(ifp, eh, m);
-}
-
-integrate void
-am7990_rint(sc)
- struct am7990_softc *sc;
-{
- register int bix;
- int rp;
- struct lermd rmd;
-
- bix = sc->sc_last_rd;
-
- /* Process all buffers with valid data. */
- for (;;) {
- rp = LE_RMDADDR(sc, bix);
- (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));
-
- if (rmd.rmd1_bits & LE_R1_OWN)
- break;
-
- if (rmd.rmd1_bits & LE_R1_ERR) {
- if (rmd.rmd1_bits & LE_R1_ENP) {
-#ifdef LEDEBUG
- if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) {
- if (rmd.rmd1_bits & LE_R1_FRAM)
- printf("%s: framing error\n",
- device_get_nameunit(sc->sc_dev));
- if (rmd.rmd1_bits & LE_R1_CRC)
- printf("%s: crc mismatch\n",
- device_get_nameunit(sc->sc_dev));
- }
-#endif
- } else {
- if (rmd.rmd1_bits & LE_R1_OFLO)
- printf("%s: overflow\n",
- device_get_nameunit(sc->sc_dev));
- }
- if (rmd.rmd1_bits & LE_R1_BUFF)
- printf("%s: receive buffer error\n",
- device_get_nameunit(sc->sc_dev));
- ifp->if_ierrors++;
- } else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) !=
- (LE_R1_STP | LE_R1_ENP)) {
- printf("%s: dropping chained buffer\n",
- device_get_nameunit(sc->sc_dev));
- ifp->if_ierrors++;
- } else {
-#ifdef LEDEBUG
- if (sc->sc_debug)
- am7990_recv_print(sc, sc->sc_last_rd);
-#endif
- am7990_read(sc, LE_RBUFADDR(sc, bix),
- (int)rmd.rmd3 - 4);
- }
-
- rmd.rmd1_bits = LE_R1_OWN;
- rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
- rmd.rmd3 = 0;
- (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
-
-#ifdef LEDEBUG
- if (sc->sc_debug)
- printf("sc->sc_last_rd = %x, rmd: "
- "ladr %04x, hadr %02x, flags %02x, "
- "bcnt %04x, mcnt %04x\n",
- sc->sc_last_rd,
- rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits,
- rmd.rmd2, rmd.rmd3);
-#endif
-
- if (++bix == sc->sc_nrbuf)
- bix = 0;
- }
-
- sc->sc_last_rd = bix;
-}
-
-integrate void
-am7990_tint(sc)
- register struct am7990_softc *sc;
-{
- register int bix;
- struct letmd tmd;
-
- bix = sc->sc_first_td;
-
- for (;;) {
- if (sc->sc_no_td <= 0)
- break;
-
-#ifdef LEDEBUG
- if (sc->sc_debug)
- printf("trans tmd: "
- "ladr %04x, hadr %02x, flags %02x, "
- "bcnt %04x, mcnt %04x\n",
- tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits,
- tmd.tmd2, tmd.tmd3);
-#endif
-
- (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
- sizeof(tmd));
-
- if (tmd.tmd1_bits & LE_T1_OWN)
- break;
-
- ifp->if_flags &= ~IFF_OACTIVE;
-
- if (tmd.tmd1_bits & LE_T1_ERR) {
- if (tmd.tmd3 & LE_T3_BUFF)
- printf("%s: transmit buffer error\n",
- device_get_nameunit(sc->sc_dev));
- else if (tmd.tmd3 & LE_T3_UFLO)
- printf("%s: underflow\n",
- device_get_nameunit(sc->sc_dev));
- if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) {
- am7990_reset(sc);
- return;
- }
- if (tmd.tmd3 & LE_T3_LCAR) {
- sc->sc_havecarrier = 0;
- if (sc->sc_nocarrier)
- (*sc->sc_nocarrier)(sc);
- else
- printf("%s: lost carrier\n",
- device_get_nameunit(sc->sc_dev));
- }
- if (tmd.tmd3 & LE_T3_LCOL)
- ifp->if_collisions++;
- if (tmd.tmd3 & LE_T3_RTRY) {
- printf("%s: excessive collisions, tdr %d\n",
- device_get_nameunit(sc->sc_dev),
- tmd.tmd3 & LE_T3_TDR_MASK);
- ifp->if_collisions += 16;
- }
- ifp->if_oerrors++;
- } else {
- if (tmd.tmd1_bits & LE_T1_ONE)
- ifp->if_collisions++;
- else if (tmd.tmd1_bits & LE_T1_MORE)
- /* Real number is unknown. */
- ifp->if_collisions += 2;
- ifp->if_opackets++;
- }
-
- if (++bix == sc->sc_ntbuf)
- bix = 0;
-
- --sc->sc_no_td;
- }
-
- sc->sc_first_td = bix;
-
- am7990_start(ifp);
-
- if (sc->sc_no_td == 0)
- ifp->if_timer = 0;
-}
-
-/*
- * Controller interrupt.
- */
-void
-am7990_intr(arg)
- register void *arg;
-{
- register struct am7990_softc *sc = arg;
- register u_int16_t isr;
-
- isr = (*sc->sc_rdcsr)(sc, LE_CSR0) | sc->sc_saved_csr0;
- sc->sc_saved_csr0 = 0;
-#ifdef LEDEBUG
- if (sc->sc_debug)
- printf("%s: am7990_intr entering with isr=%04x\n",
- device_get_nameunit(sc->sc_dev), isr);
-#endif
- if ((isr & LE_C0_INTR) == 0)
- return;
-
- (*sc->sc_wrcsr)(sc, LE_CSR0,
- isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR |
- LE_C0_RINT | LE_C0_TINT | LE_C0_IDON));
- if (isr & LE_C0_ERR) {
- if (isr & LE_C0_BABL) {
-#ifdef LEDEBUG
- printf("%s: babble\n", device_get_nameunit(sc->sc_dev));
-#endif
- ifp->if_oerrors++;
- }
-#if 0
- if (isr & LE_C0_CERR) {
- printf("%s: collision error\n",
- device_get_nameunit(sc->sc_dev));
- ifp->if_collisions++;
- }
-#endif
- if (isr & LE_C0_MISS) {
-#ifdef LEDEBUG
- printf("%s: missed packet\n",
- device_get_nameunit(sc->sc_dev));
-#endif
- ifp->if_ierrors++;
- }
- if (isr & LE_C0_MERR) {
- printf("%s: memory error\n",
- device_get_nameunit(sc->sc_dev));
- am7990_reset(sc);
- return;
- }
- }
-
- if ((isr & LE_C0_RXON) == 0) {
- printf("%s: receiver disabled\n",
- device_get_nameunit(sc->sc_dev));
- ifp->if_ierrors++;
- am7990_reset(sc);
- return;
- }
- if ((isr & LE_C0_TXON) == 0) {
- printf("%s: transmitter disabled\n",
- device_get_nameunit(sc->sc_dev));
- ifp->if_oerrors++;
- am7990_reset(sc);
- return;
- }
-
- /*
- * Pretend we have carrier; if we don't this will be cleared
- * shortly.
- */
- sc->sc_havecarrier = 1;
-
- if (isr & LE_C0_RINT)
- am7990_rint(sc);
- if (isr & LE_C0_TINT)
- am7990_tint(sc);
-
-#if NRND > 0
- rnd_add_uint32(&sc->rnd_source, isr);
-#endif
-
- return;
-}
-
-#undef ifp
-
-void
-am7990_watchdog(ifp)
- struct ifnet *ifp;
-{
- struct am7990_softc *sc = ifp->if_softc;
-
- log(LOG_ERR, "%s: device timeout\n", device_get_nameunit(sc->sc_dev));
- ++ifp->if_oerrors;
-
- am7990_reset(sc);
-}
-
-int
-am7990_mediachange(ifp)
- struct ifnet *ifp;
-{
- struct am7990_softc *sc = ifp->if_softc;
-
- if (sc->sc_mediachange)
- return ((*sc->sc_mediachange)(sc));
- return (EINVAL);
-}
-
-void
-am7990_mediastatus(ifp, ifmr)
- struct ifnet *ifp;
- struct ifmediareq *ifmr;
-{
- struct am7990_softc *sc = ifp->if_softc;
-
- if ((ifp->if_flags & IFF_UP) == 0)
- return;
-
- ifmr->ifm_status = IFM_AVALID;
- if (sc->sc_havecarrier)
- ifmr->ifm_status |= IFM_ACTIVE;
-
- if (sc->sc_mediastatus)
- (*sc->sc_mediastatus)(sc, ifmr);
-}
-
-/*
- * Setup output on interface.
- * Get another datagram to send off of the interface queue, and map it to the
- * interface before starting the output.
- * Called only at splimp or interrupt level.
- */
-void
-am7990_start(ifp)
- register struct ifnet *ifp;
-{
- register struct am7990_softc *sc = ifp->if_softc;
- register int bix;
- register struct mbuf *m;
- struct letmd tmd;
- int rp;
- int len;
-
- if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
- return;
-
- bix = sc->sc_last_td;
-
- for (;;) {
- rp = LE_TMDADDR(sc, bix);
- (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd));
-
- if (tmd.tmd1_bits & LE_T1_OWN) {
- ifp->if_flags |= IFF_OACTIVE;
- printf("missing buffer, no_td = %d, last_td = %d\n",
- sc->sc_no_td, sc->sc_last_td);
- }
-
- IF_DEQUEUE(&ifp->if_snd, m);
- if (m == 0)
- break;
-
- /*
- * If BPF is listening on this interface, let it see the packet
- * before we commit it to the wire.
- */
- if (ifp->if_bpf)
- bpf_mtap(ifp, m);
-
- /*
- * Copy the mbuf chain into the transmit buffer.
- */
- len = am7990_put(sc, LE_TBUFADDR(sc, bix), m);
-
-#ifdef LEDEBUG
- if (len > ETHERMTU + sizeof(struct ether_header))
- printf("packet length %d\n", len);
-#endif
-
- ifp->if_timer = 5;
-
- /*
- * Init transmit registers, and set transmit start flag.
- */
- tmd.tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP;
- tmd.tmd2 = -len | LE_XMD2_ONES;
- tmd.tmd3 = 0;
-
- (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));
-
-#ifdef LEDEBUG
- if (sc->sc_debug)
- am7990_xmit_print(sc, sc->sc_last_td);
-#endif
-
- (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
-
- if (++bix == sc->sc_ntbuf)
- bix = 0;
-
- if (++sc->sc_no_td == sc->sc_ntbuf) {
- ifp->if_flags |= IFF_OACTIVE;
- break;
- }
-
- }
-
- sc->sc_last_td = bix;
-}
-
-/*
- * Process an ioctl request.
- */
-int
-am7990_ioctl(ifp, cmd, data)
- register struct ifnet *ifp;
- u_long cmd;
- caddr_t data;
-{
- register struct am7990_softc *sc = ifp->if_softc;
- struct ifaddr *ifa = (struct ifaddr *)data;
- struct ifreq *ifr = (struct ifreq *)data;
- int s, error = 0;
-
- s = splimp();
-
- switch (cmd) {
-
- case SIOCSIFADDR:
- ifp->if_flags |= IFF_UP;
-
- switch (ifa->ifa_addr->sa_family) {
-#ifdef INET
- case AF_INET:
- am7990_init(sc);
- arp_ifinit((void *)ifp, ifa);
- break;
-#endif
-#ifdef NS
- case AF_NS:
- {
- register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
-
- if (ns_nullhost(*ina))
- ina->x_host =
- *(union ns_host *)LLADDR(ifp->if_sadl);
- else {
- bcopy(ina->x_host.c_host,
- LLADDR(ifp->if_sadl),
- sizeof(sc->sc_enaddr));
- }
- /* Set new address. */
- am7990_init(sc);
- break;
- }
-#endif
- default:
- am7990_init(sc);
- break;
- }
- break;
-
- case SIOCSIFFLAGS:
- if ((ifp->if_flags & IFF_UP) == 0 &&
- (ifp->if_flags & IFF_RUNNING) != 0) {
- /*
- * If interface is marked down and it is running, then
- * stop it.
- */
- am7990_stop(sc);
- ifp->if_flags &= ~IFF_RUNNING;
- } else if ((ifp->if_flags & IFF_UP) != 0 &&
- (ifp->if_flags & IFF_RUNNING) == 0) {
- /*
- * If interface is marked up and it is stopped, then
- * start it.
- */
- am7990_init(sc);
- } else {
- /*
- * Reset the interface to pick up changes in any other
- * flags that affect hardware registers.
- */
- /*am7990_stop(sc);*/
- am7990_init(sc);
- }
-#ifdef LEDEBUG
- if (ifp->if_flags & IFF_DEBUG)
- sc->sc_debug = 1;
- else
- sc->sc_debug = 0;
-#endif
- break;
-
- case SIOCADDMULTI:
- case SIOCDELMULTI:
- /*
- * Multicast list has changed; set the hardware filter
- * accordingly.
- */
- am7990_reset(sc);
- error = 0;
- break;
-
- case SIOCGIFMEDIA:
- case SIOCSIFMEDIA:
- error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
- break;
-
- default:
- error = EINVAL;
- break;
- }
-
- splx(s);
- return (error);
-}
-
-/*
-hide void
-am7990_shutdown(arg)
- void *arg;
-{
-
- am7990_stop((struct am7990_softc *)arg);
-}
-*/
-
-#ifdef LEDEBUG
-void
-am7990_recv_print(sc, no)
- struct am7990_softc *sc;
- int no;
-{
- struct lermd rmd;
- u_int16_t len;
- struct ether_header eh;
-
- (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd));
- len = rmd.rmd3;
- printf("%s: receive buffer %d, len = %d\n",
- device_get_nameunit(sc->sc_dev), no, len);
- printf("%s: status %04x\n", device_get_nameunit(sc->sc_dev),
- (*sc->sc_rdcsr)(sc, LE_CSR0));
- printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
- device_get_nameunit(sc->sc_dev),
- rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3);
- if (len >= sizeof(eh)) {
- (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
- printf("%s: dst %s", device_get_nameunit(sc->sc_dev),
- ether_sprintf(eh.ether_dhost));
- printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
- ntohs(eh.ether_type));
- }
-}
-
-void
-am7990_xmit_print(sc, no)
- struct am7990_softc *sc;
- int no;
-{
- struct letmd tmd;
- u_int16_t len;
- struct ether_header eh;
-
- (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd));
- len = -tmd.tmd2;
- printf("%s: transmit buffer %d, len = %d\n",
- device_get_nameunit(sc->sc_dev), no,
- len);
- printf("%s: status %04x\n", device_get_nameunit(sc->sc_dev),
- (*sc->sc_rdcsr)(sc, LE_CSR0));
- printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
- device_get_nameunit(sc->sc_dev),
- tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3);
- if (len >= sizeof(eh)) {
- (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
- printf("%s: dst %s", device_get_nameunit(sc->sc_dev),
- ether_sprintf(eh.ether_dhost));
- printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
- ntohs(eh.ether_type));
- }
-}
-#endif /* LEDEBUG */
-
-/*
- * Set up the logical address filter.
- */
-void
-am7990_setladrf(ac, af)
- struct arpcom *ac;
- u_int16_t *af;
-{
-#if 0
- struct ifnet *ifp = &ac->ac_if;
- struct ether_multi *enm;
- register u_char *cp;
- register u_int32_t crc;
- static const u_int32_t crctab[] = {
- 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
- 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
- 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
- 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
- };
- register int len;
- struct ether_multistep step;
-
- /*
- * Set up multicast address filter by passing all multicast addresses
- * through a crc generator, and then using the high order 6 bits as an
- * index into the 64 bit logical address filter. The high order bit
- * selects the word, while the rest of the bits select the bit within
- * the word.
- */
-
- if (ifp->if_flags & IFF_PROMISC)
- goto allmulti;
-
- af[0] = af[1] = af[2] = af[3] = 0x0000;
- ETHER_FIRST_MULTI(step, ac, enm);
- while (enm != NULL) {
- if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
- /*
- * We must listen to a range of multicast addresses.
- * For now, just accept all multicasts, rather than
- * trying to set only those filter bits needed to match
- * the range. (At this time, the only use of address
- * ranges is for IP multicast routing, for which the
- * range is big enough to require all bits set.)
- */
- goto allmulti;
- }
-
- cp = enm->enm_addrlo;
- crc = 0xffffffff;
- for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
- crc ^= *cp++;
- crc = (crc >> 4) ^ crctab[crc & 0xf];
- crc = (crc >> 4) ^ crctab[crc & 0xf];
- }
- /* Just want the 6 most significant bits. */
- crc >>= 26;
-
- /* Set the corresponding bit in the filter. */
- af[crc >> 4] |= 1 << (crc & 0xf);
-
- ETHER_NEXT_MULTI(step, enm);
- }
- ifp->if_flags &= ~IFF_ALLMULTI;
- return;
-
-allmulti:
- ifp->if_flags |= IFF_ALLMULTI;
- af[0] = af[1] = af[2] = af[3] = 0xffff;
-#endif
-}
-
-
-/*
- * Routines for accessing the transmit and receive buffers.
- * The various CPU and adapter configurations supported by this
- * driver require three different access methods for buffers
- * and descriptors:
- * (1) contig (contiguous data; no padding),
- * (2) gap2 (two bytes of data followed by two bytes of padding),
- * (3) gap16 (16 bytes of data followed by 16 bytes of padding).
- */
-
-/*
- * contig: contiguous data with no padding.
- *
- * Buffers may have any alignment.
- */
-
-void
-am7990_copytobuf_contig(sc, from, boff, len)
- struct am7990_softc *sc;
- void *from;
- int boff, len;
-{
- volatile caddr_t buf = sc->sc_mem;
-
- /*
- * Just call bcopy() to do the work.
- */
- bcopy(from, buf + boff, len);
-}
-
-void
-am7990_copyfrombuf_contig(sc, to, boff, len)
- struct am7990_softc *sc;
- void *to;
- int boff, len;
-{
- volatile caddr_t buf = sc->sc_mem;
-
- /*
- * Just call bcopy() to do the work.
- */
- bcopy(buf + boff, to, len);
-}
-
-void
-am7990_zerobuf_contig(sc, boff, len)
- struct am7990_softc *sc;
- int boff, len;
-{
- volatile caddr_t buf = sc->sc_mem;
-
- /*
- * Just let bzero() do the work
- */
- bzero(buf + boff, len);
-}
-
-#if 0
-/*
- * Examples only; duplicate these and tweak (if necessary) in
- * machine-specific front-ends.
- */
-
-/*
- * gap2: two bytes of data followed by two bytes of pad.
- *
- * Buffers must be 4-byte aligned. The code doesn't worry about
- * doing an extra byte.
- */
-
-void
-am7990_copytobuf_gap2(sc, fromv, boff, len)
- struct am7990_softc *sc;
- void *fromv;
- int boff;
- register int len;
-{
- volatile caddr_t buf = sc->sc_mem;
- register caddr_t from = fromv;
- register volatile u_int16_t *bptr;
-
- if (boff & 0x1) {
- /* handle unaligned first byte */
- bptr = ((volatile u_int16_t *)buf) + (boff - 1);
- *bptr = (*from++ << 8) | (*bptr & 0xff);
- bptr += 2;
- len--;
- } else
- bptr = ((volatile u_int16_t *)buf) + boff;
- while (len > 1) {
- *bptr = (from[1] << 8) | (from[0] & 0xff);
- bptr += 2;
- from += 2;
- len -= 2;
- }
- if (len == 1)
- *bptr = (u_int16_t)*from;
-}
-
-void
-am7990_copyfrombuf_gap2(sc, tov, boff, len)
- struct am7990_softc *sc;
- void *tov;
- int boff, len;
-{
- volatile caddr_t buf = sc->sc_mem;
- register caddr_t to = tov;
- register volatile u_int16_t *bptr;
- register u_int16_t tmp;
-
- if (boff & 0x1) {
- /* handle unaligned first byte */
- bptr = ((volatile u_int16_t *)buf) + (boff - 1);
- *to++ = (*bptr >> 8) & 0xff;
- bptr += 2;
- len--;
- } else
- bptr = ((volatile u_int16_t *)buf) + boff;
- while (len > 1) {
- tmp = *bptr;
- *to++ = tmp & 0xff;
- *to++ = (tmp >> 8) & 0xff;
- bptr += 2;
- len -= 2;
- }
- if (len == 1)
- *to = *bptr & 0xff;
-}
-
-void
-am7990_zerobuf_gap2(sc, boff, len)
- struct am7990_softc *sc;
- int boff, len;
-{
- volatile caddr_t buf = sc->sc_mem;
- register volatile u_int16_t *bptr;
-
- if ((unsigned)boff & 0x1) {
- bptr = ((volatile u_int16_t *)buf) + (boff - 1);
- *bptr &= 0xff;
- bptr += 2;
- len--;
- } else
- bptr = ((volatile u_int16_t *)buf) + boff;
- while (len > 0) {
- *bptr = 0;
- bptr += 2;
- len -= 2;
- }
-}
-
-/*
- * gap16: 16 bytes of data followed by 16 bytes of pad.
- *
- * Buffers must be 32-byte aligned.
- */
-
-void
-am7990_copytobuf_gap16(sc, fromv, boff, len)
- struct am7990_softc *sc;
- void *fromv;
- int boff;
- register int len;
-{
- volatile caddr_t buf = sc->sc_mem;
- register caddr_t from = fromv;
- register caddr_t bptr;
- register int xfer;
-
- bptr = buf + ((boff << 1) & ~0x1f);
- boff &= 0xf;
- xfer = min(len, 16 - boff);
- while (len > 0) {
- bcopy(from, bptr + boff, xfer);
- from += xfer;
- bptr += 32;
- boff = 0;
- len -= xfer;
- xfer = min(len, 16);
- }
-}
-
-void
-am7990_copyfrombuf_gap16(sc, tov, boff, len)
- struct am7990_softc *sc;
- void *tov;
- int boff, len;
-{
- volatile caddr_t buf = sc->sc_mem;
- register caddr_t to = tov;
- register caddr_t bptr;
- register int xfer;
-
- bptr = buf + ((boff << 1) & ~0x1f);
- boff &= 0xf;
- xfer = min(len, 16 - boff);
- while (len > 0) {
- bcopy(bptr + boff, to, xfer);
- to += xfer;
- bptr += 32;
- boff = 0;
- len -= xfer;
- xfer = min(len, 16);
- }
-}
-
-void
-am7990_zerobuf_gap16(sc, boff, len)
- struct am7990_softc *sc;
- int boff, len;
-{
- volatile caddr_t buf = sc->sc_mem;
- register caddr_t bptr;
- register int xfer;
-
- bptr = buf + ((boff << 1) & ~0x1f);
- boff &= 0xf;
- xfer = min(len, 16 - boff);
- while (len > 0) {
- bzero(bptr + boff, xfer);
- bptr += 32;
- boff = 0;
- len -= xfer;
- xfer = min(len, 16);
- }
-}
-#endif /* Example only */
-char *
-ether_sprintf(ap)
- register u_char *ap;
-{
- int i;
- static char etherbuf[18];
- register char *cp = etherbuf;
- static char digits[] = "0123456789abcdef";
-
- for (i = 0; i < 6; i++) {
- *cp++ = digits[*ap >> 4];
- *cp++ = digits[*ap++ & 0xf];
- *cp++ = ':';
- }
- *--cp = 0;
- return (etherbuf);
-}
OpenPOWER on IntegriCloud