summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/arch/sparc/dev/hme.c1492
-rw-r--r--sys/arch/sparc/dev/hmereg.h582
-rw-r--r--sys/arch/sparc/dev/hmevar.h68
3 files changed, 2142 insertions, 0 deletions
diff --git a/sys/arch/sparc/dev/hme.c b/sys/arch/sparc/dev/hme.c
new file mode 100644
index 00000000000..9df40e65026
--- /dev/null
+++ b/sys/arch/sparc/dev/hme.c
@@ -0,0 +1,1492 @@
+/* $OpenBSD: hme.c,v 1.1 1998/07/10 19:09:08 jason Exp $ */
+
+/*
+ * Copyright (c) 1998 Jason L. Wright (jason@thought.net)
+ * All rights reserved.
+ *
+ * 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 Jason L. Wright
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * Driver for the Happy Meal (hme) ethernet boards
+ * Based on the driver from S/Linux by David Miller
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/syslog.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include "bpfilter.h"
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#include <net/bpfdesc.h>
+#endif
+
+#include <machine/autoconf.h>
+#include <sparc/cpu.h>
+#include <sparc/sparc/cpuvar.h>
+#include <sparc/dev/sbusvar.h>
+#include <sparc/dev/dmareg.h> /* for SBUS_BURST_* */
+#include <sparc/dev/hmereg.h>
+#include <sparc/dev/hmevar.h>
+
+int hmematch __P((struct device *, void *, void *));
+void hmeattach __P((struct device *, struct device *, void *));
+void hmewatchdog __P((struct ifnet *));
+int hmeintr __P((void *));
+int hmeioctl __P((struct ifnet *, u_long, caddr_t));
+void hmereset __P((struct hme_softc *sc));
+void hmestart __P((struct ifnet *));
+void hmestop __P((struct hme_softc *sc));
+void hmeinit __P((struct hme_softc *sc));
+
+static void hme_tcvr_write __P((struct hme_softc *sc, int reg,
+ u_short val));
+static int hme_tcvr_read __P((struct hme_softc *sc, int reg));
+static void hme_tcvr_bb_write __P((struct hme_softc *sc, int reg,
+ u_short val));
+static int hme_tcvr_bb_read __P((struct hme_softc *sc, int reg));
+static void hme_tcvr_bb_writeb __P((struct hme_softc *sc, int b));
+static int hme_tcvr_bb_readb __P((struct hme_softc *sc));
+static void hme_tcvr_check __P((struct hme_softc *sc));
+static int hme_tcvr_reset __P((struct hme_softc *sc));
+
+static void hme_poll_stop __P((struct hme_softc *sc));
+
+static int hme_mint __P((struct hme_softc *, u_int32_t));
+static int hme_tint __P((struct hme_softc *, u_int32_t));
+static int hme_rint __P((struct hme_softc *, u_int32_t));
+static int hme_eint __P((struct hme_softc *, u_int32_t));
+
+static void hme_auto_negotiate __P((struct hme_softc *sc));
+static void hme_manual_negotiate __P((struct hme_softc *sc));
+static void hme_negotiate_watchdog __P((void *arg));
+static void hme_print_link_mode __P((struct hme_softc *sc));
+static void hme_set_initial_advertisement __P((struct hme_softc *sc));
+
+static void hme_reset_rx __P((struct hme_softc *sc));
+static void hme_reset_tx __P((struct hme_softc *sc));
+static void hme_meminit __P((struct hme_softc *sc));
+
+static int hme_put __P((struct hme_softc *sc, int idx, struct mbuf *m));
+
+static struct mbuf *hme_get __P((struct hme_softc *sc, int idx, int len));
+static void hme_read __P((struct hme_softc *sc, int idx, int len));
+
+struct cfattach hme_ca = {
+ sizeof (struct hme_softc), hmematch, hmeattach
+};
+
+struct cfdriver hme_cd = {
+ NULL, "hme", DV_IFNET
+};
+
+int
+hmematch(parent, vcf, aux)
+ struct device *parent;
+ void *vcf, *aux;
+{
+ struct cfdata *cf = vcf;
+ struct confargs *ca = aux;
+ register struct romaux *ra = &ca->ca_ra;
+
+ if (strcmp(cf->cf_driver->cd_name, ra->ra_name) &&
+ strcmp("SUNW,hme", ra->ra_name)) {
+ return (0);
+ }
+ return (1);
+}
+
+void
+hmeattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct confargs *ca = aux;
+ struct hme_softc *sc = (struct hme_softc *)self;
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ int pri;
+
+#if 0
+ /*
+ * XXX We should check the prom env var 'local-mac-address?'
+ * XXX If true, use the MAC address specific to the board, and if
+ * XXX false, use the MAC address specific to the system.
+ */
+
+ /* XXX the following declaration should be elsewhere */
+ extern void myetheraddr __P((u_char *));
+#endif
+
+
+ if (ca->ca_ra.ra_nintr != 1) {
+ printf(": expected 1 interrupt, got %d\n", ca->ca_ra.ra_nintr);
+ return;
+ }
+ pri = ca->ca_ra.ra_intr[0].int_pri;
+
+ /* map registers */
+ if (ca->ca_ra.ra_nreg != 5) {
+ printf(": expected 5 registers, got %d\n", ca->ca_ra.ra_nreg);
+ return;
+ }
+ sc->sc_gr = mapiodev(&(ca->ca_ra.ra_reg[0]), 0,
+ ca->ca_ra.ra_reg[0].rr_len);
+ sc->sc_txr = mapiodev(&(ca->ca_ra.ra_reg[1]), 0,
+ ca->ca_ra.ra_reg[1].rr_len);
+ sc->sc_rxr = mapiodev(&(ca->ca_ra.ra_reg[2]), 0,
+ ca->ca_ra.ra_reg[2].rr_len);
+ sc->sc_cr = mapiodev(&(ca->ca_ra.ra_reg[3]), 0,
+ ca->ca_ra.ra_reg[3].rr_len);
+ sc->sc_tcvr = mapiodev(&(ca->ca_ra.ra_reg[4]), 0,
+ ca->ca_ra.ra_reg[4].rr_len);
+
+ sc->sc_node = ca->ca_ra.ra_node;
+
+ sc->sc_rev = getpropint(ca->ca_ra.ra_node, "hm-rev", -1);
+ if (sc->sc_rev == 0xff)
+ sc->sc_rev = 0xa0;
+ if (sc->sc_rev == 0x20 || sc->sc_rev == 0x21)
+ sc->sc_flags = HME_FLAG_20_21;
+ else if (sc->sc_rev != 0xa0)
+ sc->sc_flags = HME_FLAG_NOT_A0;
+
+ sc->sc_burst = ((struct sbus_softc *)parent)->sc_burst;
+
+ sc->sc_desc_dva = (struct hme_desc *) dvma_malloc(
+ sizeof(struct hme_desc), &(sc->sc_desc), M_NOWAIT);
+ sc->sc_bufs_dva = (struct hme_bufs *) dvma_malloc(
+ sizeof(struct hme_bufs) + RX_ALIGN_SIZE, &(sc->sc_bufs),
+ M_NOWAIT); /* XXX must be aligned on 64 byte boundary */
+
+ hme_set_initial_advertisement(sc);
+
+ sbus_establish(&sc->sc_sd, &sc->sc_dev);
+
+ sc->sc_ih.ih_fun = hmeintr;
+ sc->sc_ih.ih_arg = sc;
+ intr_establish(ca->ca_ra.ra_intr[0].int_pri, &sc->sc_ih);
+
+#if 1
+ /*
+ * XXX Below should only be used if 'local-mac-address?' == true
+ */
+ getprop(ca->ca_ra.ra_node, "local-mac-address",
+ sc->sc_arpcom.ac_enaddr,
+ sizeof(sc->sc_arpcom.ac_enaddr));
+#else
+ /*
+ * XXX Below should only be used if 'local-mac-address?' == false
+ */
+ myetheraddr(sc->sc_arpcom.ac_enaddr);
+#endif
+
+ bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
+ ifp->if_softc = sc;
+ ifp->if_start = hmestart;
+ ifp->if_ioctl = hmeioctl;
+ ifp->if_watchdog = hmewatchdog;
+ ifp->if_flags =
+ IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
+
+ /* Attach the interface. */
+ if_attach(ifp);
+ ether_ifattach(ifp);
+
+ sc->sc_an_state = HME_TIMER_DONE;
+ sc->sc_an_ticks = 0;
+
+ printf(" pri %d: address %s rev %d\n", pri,
+ ether_sprintf(sc->sc_arpcom.ac_enaddr), sc->sc_rev);
+
+#if NBPFILTER > 0
+ bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
+#endif
+}
+
+/*
+ * Start output on interface.
+ * We make two assumptions here:
+ * 1) that the current priority is set to splnet _before_ this code
+ * is called *and* is returned to the appropriate priority after
+ * return
+ * 2) that the IFF_OACTIVE flag is checked before this code is called
+ * (i.e. that the output part of the interface is idle)
+ */
+void
+hmestart(ifp)
+ struct ifnet *ifp;
+{
+ struct hme_softc *sc = ifp->if_softc;
+ struct mbuf *m;
+ int bix, len;
+
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
+ return;
+
+ bix = sc->sc_last_td;
+
+ for (;;) {
+ IF_DEQUEUE(&ifp->if_snd, m);
+ if (m == 0)
+ break;
+#if NBPFILTER > 0
+ /*
+ * 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->if_bpf, m);
+#endif
+
+ /*
+ * Copy the mbuf chain into the transmit buffer.
+ */
+ len = hme_put(sc, bix, m);
+
+ /*
+ * Initialize transmit registers and start transmission
+ */
+ sc->sc_desc->hme_txd[bix].tx_addr = (u_long) sc->sc_bufs_dva +
+ (((u_long) &(sc->sc_bufs->tx_buf[bix])) -
+ ((u_long) sc->sc_bufs));
+ sc->sc_desc->hme_txd[bix].tx_flags =
+ TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP |
+ (len & TXFLAG_SIZE);
+
+ sc->sc_txr->tx_pnding = TXR_TP_DMAWAKEUP;
+
+ if (++bix == TX_RING_SIZE)
+ bix = 0;
+
+ if (++sc->sc_no_td == TX_RING_SIZE) {
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+ }
+
+ sc->sc_last_td = bix;
+}
+
+#define MAX_STOP_TRIES 16
+
+void
+hmestop(sc)
+ struct hme_softc *sc;
+{
+ int tries = 0;
+
+ sc->sc_gr->reset = GR_RESET_ALL;
+ while (sc->sc_gr->reset && (tries != MAX_STOP_TRIES))
+ DELAY(20);
+ if (tries == MAX_STOP_TRIES)
+ printf("%s: stop failed\n", sc->sc_dev.dv_xname);
+}
+
+/*
+ * Reset interface.
+ */
+void
+hmereset(sc)
+ struct hme_softc *sc;
+{
+ int s;
+
+ s = splnet();
+ hmestop(sc);
+ hmeinit(sc);
+ splx(s);
+}
+
+/*
+ * Device timeout/watchdog routine. Entered if the device neglects to generate
+ * an interrupt after a transmit has been started on it.
+ */
+void
+hmewatchdog(ifp)
+ struct ifnet *ifp;
+{
+ struct hme_softc *sc = ifp->if_softc;
+
+ log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
+ ++sc->sc_arpcom.ac_if.if_oerrors;
+
+ hmereset(sc);
+}
+
+int
+hmeioctl(ifp, cmd, data)
+ struct ifnet *ifp;
+ u_long cmd;
+ caddr_t data;
+{
+ struct hme_softc *sc = ifp->if_softc;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int s, error = 0;
+
+ s = splimp();
+
+ if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
+ splx(s);
+ return error;
+ }
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ switch (ifa->ifa_addr->sa_family) {
+#ifdef INET
+ case AF_INET:
+ hmeinit(sc);
+ arp_ifinit(&sc->sc_arpcom, ifa);
+ break;
+#endif /* INET */
+#ifdef NS
+ /* XXX - This code is probably wrong. */
+ case AF_NS:
+ {
+ struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
+
+ if (ns_nullhost(*ina))
+ ina->x_host =
+ *(union ns_host *)(sc->sc_arpcom.ac_enaddr);
+ else
+ bcopy(ina->x_host.c_host,
+ sc->sc_arpcom.ac_enaddr,
+ sizeof(sc->sc_arpcom.ac_enaddr));
+ /* Set new address. */
+ hmeinit(sc);
+ break;
+ }
+#endif /* NS */
+ default:
+ hmeinit(sc);
+ break;
+ }
+ break;
+
+ case SIOCSIFFLAGS:
+ sc->sc_promisc = ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI);
+ 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.
+ */
+ hmestop(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.
+ */
+ hmeinit(sc);
+ } else {
+ /*
+ * Reset the interface to pick up changes in any other
+ * flags that affect hardware registers.
+ */
+ hmestop(sc);
+ hmeinit(sc);
+ }
+#ifdef IEDEBUG
+ if (ifp->if_flags & IFF_DEBUG)
+ sc->sc_debug = IED_ALL;
+ else
+ sc->sc_debug = 0;
+#endif
+ break;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ error = (cmd == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &sc->sc_arpcom):
+ ether_delmulti(ifr, &sc->sc_arpcom);
+
+ if (error == ENETRESET) {
+ /*
+ * Multicast list has changed; set the hardware filter
+ * accordingly.
+ */
+#if 0
+ mc_reset(sc);
+#endif
+ error = 0;
+ }
+ break;
+ default:
+ error = EINVAL;
+ }
+ splx(s);
+ return error;
+}
+
+void
+hmeinit(sc)
+ struct hme_softc *sc;
+{
+ u_int32_t c;
+ struct hme_tcvr *tcvr = sc->sc_tcvr;
+ struct hme_cr *cr = sc->sc_cr;
+ struct hme_gr *gr = sc->sc_gr;
+ struct hme_txr *txr = sc->sc_txr;
+ struct hme_rxr *rxr = sc->sc_rxr;
+
+ hme_poll_stop(sc);
+ hmestop(sc);
+
+ hme_meminit(sc);
+
+ tcvr->int_mask = 0xffff;
+
+ c = tcvr->cfg;
+ if (sc->sc_flags & HME_FLAG_FENABLE)
+ tcvr->cfg = c & ~(TCVR_CFG_BENABLE);
+ else
+ tcvr->cfg = c | TCVR_CFG_BENABLE;
+
+ hme_tcvr_check(sc);
+ switch (sc->sc_tcvr_type) {
+ case HME_TCVR_NONE:
+ printf("%s: no transceiver type!\n", sc->sc_dev.dv_xname);
+ return;
+ case HME_TCVR_INTERNAL:
+ cr->xif_cfg = 0;
+ break;
+ case HME_TCVR_EXTERNAL:
+ cr->xif_cfg = CR_XCFG_MIIDISAB;
+ break;
+ }
+ hme_tcvr_reset(sc);
+
+ hme_reset_tx(sc);
+ hme_reset_rx(sc);
+
+ cr->rand_seed = sc->sc_arpcom.ac_enaddr[5] |
+ ((sc->sc_arpcom.ac_enaddr[4] << 8) & 0x3f00);
+ cr->mac_addr0 = (sc->sc_arpcom.ac_enaddr[0] << 8) |
+ sc->sc_arpcom.ac_enaddr[1];
+ cr->mac_addr1 = (sc->sc_arpcom.ac_enaddr[2] << 8) |
+ sc->sc_arpcom.ac_enaddr[3];
+ cr->mac_addr2 = (sc->sc_arpcom.ac_enaddr[4] << 8) |
+ sc->sc_arpcom.ac_enaddr[5];
+
+ cr->jsize = HME_DEFAULT_JSIZE;
+ cr->ipkt_gap1 = HME_DEFAULT_IPKT_GAP1;
+ cr->ipkt_gap2 = HME_DEFAULT_IPKT_GAP2;
+ cr->htable3 = 0;
+ cr->htable2 = 0;
+ cr->htable1 = 0;
+ cr->htable0 = 0;
+
+ rxr->rx_ring = (u_long) sc->sc_desc_dva +
+ (((u_long) &sc->sc_desc->hme_rxd[0])
+ - ((u_long)sc->sc_desc));
+ txr->tx_ring = (u_long) sc->sc_desc_dva +
+ (((u_long) &sc->sc_desc->hme_txd[0])
+ - ((u_long)sc->sc_desc));
+
+ if (sc->sc_burst & SBUS_BURST_64)
+ gr->cfg = GR_CFG_BURST64;
+ else if (sc->sc_burst & SBUS_BURST_32)
+ gr->cfg = GR_CFG_BURST32;
+ else if (sc->sc_burst & SBUS_BURST_16)
+ gr->cfg = GR_CFG_BURST16;
+ else {
+ printf("%s: burst size unknown\n", sc->sc_dev.dv_xname);
+ gr->cfg = 0;
+ }
+
+ gr->imask = GR_IMASK_SENTFRAME | GR_IMASK_TXPERR |
+ GR_IMASK_GOTFRAME | GR_IMASK_RCNTEXP;
+
+ txr->tx_rsize = (TX_RING_SIZE >> TXR_RSIZE_SHIFT) - 1;
+ txr->cfg |= TXR_CFG_DMAENABLE;
+
+ c = RXR_CFG_DMAENABLE | (RX_OFFSET << 3) | (RX_CSUMLOC << 16);
+#if RX_RING_SIZE == 32
+ c |= RXR_CFG_RINGSIZE32;
+#elif RX_RING_SIZE == 64
+ c |= RXR_CFG_RINGSIZE64;
+#elif RX_RING_SIZE == 128
+ c |= RXR_CFG_RINGSIZE128;
+#elif RX_RING_SIZE == 256
+ c |= RXR_CFG_RINGSIZE256;
+#else
+#error "RX_RING_SIZE must be 32, 64, 128, or 256."
+#endif
+ rxr->cfg = c;
+ DELAY(20);
+ if (c != rxr->cfg) /* the receiver sometimes misses bits */
+ printf("%s: setting rxreg->cfg failed.\n", sc->sc_dev.dv_xname);
+
+ cr->rx_cfg = CR_RXCFG_HENABLE;
+ DELAY(10);
+
+ c = CR_TXCFG_DGIVEUP;
+ if (sc->sc_flags & HME_FLAG_FULL)
+ c |= CR_TXCFG_FULLDPLX;
+ cr->tx_cfg = c;
+
+ c = CR_XCFG_ODENABLE;
+ if (sc->sc_flags & HME_FLAG_LANCE)
+ c |= (HME_DEFAULT_IPKT_GAP0 << 5) | CR_XCFG_LANCE;
+ if (sc->sc_tcvr_type == HME_TCVR_EXTERNAL)
+ c |= CR_XCFG_MIIDISAB;
+ cr->xif_cfg = c;
+
+ cr->tx_cfg |= CR_TXCFG_ENABLE; /* enable tx */
+ cr->rx_cfg |= CR_RXCFG_ENABLE; /* enable rx */
+
+ hme_auto_negotiate(sc);
+}
+
+static void
+hme_set_initial_advertisement(sc)
+ struct hme_softc *sc;
+{
+ hmestop(sc);
+ sc->sc_tcvr->int_mask = 0xffff;
+ if (sc->sc_flags & HME_FLAG_FENABLE)
+ sc->sc_tcvr->cfg &= ~(TCVR_CFG_BENABLE);
+ else
+ sc->sc_tcvr->cfg |= TCVR_CFG_BENABLE;
+
+ hme_tcvr_check(sc);
+ switch (sc->sc_tcvr_type) {
+ case HME_TCVR_NONE:
+ return;
+ case HME_TCVR_INTERNAL:
+ sc->sc_cr->xif_cfg = 0;
+ break;
+ case HME_TCVR_EXTERNAL:
+ sc->sc_cr->xif_cfg = CR_XCFG_MIIDISAB;
+ break;
+ }
+ if (hme_tcvr_reset(sc))
+ return;
+
+ /* grab the supported modes and advertised modes */
+ sc->sc_sw.bmsr = hme_tcvr_read(sc, DP83840_BMSR);
+ sc->sc_sw.anar = hme_tcvr_read(sc, DP83840_ANAR);
+
+ /* If 10BaseT Half duplex supported, advertise it, and so on... */
+ if (sc->sc_sw.bmsr & BMSR_10BASET_HALF)
+ sc->sc_sw.anar |= ANAR_10;
+ else
+ sc->sc_sw.anar &= ~(ANAR_10);
+
+ if (sc->sc_sw.bmsr & BMSR_10BASET_FULL)
+ sc->sc_sw.anar |= ANAR_10_FD;
+ else
+ sc->sc_sw.anar &= ~(ANAR_10_FD);
+
+ if (sc->sc_sw.bmsr & BMSR_100BASETX_HALF)
+ sc->sc_sw.anar |= ANAR_TX;
+ else
+ sc->sc_sw.anar &= ~(ANAR_TX);
+
+ if (sc->sc_sw.bmsr & BMSR_100BASETX_FULL)
+ sc->sc_sw.anar |= ANAR_TX_FD;
+ else
+ sc->sc_sw.anar &= ~(ANAR_TX_FD);
+
+ /* Inform card about what it should advertise */
+ hme_tcvr_write(sc, DP83840_ANAR, sc->sc_sw.anar);
+}
+
+#define XCVR_RESET_TRIES 16
+#define XCVR_UNISOLATE_TRIES 32
+
+static int
+hme_tcvr_reset(sc)
+ struct hme_softc *sc;
+{
+ struct hme_tcvr *tcvr = sc->sc_tcvr;
+ u_int32_t cfg;
+ int result, tries = XCVR_RESET_TRIES;
+
+ cfg = tcvr->cfg;
+ if (sc->sc_tcvr_type == HME_TCVR_EXTERNAL) {
+ tcvr->cfg = cfg & ~(TCVR_CFG_PSELECT);
+ sc->sc_tcvr_type = HME_TCVR_INTERNAL;
+ sc->sc_phyaddr = TCVR_PHYADDR_ITX;
+ hme_tcvr_write(sc, DP83840_BMCR,
+ (BMCR_LOOPBACK | BMCR_PDOWN | BMCR_ISOLATE));
+ result = hme_tcvr_read(sc, DP83840_BMCR);
+ if (result == TCVR_FAILURE) {
+ printf("%s: tcvr_reset failed\n", sc->sc_dev.dv_xname);
+ return -1;
+ }
+ tcvr->cfg = cfg | TCVR_CFG_PSELECT;
+ sc->sc_tcvr_type = HME_TCVR_EXTERNAL;
+ sc->sc_phyaddr = TCVR_PHYADDR_ETX;
+ }
+ else {
+ if (cfg & TCVR_CFG_MDIO1) {
+ tcvr->cfg = cfg | TCVR_CFG_PSELECT;
+ hme_tcvr_write(sc, DP83840_BMCR,
+ (BMCR_LOOPBACK | BMCR_PDOWN | BMCR_ISOLATE));
+ result = hme_tcvr_read(sc, DP83840_BMCR);
+ if (result == TCVR_FAILURE) {
+ printf("%s: tcvr_reset failed\n",
+ sc->sc_dev.dv_xname);
+ return -1;
+ }
+ tcvr->cfg = cfg & ~(TCVR_CFG_PSELECT);
+ sc->sc_tcvr_type = HME_TCVR_INTERNAL;
+ sc->sc_phyaddr = TCVR_PHYADDR_ITX;
+ }
+ }
+
+ hme_tcvr_write(sc, DP83840_BMCR, BMCR_RESET);
+
+ while (--tries) {
+ result = hme_tcvr_read(sc, DP83840_BMCR);
+ if (result == TCVR_FAILURE)
+ return -1;
+ sc->sc_sw.bmcr = result;
+ if (!(result & BMCR_RESET))
+ break;
+ DELAY(200);
+ }
+ if (!tries) {
+ printf("%s: bmcr reset failed\n", sc->sc_dev.dv_xname);
+ return -1;
+ }
+
+ sc->sc_sw.bmsr = hme_tcvr_read(sc, DP83840_BMSR);
+ sc->sc_sw.phyidr1 = hme_tcvr_read(sc, DP83840_PHYIDR1);
+ sc->sc_sw.phyidr2 = hme_tcvr_read(sc, DP83840_PHYIDR2);
+ sc->sc_sw.anar = hme_tcvr_read(sc, DP83840_BMSR);
+
+ sc->sc_sw.bmcr &= ~(BMCR_ISOLATE);
+ hme_tcvr_write(sc, DP83840_BMCR, sc->sc_sw.bmcr);
+
+ tries = XCVR_UNISOLATE_TRIES;
+ while (--tries) {
+ result = hme_tcvr_read(sc, DP83840_BMCR);
+ if (result == TCVR_FAILURE)
+ return -1;
+ if (!(result & BMCR_ISOLATE))
+ break;
+ DELAY(200);
+ }
+ if (!tries) {
+ printf("%s: bmcr unisolate failed\n", sc->sc_dev.dv_xname);
+ return -1;
+ }
+
+ result = hme_tcvr_read(sc, DP83840_PCR);
+ hme_tcvr_write(sc, DP83840_PCR, (result | PCR_CIM_DIS));
+ return 0;
+}
+
+
+/*
+ * We need to know whether we are using an internal or external transceiver.
+ */
+static void
+hme_tcvr_check(sc)
+ struct hme_softc *sc;
+{
+ struct hme_tcvr *tcvr = sc->sc_tcvr;
+ u_int32_t cfg = tcvr->cfg;
+
+ /* polling? */
+ if (sc->sc_flags & HME_FLAG_POLL) {
+ if (sc->sc_tcvr_type == HME_TCVR_INTERNAL) {
+ hme_poll_stop(sc);
+ sc->sc_phyaddr = TCVR_PHYADDR_ETX;
+ sc->sc_tcvr_type = HME_TCVR_EXTERNAL;
+ cfg &= ~(TCVR_CFG_PENABLE);
+ cfg |= TCVR_CFG_PSELECT;
+ tcvr->cfg = cfg;
+ }
+ else {
+ if (!(tcvr->status >> 16)) {
+ hme_poll_stop(sc);
+ sc->sc_phyaddr = TCVR_PHYADDR_ITX;
+ sc->sc_tcvr_type = HME_TCVR_INTERNAL;
+ cfg &= ~(TCVR_CFG_PSELECT);
+ tcvr->cfg = cfg;
+ }
+ }
+ }
+ else {
+ u_int32_t cfg2 = tcvr->cfg;
+
+ if (cfg2 & TCVR_CFG_MDIO1) {
+ tcvr->cfg = cfg | TCVR_CFG_PSELECT;
+ sc->sc_phyaddr = TCVR_PHYADDR_ETX;
+ sc->sc_tcvr_type = HME_TCVR_EXTERNAL;
+ }
+ else {
+ if (cfg2 & TCVR_CFG_MDIO0) {
+ tcvr->cfg = cfg & ~(TCVR_CFG_PSELECT);
+ sc->sc_phyaddr = TCVR_PHYADDR_ITX;
+ sc->sc_tcvr_type = HME_TCVR_INTERNAL;
+ }
+ else {
+ sc->sc_tcvr_type = HME_TCVR_NONE;
+ }
+ }
+ }
+}
+
+static void
+hme_poll_stop(sc)
+ struct hme_softc *sc;
+{
+ struct hme_tcvr *tcvr = sc->sc_tcvr;
+
+ /* if not polling, or polling not enabled, we're done. */
+ if ((sc->sc_flags & (HME_FLAG_POLLENABLE | HME_FLAG_POLL)) !=
+ (HME_FLAG_POLLENABLE | HME_FLAG_POLL))
+ return;
+
+ /* Turn off MIF interrupts, and diable polling */
+ tcvr->int_mask = 0xffff;
+ tcvr->cfg &= ~(TCVR_CFG_PENABLE);
+ sc->sc_flags &= ~(HME_FLAG_POLL);
+ DELAY(200);
+}
+
+#define XCVR_WRITE_TRIES 16
+
+static void
+hme_tcvr_write(sc, reg, val)
+ struct hme_softc *sc;
+ int reg;
+ u_short val;
+{
+ struct hme_tcvr *tcvr = sc->sc_tcvr;
+ int tries = XCVR_WRITE_TRIES;
+
+ /* Use the bitbang? */
+ if (! (sc->sc_flags & HME_FLAG_FENABLE))
+ return hme_tcvr_bb_write(sc, reg, val);
+
+ /* No, good... we just write to the tcvr frame */
+ tcvr->frame = (FRAME_WRITE | sc->sc_phyaddr << 23) |
+ ((reg & 0xff) << 18) |
+ (val & 0xffff);
+ while (!(tcvr->frame & 0x10000) && (tries != 0)) {
+ tries--;
+ DELAY(200);
+ }
+
+ if (!tries)
+ printf("%s: tcvr_write failed\n", sc->sc_dev.dv_xname);
+}
+
+#define XCVR_READ_TRIES 16
+
+static int
+hme_tcvr_read(sc, reg)
+ struct hme_softc *sc;
+ int reg;
+{
+ struct hme_tcvr *tcvr = sc->sc_tcvr;
+ int tries = XCVR_READ_TRIES;
+
+ if (sc->sc_tcvr_type == HME_TCVR_NONE) {
+ printf("%s: no transceiver type\n", sc->sc_dev.dv_xname);
+ return TCVR_FAILURE;
+ }
+
+ /* Use the bitbang? */
+ if (! (sc->sc_flags & HME_FLAG_FENABLE))
+ return hme_tcvr_bb_read(sc, reg);
+
+ /* No, good... we just write/read to the tcvr frame */
+ tcvr->frame = (FRAME_READ | sc->sc_phyaddr << 23) |
+ ((reg & 0xff) << 18);
+ while (!(tcvr->frame & 0x10000) && (tries != 0)) {
+ tries--;
+ DELAY(200);
+ }
+
+ if (!tries) {
+ printf("%s: tcvr_write failed\n", sc->sc_dev.dv_xname);
+ return TCVR_FAILURE;
+ }
+ return (tcvr->frame & 0xffff);
+}
+
+/*
+ * Writing to the serial BitBang, is a matter of putting the bit
+ * into the data register, then strobing the clock.
+ */
+static void
+hme_tcvr_bb_writeb(sc, b)
+ struct hme_softc *sc;
+ int b;
+{
+ sc->sc_tcvr->bb_data = b & 0x1;
+ sc->sc_tcvr->bb_clock = 0;
+ sc->sc_tcvr->bb_clock = 1;
+}
+
+static int
+hme_tcvr_bb_readb(sc)
+ struct hme_softc *sc;
+{
+ int ret;
+
+ sc->sc_tcvr->bb_clock = 0;
+ DELAY(10);
+ if (sc->sc_tcvr_type == HME_TCVR_INTERNAL)
+ ret = sc->sc_tcvr->cfg & TCVR_CFG_MDIO0;
+ else
+ ret = sc->sc_tcvr->cfg & TCVR_CFG_MDIO1;
+ sc->sc_tcvr->bb_clock = 1;
+ return ((ret) ? 1 : 0);
+}
+
+static void
+hme_tcvr_bb_write(sc, reg, val)
+ struct hme_softc *sc;
+ int reg;
+ u_short val;
+{
+ struct hme_tcvr *tcvr = sc->sc_tcvr;
+ int i;
+
+ tcvr->bb_oenab = 1; /* turn on bitbang intrs */
+
+ for (i = 0; i < 32; i++) /* make bitbang idle */
+ hme_tcvr_bb_writeb(sc, 1);
+
+ hme_tcvr_bb_writeb(sc, 0); /* 0101 signals a write */
+ hme_tcvr_bb_writeb(sc, 1);
+ hme_tcvr_bb_writeb(sc, 0);
+ hme_tcvr_bb_writeb(sc, 1);
+
+ for (i = 4; i >= 0; i--) /* send PHY addr */
+ hme_tcvr_bb_writeb(sc, ((sc->sc_phyaddr & 0xff) >> i) & 0x1);
+
+ for (i = 4; i >= 0; i--) /* send register num */
+ hme_tcvr_bb_writeb(sc, ((reg & 0xff) >> i) & 0x1);
+
+ hme_tcvr_bb_writeb(sc, 1); /* get ready for data */
+ hme_tcvr_bb_writeb(sc, 0);
+
+ for (i = 15; i >= 0; i--) /* send new value */
+ hme_tcvr_bb_writeb(sc, (val >> i) & 0x1);
+
+ tcvr->bb_oenab = 0; /* turn off bitbang intrs */
+}
+
+static int
+hme_tcvr_bb_read(sc, reg)
+ struct hme_softc *sc;
+ int reg;
+{
+ struct hme_tcvr *tcvr = sc->sc_tcvr;
+ int ret = 0, i;
+
+ tcvr->bb_oenab = 1; /* turn on bitbang intrs */
+
+ for (i = 0; i < 32; i++) /* make bitbang idle */
+ hme_tcvr_bb_writeb(sc, 1);
+
+ hme_tcvr_bb_writeb(sc, 0); /* 0110 signals a read */
+ hme_tcvr_bb_writeb(sc, 1);
+ hme_tcvr_bb_writeb(sc, 1);
+ hme_tcvr_bb_writeb(sc, 0);
+
+ for (i = 4; i >= 0; i--) /* send PHY addr */
+ hme_tcvr_bb_writeb(sc, ((sc->sc_phyaddr & 0xff) >> i) & 0x1);
+
+ for (i = 4; i >= 0; i--) /* send register num */
+ hme_tcvr_bb_writeb(sc, ((reg & 0xff) >> i) & 0x1);
+
+ tcvr->bb_oenab = 0; /* turn off bitbang intrs */
+
+ hme_tcvr_bb_readb(sc); /* ignore... */
+
+ for (i = 15; i >= 15; i--) /* read value */
+ ret |= hme_tcvr_bb_readb(sc) << i;
+
+ hme_tcvr_bb_readb(sc); /* ignore... */
+ hme_tcvr_bb_readb(sc); /* ignore... */
+ hme_tcvr_bb_readb(sc); /* ignore... */
+
+ return ret;
+}
+
+static void
+hme_auto_negotiate(sc)
+ struct hme_softc *sc;
+{
+ int tries;
+
+ /* grab all of the registers */
+ sc->sc_sw.bmsr = hme_tcvr_read(sc, DP83840_BMSR);
+ sc->sc_sw.bmcr = hme_tcvr_read(sc, DP83840_BMCR);
+ sc->sc_sw.phyidr1 = hme_tcvr_read(sc, DP83840_PHYIDR1);
+ sc->sc_sw.phyidr2 = hme_tcvr_read(sc, DP83840_PHYIDR2);
+ sc->sc_sw.anar = hme_tcvr_read(sc, DP83840_ANAR);
+
+ /* can this board autonegotiate? No, do it manually */
+ if (! (sc->sc_sw.bmsr & BMSR_ANC))
+ hme_manual_negotiate(sc);
+
+ /* advertise -everything- supported */
+ if (sc->sc_sw.bmsr & BMSR_10BASET_HALF)
+ sc->sc_sw.anar |= ANAR_10;
+ else
+ sc->sc_sw.anar &= ~(ANAR_10);
+
+ if (sc->sc_sw.bmsr & BMSR_10BASET_FULL)
+ sc->sc_sw.anar |= ANAR_10_FD;
+ else
+ sc->sc_sw.anar &= ~(ANAR_10_FD);
+
+ if (sc->sc_sw.bmsr & BMSR_100BASETX_HALF)
+ sc->sc_sw.anar |= ANAR_TX;
+ else
+ sc->sc_sw.anar &= ~(ANAR_TX);
+
+ if (sc->sc_sw.bmsr & BMSR_100BASETX_FULL)
+ sc->sc_sw.anar |= ANAR_TX_FD;
+ else
+ sc->sc_sw.anar &= ~(ANAR_TX_FD);
+
+ hme_tcvr_write(sc, DP83840_ANAR, sc->sc_sw.anar);
+
+ /* Start autonegoiation */
+ sc->sc_sw.bmcr |= BMCR_ANE; /* enable auto-neg */
+ hme_tcvr_write(sc, DP83840_BMCR, sc->sc_sw.bmcr);
+ sc->sc_sw.bmcr |= BMCR_RAN; /* force a restart */
+ hme_tcvr_write(sc, DP83840_BMCR, sc->sc_sw.bmcr);
+
+ /* BMCR_RAN clears itself when it has started negotiation... */
+ tries = 64;
+ while (--tries) {
+ int r = hme_tcvr_read(sc, DP83840_BMCR);
+ if (r == TCVR_FAILURE)
+ return;
+ sc->sc_sw.bmcr = r;
+ if (! (sc->sc_sw.bmcr & BMCR_RAN))
+ break;
+ DELAY(100);
+ }
+ if (!tries) {
+ printf("%s: failed to start auto-negotiation\n",
+ sc->sc_dev.dv_xname);
+ hme_manual_negotiate(sc);
+ return;
+ }
+ sc->sc_an_state = HME_TIMER_AUTONEG;
+ sc->sc_an_ticks = 0;
+ timeout(hme_negotiate_watchdog, sc, (12 * hz)/10);
+}
+
+static void
+hme_manual_negotiate(sc)
+ struct hme_softc *sc;
+{
+ printf("%s: Starting manual negotiation... not yet!\n",
+ sc->sc_dev.dv_xname);
+}
+
+/*
+ * If auto-negotiating, check to see if it has completed successfully. If so,
+ * wait for a link up. If it completed unsucessfully, try the manual process.
+ */
+static void
+hme_negotiate_watchdog(arg)
+ void *arg;
+{
+ struct hme_softc *sc = (struct hme_softc *)arg;
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+
+ sc->sc_an_ticks++;
+ switch (sc->sc_an_state) {
+ case HME_TIMER_DONE:
+ return;
+ case HME_TIMER_AUTONEG:
+ printf("%s: tick: autoneg...\n", sc->sc_dev.dv_xname);
+ sc->sc_sw.bmsr = hme_tcvr_read(sc, DP83840_BMSR);
+ if (sc->sc_sw.bmsr & BMSR_ANCOMPLETE) {
+ sc->sc_an_state = HME_TIMER_LINKUP;
+ sc->sc_an_ticks = 0;
+ timeout(hme_negotiate_watchdog, sc, (12 * hz)/10);
+ return;
+ }
+ if (sc->sc_an_ticks > 10) {
+ printf("%s: auto-negotiation failed.\n",
+ sc->sc_dev.dv_xname);
+ return;
+ }
+ timeout(hme_negotiate_watchdog, sc, (12 * hz)/10);
+ break;
+ case HME_TIMER_LINKUP:
+ printf("%s: tick: linkup..\n", sc->sc_dev.dv_xname);
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+ ifp->if_timer = 0;
+ hmestart(ifp);
+ sc->sc_sw.bmsr = hme_tcvr_read(sc, DP83840_BMSR);
+ if (sc->sc_sw.bmsr & BMSR_LINKSTATUS) {
+ sc->sc_an_state = HME_TIMER_DONE;
+ sc->sc_an_ticks = 0;
+ hme_print_link_mode(sc);
+ return;
+ }
+ if ((sc->sc_an_ticks % 10) == 0) {
+ printf("%s: link down...\n", sc->sc_dev.dv_xname);
+ timeout(hme_negotiate_watchdog, sc, (12 * hz)/10);
+ return;
+ }
+ }
+}
+
+static void
+hme_print_link_mode(sc)
+ struct hme_softc *sc;
+{
+ sc->sc_sw.anlpar = hme_tcvr_read(sc, DP83840_ANLPAR);
+ printf("%s: %s transceiver up %dMb/s %s duplex\n",
+ sc->sc_dev.dv_xname,
+ (sc->sc_tcvr_type == HME_TCVR_EXTERNAL) ? "external" : "internal",
+ (sc->sc_sw.anlpar & (ANLPAR_TX_FD | ANLPAR_TX)) ? 100 : 10,
+ (sc->sc_sw.anlpar & (ANLPAR_TX_FD | ANLPAR_10_FD)) ? "full" : "half");
+}
+
+#define RESET_TRIES 32
+
+static void
+hme_reset_tx(sc)
+ struct hme_softc *sc;
+{
+ int tries = RESET_TRIES;
+ struct hme_cr *cr = sc->sc_cr;
+
+ cr->tx_swreset = 0;
+ while (tries-- && (cr->tx_swreset & 1))
+ DELAY(20);
+
+ if (!tries)
+ printf("%s: reset tx failed\n", sc->sc_dev.dv_xname);
+}
+
+static void
+hme_reset_rx(sc)
+ struct hme_softc *sc;
+{
+ int tries = RESET_TRIES;
+ struct hme_cr *cr = sc->sc_cr;
+
+ cr->rx_swreset = 0;
+ while (tries-- && (cr->rx_swreset & 1))
+ DELAY(20);
+
+ if (!tries)
+ printf("%s: reset rx failed\n", sc->sc_dev.dv_xname);
+}
+
+static void
+hme_meminit(sc)
+ struct hme_softc *sc;
+{
+ struct hme_desc *desc = sc->sc_desc;
+ int i;
+
+ /* setup tx descriptors */
+ sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
+ for (i = 0; i < TX_RING_SIZE; i++)
+ desc->hme_txd[i].tx_flags = 0;
+
+ /* setup rx descriptors */
+ sc->sc_last_rd = 0;
+ for (i = 0; i < RX_RING_SIZE; i++) {
+
+ desc->hme_rxd[i].rx_addr = (u_long) sc->sc_bufs_dva +
+ (((u_long) &(sc->sc_bufs->rx_buf[i])) -
+ ((u_long) sc->sc_bufs));
+
+ desc->hme_rxd[i].rx_flags =
+ RXFLAG_OWN | ((RX_PKT_BUF_SZ - RX_OFFSET) << 16);
+ }
+
+}
+
+/*
+ * Pull data off an interface.
+ * Len is the 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.
+ */
+static struct mbuf *
+hme_get(sc, idx, totlen)
+ struct hme_softc *sc;
+ int idx, totlen;
+{
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ struct mbuf *m;
+ struct mbuf *top, **mp;
+ int len, pad, boff = 0;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return (NULL);
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = totlen;
+ pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
+ m->m_data += pad;
+ len = MHLEN - pad;
+ top = NULL;
+ mp = &top;
+
+ while (totlen > 0) {
+ if (top) {
+ MGET(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL) {
+ m_freem(top);
+ return NULL;
+ }
+ len = MLEN;
+ }
+ if (top && totlen >= MINCLSIZE) {
+ MCLGET(m, M_DONTWAIT);
+ if (m->m_flags & M_EXT)
+ len = MCLBYTES;
+ }
+ m->m_len = len = min(totlen, len);
+ bcopy(&(sc->sc_bufs->rx_buf[idx][boff + RX_OFFSET]),
+ mtod(m, caddr_t), len);
+ boff += len;
+ totlen -= len;
+ *mp = m;
+ mp = &m->m_next;
+ }
+
+ return (top);
+}
+
+static int
+hme_put(sc, idx, m)
+ struct hme_softc *sc;
+ int idx;
+ struct mbuf *m;
+{
+ struct mbuf *n;
+ int len, tlen = 0, boff = 0;
+
+ for (; m; m = n) {
+ len = m->m_len;
+ if (len == 0) {
+ MFREE(m, n);
+ continue;
+ }
+ bcopy(mtod(m, caddr_t), &(sc->sc_bufs->tx_buf[idx][boff]), len);
+ boff += len;
+ tlen += len;
+ MFREE(m, n);
+ }
+ return tlen;
+}
+
+/*
+ * mif interrupt
+ */
+static int
+hme_mint(sc, why)
+ struct hme_softc *sc;
+ u_int32_t why;
+{
+ sc->sc_sw.bmcr = hme_tcvr_read(sc, DP83840_BMCR);
+ sc->sc_sw.anlpar = hme_tcvr_read(sc, DP83840_ANLPAR);
+
+ printf("%s: link status changed\n", sc->sc_dev.dv_xname);
+ if (sc->sc_sw.anlpar & ANLPAR_TX_FD) {
+ sc->sc_sw.bmcr |= (BMCR_SPEED | BMCR_DUPLEX);
+ } else if (sc->sc_sw.anlpar & ANLPAR_TX) {
+ sc->sc_sw.bmcr |= BMCR_SPEED;
+ } else if (sc->sc_sw.anlpar & ANLPAR_10_FD) {
+ sc->sc_sw.bmcr |= BMCR_DUPLEX;
+ } /* else 10Mb half duplex... */
+ hme_tcvr_write(sc, DP83840_BMCR, sc->sc_sw.bmcr);
+ hme_print_link_mode(sc);
+ hme_poll_stop(sc);
+ return 1;
+}
+
+/*
+ * receive interrupt
+ */
+static int
+hme_rint(sc, why)
+ struct hme_softc *sc;
+ u_int32_t why;
+{
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ int bix, len;
+ struct hme_rxd rxd;
+
+ bix = sc->sc_last_rd;
+
+ /* Process all buffers with valid data. */
+ for (;;) {
+ bcopy(&(sc->sc_desc->hme_rxd[bix]), &rxd, sizeof(rxd));
+ len = rxd.rx_flags >> 16;
+
+ if (rxd.rx_flags & RXFLAG_OWN)
+ break;
+
+ if (rxd.rx_flags & RXFLAG_OVERFLOW)
+ ifp->if_ierrors++;
+ else
+ hme_read(sc, bix, len);
+
+ rxd.rx_flags = RXFLAG_OWN|((RX_PKT_BUF_SZ - RX_OFFSET) << 16);
+ bcopy(&rxd, &(sc->sc_desc->hme_rxd[bix]), sizeof(rxd));
+
+ if (++bix == RX_RING_SIZE)
+ bix = 0;
+ }
+
+ sc->sc_last_rd = bix;
+
+ return 1;
+}
+
+/*
+ * error interrupt
+ */
+static int
+hme_eint(sc, why)
+ struct hme_softc *sc;
+ u_int32_t why;
+{
+ if (why & GR_STAT_RFIFOVF) { /* probably dma error */
+ printf("%s: receive fifo overflow\n", sc->sc_dev.dv_xname);
+ hmereset(sc);
+ }
+
+ if (why & GR_STAT_STSTERR) {
+ printf("%s: SQE test failed: resetting\n", sc->sc_dev.dv_xname);
+ hmereset(sc);
+ }
+
+ if (why & GR_STAT_TFIFO_UND) { /* probably dma error */
+ printf("%s: tx fifo underrun\n", sc->sc_dev.dv_xname);
+ hmereset(sc);
+ }
+
+ if (why & GR_STAT_MAXPKTERR) { /* driver bug */
+ printf("%s: tx max packet size error\n", sc->sc_dev.dv_xname);
+ hmereset(sc);
+ }
+
+ if (why & GR_STAT_NORXD) { /* driver bug */
+ printf("%s: out of receive descriptors\n", sc->sc_dev.dv_xname);
+ hmereset(sc);
+ }
+
+ if (why & GR_STAT_EOPERR) {
+ printf("%s: eop not set in tx descriptor\n",
+ sc->sc_dev.dv_xname);
+ hmereset(sc);
+ }
+
+ if (why & (GR_STAT_RXERR | GR_STAT_RXPERR | GR_STAT_RXTERR)) {
+ printf("%s: rx dma error < ", sc->sc_dev.dv_xname);
+ if (why & GR_STAT_RXERR)
+ printf("Generic ");
+ if (why & GR_STAT_RXPERR);
+ printf("Parity ");
+ if (why & GR_STAT_RXTERR)
+ printf("RxTag ");
+ printf(" >\n");
+ hmereset(sc);
+ }
+
+ if (why &
+ (GR_STAT_TXEACK|GR_STAT_TXLERR|GR_STAT_TXPERR|GR_STAT_TXTERR)) {
+ printf("%s: rx dma error < ", sc->sc_dev.dv_xname);
+ if (why & GR_STAT_TXEACK)
+ printf("Generic ");
+ if (why & GR_STAT_TXLERR);
+ printf("Late ");
+ if (why & GR_STAT_TXPERR)
+ printf("Parity ");
+ if (why & GR_STAT_TXTERR);
+ printf("TxTag ");
+ printf(" >\n");
+ hmereset(sc);
+ }
+
+ if (why & (GR_STAT_SLVERR | GR_STAT_SLVPERR)) {
+ printf("%s: sbus %s error accessing registers\n",
+ sc->sc_dev.dv_xname,
+ (why & GR_STAT_SLVPERR) ? "parity" : "generic");
+ hmereset(sc);
+ }
+
+ return 1;
+}
+
+/*
+ * transmit interrupt
+ */
+static int
+hme_tint(sc, why)
+ struct hme_softc *sc;
+ u_int32_t why;
+{
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ int bix;
+ struct hme_txd txd;
+
+ bix = sc->sc_first_td;
+
+ for (;;) {
+ if (sc->sc_no_td <= 0)
+ break;
+
+ bcopy(&(sc->sc_desc->hme_txd[bix]), &txd, sizeof(txd));
+
+ if (txd.tx_flags & TXFLAG_OWN)
+ break;
+
+ ifp->if_flags &= ~IFF_OACTIVE;
+ ifp->if_opackets++;
+
+ if (++bix == TX_RING_SIZE)
+ bix = 0;
+
+ --sc->sc_no_td;
+ }
+
+ sc->sc_first_td = bix;
+
+ hmestart(ifp);
+
+ if (sc->sc_no_td == 0)
+ ifp->if_timer = 0;
+
+ return 1;
+}
+
+/*
+ * Interrup handler
+ */
+int
+hmeintr(v)
+ void *v;
+{
+ struct hme_softc *sc = (struct hme_softc *)v;
+ struct hme_gr *gr = sc->sc_gr;
+ u_int32_t why;
+ int r = 0;
+
+ why = gr->stat;
+
+ if (why & GR_STAT_ALL_ERRORS)
+ r |= hme_eint(sc, why);
+
+ if (why & GR_STAT_MIFIRQ)
+ r |= hme_mint(sc, why);
+
+ if (why & (GR_STAT_TXALL | GR_STAT_HOSTTOTX))
+ r |= hme_tint(sc, why);
+
+ if (why & GR_STAT_RXTOHOST)
+ r |= hme_rint(sc, why);
+
+ return (r);
+}
+
+static void
+hme_read(sc, idx, len)
+ struct hme_softc *sc;
+ int idx, len;
+{
+ struct ifnet *ifp = &sc->sc_arpcom.ac_if;
+ struct ether_header *eh;
+ struct mbuf *m;
+
+ if (len <= sizeof(struct ether_header) ||
+ len > ETHERMTU + sizeof(struct ether_header)) {
+
+ printf("%s: invalid packet size %d; dropping\n",
+ sc->sc_dev.dv_xname, len);
+
+ ifp->if_ierrors++;
+ return;
+ }
+
+ /* Pull packet off interface. */
+ m = hme_get(sc, idx, len);
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ return;
+ }
+
+ ifp->if_ipackets++;
+
+ /* We assume that the header fit entirely in one mbuf. */
+ eh = mtod(m, struct ether_header *);
+
+#if NBPFILTER > 0
+ /*
+ * Check if there's a BPF listener on this interface.
+ * If so, hand off the raw packet to BPF.
+ */
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m);
+#endif
+ /* Pass the packet up, with the ether header sort-of removed. */
+ m_adj(m, sizeof(struct ether_header));
+ ether_input(ifp, eh, m);
+}
diff --git a/sys/arch/sparc/dev/hmereg.h b/sys/arch/sparc/dev/hmereg.h
new file mode 100644
index 00000000000..98d481a8210
--- /dev/null
+++ b/sys/arch/sparc/dev/hmereg.h
@@ -0,0 +1,582 @@
+/* $OpenBSD: hmereg.h,v 1.1 1998/07/10 19:09:12 jason Exp $ */
+
+/*
+ * Copyright (c) 1998 Jason L. Wright (jason@thought.net)
+ * All rights reserved.
+ *
+ * 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 Jason L. Wright
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#define HME_DEFAULT_JSIZE 4
+#define HME_DEFAULT_IPKT_GAP0 16
+#define HME_DEFAULT_IPKT_GAP1 8
+#define HME_DEFAULT_IPKT_GAP2 4
+#define MEMSIZE 4096
+
+/* global registers */
+struct hme_gr {
+ volatile u_int32_t reset; /* reset tx/rx */
+ volatile u_int32_t cfg; /* config */
+ volatile u_int32_t _padding[62]; /* unused */
+ volatile u_int32_t stat; /* intr status */
+ volatile u_int32_t imask; /* intr mask */
+};
+
+/* hme_gr.reset (software reset register) */
+#define GR_RESET_ETX 0x01 /* reset external tx */
+#define GR_RESET_ERX 0x02 /* reset external rx */
+#define GR_RESET_ALL (GR_RESET_ETX | GR_RESET_ERX)
+
+/* hme_gr.cfg (configuration register) */
+#define GR_CFG_BURSTMSK 0x03 /* burst mask */
+#define GR_CFG_BURST16 0x00 /* 16 byte bursts */
+#define GR_CFG_BURST32 0x01 /* 32 byte bursts */
+#define GR_CFG_BURST64 0x02 /* 32 byte bursts */
+#define GR_CFG_64BIT 0x04
+#define GR_CFG_PARITY 0x08
+#define GR_CFG_RESV 0x10
+
+/* hme_gr.stat (interrupt status register) */
+#define GR_STAT_GOTFRAME 0x00000001 /* frame received */
+#define GR_STAT_RCNTEXP 0x00000002 /* rx frame count expired */
+#define GR_STAT_ACNTEXP 0x00000004 /* align error count expired */
+#define GR_STAT_CCNTEXP 0x00000008 /* crc error count expired */
+#define GR_STAT_LCNTEXP 0x00000010 /* length error count expired */
+#define GR_STAT_RFIFOVF 0x00000020 /* rx fifo overflow */
+#define GR_STAT_CVCNTEXP 0x00000040 /* code violation counter expired */
+#define GR_STAT_STSTERR 0x00000080 /* xif sqe test failed */
+#define GR_STAT_SENTFRAME 0x00000100 /* frame sent */
+#define GR_STAT_TFIFO_UND 0x00000200 /* tx fifo underrun */
+#define GR_STAT_MAXPKTERR 0x00000400 /* max-packet size error */
+#define GR_STAT_NCNTEXP 0x00000800 /* normal collision count expired */
+#define GR_STAT_ECNTEXP 0x00001000 /* excess collision count expired */
+#define GR_STAT_LCCNTEXP 0x00002000 /* late collision count expired */
+#define GR_STAT_FCNTEXP 0x00004000 /* first collision count expired */
+#define GR_STAT_DTIMEXP 0x00008000 /* defer timer expired */
+#define GR_STAT_RXTOHOST 0x00010000 /* pkt moved from rx fifo->memory */
+#define GR_STAT_NORXD 0x00020000 /* out of receive descriptors */
+#define GR_STAT_RXERR 0x00040000 /* rx dma error */
+#define GR_STAT_RXLATERR 0x00080000 /* late error during rx dma */
+#define GR_STAT_RXPERR 0x00100000 /* parity error during rx dma */
+#define GR_STAT_RXTERR 0x00200000 /* tag error during rx dma */
+#define GR_STAT_EOPERR 0x00400000 /* tx descriptor did not set EOP */
+#define GR_STAT_MIFIRQ 0x00800000 /* mif needs attention */
+#define GR_STAT_HOSTTOTX 0x01000000 /* pkt moved from memory->tx fifo */
+#define GR_STAT_TXALL 0x02000000 /* all pkts in fifo transmitted */
+#define GR_STAT_TXEACK 0x04000000 /* error during tx dma */
+#define GR_STAT_TXLERR 0x08000000 /* late error during tx dma */
+#define GR_STAT_TXPERR 0x10000000 /* parity error during tx dma */
+#define GR_STAT_TXTERR 0x20000000 /* tag error durig tx dma */
+#define GR_STAT_SLVERR 0x40000000 /* pio access error */
+#define GR_STAT_SLVPERR 0x80000000 /* pio access parity error */
+
+/* all the errors to worry about */
+#define GR_STAT_ALL_ERRORS \
+ (GR_STAT_SLVPERR | GR_STAT_SLVERR | GR_STAT_TXTERR | \
+ GR_STAT_TXPERR | GR_STAT_TXLERR | GR_STAT_TXEACK | \
+ GR_STAT_EOPERR | GR_STAT_RXTERR | GR_STAT_RXPERR | \
+ GR_STAT_RXLATERR | GR_STAT_RXERR | GR_STAT_NORXD | \
+ GR_STAT_DTIMEXP | GR_STAT_FCNTEXP | GR_STAT_LCCNTEXP | \
+ GR_STAT_ECNTEXP | GR_STAT_NCNTEXP | GR_STAT_MAXPKTERR | \
+ GR_STAT_TFIFO_UND | GR_STAT_STSTERR | GR_STAT_CVCNTEXP | \
+ GR_STAT_RFIFOVF | GR_STAT_LCNTEXP | GR_STAT_CCNTEXP | \
+ GR_STAT_ACNTEXP)
+
+
+/* hme_gr.stat (interrupt status register) */
+#define GR_IMASK_GOTFRAME 0x00000001 /* frame received */
+#define GR_IMASK_RCNTEXP 0x00000002 /* rx frame count expired */
+#define GR_IMASK_ACNTEXP 0x00000004 /* align error count expired */
+#define GR_IMASK_CCNTEXP 0x00000008 /* crc error count expired */
+#define GR_IMASK_LCNTEXP 0x00000010 /* length error count expired */
+#define GR_IMASK_RFIFOVF 0x00000020 /* rx fifo overflow */
+#define GR_IMASK_CVCNTEXP 0x00000040 /* code violation count expired */
+#define GR_IMASK_STSTERR 0x00000080 /* xif sqe test failed */
+#define GR_IMASK_SENTFRAME 0x00000100 /* frame sent */
+#define GR_IMASK_TFIFO_UND 0x00000200 /* tx fifo underrun */
+#define GR_IMASK_MAXPKTERR 0x00000400 /* max-packet size error */
+#define GR_IMASK_NCNTEXP 0x00000800 /* normal collision count expired */
+#define GR_IMASK_ECNTEXP 0x00001000 /* excess collision count expired */
+#define GR_IMASK_LCCNTEXP 0x00002000 /* late collision count expired */
+#define GR_IMASK_FCNTEXP 0x00004000 /* first collision count expired */
+#define GR_IMASK_DTIMEXP 0x00008000 /* defer timer expired */
+#define GR_IMASK_RXTOHOST 0x00010000 /* pkt moved from rx fifo->memory */
+#define GR_IMASK_NORXD 0x00020000 /* out of receive descriptors */
+#define GR_IMASK_RXERR 0x00040000 /* rx dma error */
+#define GR_IMASK_RXLATERR 0x00080000 /* late error during rx dma */
+#define GR_IMASK_RXPERR 0x00100000 /* parity error during rx dma */
+#define GR_IMASK_RXTERR 0x00200000 /* tag error during rx dma */
+#define GR_IMASK_EOPERR 0x00400000 /* tx descriptor did not set EOP */
+#define GR_IMASK_MIFIRQ 0x00800000 /* mif needs attention */
+#define GR_IMASK_HOSTTOTX 0x01000000 /* pkt moved from memory->tx fifo */
+#define GR_IMASK_TXALL 0x02000000 /* all pkts in fifo transmitted */
+#define GR_IMASK_TXEACK 0x04000000 /* error during tx dma */
+#define GR_IMASK_TXLERR 0x08000000 /* late error during tx dma */
+#define GR_IMASK_TXPERR 0x10000000 /* parity error during tx dma */
+#define GR_IMASK_TXTERR 0x20000000 /* tag error during tx dma */
+#define GR_IMASK_SLVERR 0x40000000 /* pio access error */
+#define GR_IMASK_SLVPERR 0x80000000 /* PIO access parity error */
+
+/*
+ * external transmitter registers
+ */
+struct hme_txr {
+ volatile u_int32_t tx_pnding; /* tx pending/wakeup */
+ volatile u_int32_t cfg; /* tx cfg */
+ volatile u_int32_t tx_ring; /* tx ring ptr */
+ volatile u_int32_t tx_bbase; /* tx buffer base */
+ volatile u_int32_t tx_bdisp; /* tx buffer displacement */
+ volatile u_int32_t tx_fifo_wptr; /* tx fifo write pointer */
+ volatile u_int32_t tx_fifo_swptr; /* tx fifo write ptr (shadow) */
+ volatile u_int32_t tx_fifo_rptr; /* tx fifo read pointer */
+ volatile u_int32_t tx_fifo_srptr; /* tx fifo read ptr (shadow) */
+ volatile u_int32_t tx_fifo_pcnt; /* tx fifo packet counter */
+ volatile u_int32_t smachine; /* tx state machine */
+ volatile u_int32_t tx_rsize; /* tx ring size */
+ volatile u_int32_t tx_bptr; /* tx buffer pointer */
+};
+
+/* hme_txr.tx_pnding (tx pending/wakeup) */
+#define TXR_TP_DMAWAKEUP 0x00000001 /* Restart transmit dma */
+
+/* hme_txr.tx_cfg (tx configuration) */
+#define TXR_CFG_DMAENABLE 0x00000001 /* enable tx dma */
+#define TXR_CFG_FIFOTHRESH 0x000003fe /* tx fifo threshold */
+#define TXR_CFG_IRQDAFTER 0x00000400 /* intr after tx-fifo empty */
+#define TXR_CFG_IRQDBEFORE 0x00000000 /* intr before tx-fifo empty */
+#define TXR_RSIZE_SHIFT 4
+
+/*
+ * external receiver registers
+ */
+struct hme_rxr {
+ volatile u_int32_t cfg; /* rx cfg */
+ volatile u_int32_t rx_ring; /* rx ring pointer */
+ volatile u_int32_t rx_bptr; /* rx buffer ptr */
+ volatile u_int32_t rx_fifo_wptr; /* rx fifo write ptr */
+ volatile u_int32_t rx_fifo_swptr; /* rx fifo write ptr (shadow) */
+ volatile u_int32_t rx_fifo_rptr; /* rx fifo read ptr */
+ volatile u_int32_t rx_fifo_srptr; /* rx fifo read ptr (shadow) */
+ volatile u_int32_t smachine; /* rx state machine */
+};
+
+/* hme_rxr.rx_cfg (rx configuration) */
+#define RXR_CFG_DMAENABLE 0x00000001 /* rx dma enable */
+#define RXR_CFG_reserved1 0x00000006 /* reserved bits */
+#define RXR_CFG_BYTEOFFSET 0x00000038 /* rx first byte offset */
+#define RXR_CFG_reserved2 0x000001c0 /* reserved bits */
+#define RXR_CFG_RINGSIZE32 0x00000000 /* rx descptr ring size: 32 */
+#define RXR_CFG_RINGSIZE64 0x00000200 /* rx descptr ring size: 64 */
+#define RXR_CFG_RINGSIZE128 0x00000400 /* rx descptr ring size: 128 */
+#define RXR_CFG_RINGSIZE256 0x00000600 /* rx descptr ring size: 128 */
+#define RXR_CFG_reserved3 0x0000f800 /* reserved bits */
+#define RXR_CFG_CSUMSTART 0x007f0000 /* rx offset of checksum */
+
+/*
+ * configuration registers
+ */
+struct hme_cr {
+ volatile u_int32_t xif_cfg; /* xif configuration reg */
+ volatile u_int32_t _padding[129]; /* reserved */
+ volatile u_int32_t tx_swreset; /* tx software reset */
+ volatile u_int32_t tx_cfg; /* tx configuration reg */
+ volatile u_int32_t ipkt_gap1; /* interpacket gap 1 */
+ volatile u_int32_t ipkt_gap2; /* interpacket gap 2 */
+ volatile u_int32_t attempt_limit; /* tx attempt limit */
+ volatile u_int32_t stime; /* tx slot time */
+ volatile u_int32_t preamble_len; /* len of tx preamble */
+ volatile u_int32_t preamble_patt; /* tx preamble pattern */
+ volatile u_int32_t tx_sframedelim; /* tx frame delimiter */
+ volatile u_int32_t jsize; /* tx jam size */
+ volatile u_int32_t tx_pkt_max; /* tx maximum pkt size */
+ volatile u_int32_t tx_pkt_min; /* tx minimum pkt size */
+ volatile u_int32_t peak_attempt; /* tx peak counter */
+ volatile u_int32_t dt_ctr; /* tx defer counter */
+ volatile u_int32_t nc_ctr; /* tx normal collision cntr */
+ volatile u_int32_t fc_ctr; /* tx first collision cntr */
+ volatile u_int32_t ex_ctr; /* tx execess collision cntr */
+ volatile u_int32_t lt_ctr; /* tx late collision cntr */
+ volatile u_int32_t rand_seed; /* tx random seed */
+ volatile u_int32_t tx_smachine; /* tx state machine */
+ volatile u_int32_t _padding2[44]; /* reserved */
+ volatile u_int32_t rx_swreset; /* rx software reset */
+ volatile u_int32_t rx_cfg; /* rx configuration */
+ volatile u_int32_t rx_pkt_max; /* rx maximum pkt size */
+ volatile u_int32_t rx_pkt_min; /* rx minimum pkt size */
+ volatile u_int32_t mac_addr2; /* macaddress register2 (MSB) */
+ volatile u_int32_t mac_addr1; /* macaddress register1 */
+ volatile u_int32_t mac_addr0; /* macaddress register0 (LSB) */
+ volatile u_int32_t fr_ctr; /* rx frame counter */
+ volatile u_int32_t gle_ctr; /* rx giant counter */
+ volatile u_int32_t unale_ctr; /* rx unaligned error cntr */
+ volatile u_int32_t rcrce_ctr; /* rx crc error cntr */
+ volatile u_int32_t rx_smachine; /* rx state machine */
+ volatile u_int32_t rx_cvalid; /* rx code violation */
+ volatile u_int32_t _padding3; /* reserved */
+ volatile u_int32_t htable3; /* hash table 3 */
+ volatile u_int32_t htable2; /* hash table 2 */
+ volatile u_int32_t htable1; /* hash table 1 */
+ volatile u_int32_t htable0; /* hash table 0 */
+ volatile u_int32_t afilter2; /* address filter 2 */
+ volatile u_int32_t afilter1; /* address filter 1 */
+ volatile u_int32_t afilter0; /* address filter 0 */
+ volatile u_int32_t afilter_mask; /* address filter mask */
+};
+
+/* BigMac XIF config register. */
+#define CR_XCFG_ODENABLE 0x00000001 /* Output driver enable */
+#define CR_XCFG_XLBACK 0x00000002 /* Loopback-mode XIF enable */
+#define CR_XCFG_MLBACK 0x00000004 /* Loopback-mode MII enable */
+#define CR_XCFG_MIIDISAB 0x00000008 /* MII receive buffer disable */
+#define CR_XCFG_SQENABLE 0x00000010 /* SQE test enable */
+#define CR_XCFG_SQETWIN 0x000003e0 /* SQE time window */
+#define CR_XCFG_LANCE 0x00000010 /* Lance mode enable */
+#define CR_XCFG_LIPG0 0x000003e0 /* Lance mode IPG0 */
+
+/* BigMac transmit config register. */
+#define CR_TXCFG_ENABLE 0x00000001 /* Enable the transmitter */
+#define CR_TXCFG_SMODE 0x00000020 /* Enable slow transmit mode */
+#define CR_TXCFG_CIGN 0x00000040 /* Ignore transmit collisions */
+#define CR_TXCFG_FCSOFF 0x00000080 /* Do not emit FCS */
+#define CR_TXCFG_DBACKOFF 0x00000100 /* Disable backoff */
+#define CR_TXCFG_FULLDPLX 0x00000200 /* Enable full-duplex */
+#define CR_TXCFG_DGIVEUP 0x00000400 /* Don't give up on transmits */
+
+/* BigMac receive config register. */
+#define CR_RXCFG_ENABLE 0x00000001 /* Enable the receiver */
+#define CR_RXCFG_PSTRIP 0x00000020 /* Pad byte strip enable */
+#define CR_RXCFG_PMISC 0x00000040 /* Enable promiscous mode */
+#define CR_RXCFG_DERR 0x00000080 /* Disable error checking */
+#define CR_RXCFG_DCRCS 0x00000100 /* Disable CRC stripping */
+#define CR_RXCFG_ME 0x00000200 /* Receive packets addressed to me */
+#define CR_RXCFG_PGRP 0x00000400 /* Enable promisc group mode */
+#define CR_RXCFG_HENABLE 0x00000800 /* Enable the hash filter */
+#define CR_RXCFG_AENABLE 0x00001000 /* Enable the address filter */
+
+struct hme_tcvr {
+ volatile u_int32_t bb_clock; /* bit bang clock */
+ volatile u_int32_t bb_data; /* bit bang data */
+ volatile u_int32_t bb_oenab; /* bit bang output enable */
+ volatile u_int32_t frame; /* frame control & data */
+ volatile u_int32_t cfg; /* MIF configuration */
+ volatile u_int32_t int_mask; /* MIF interrupt mask */
+ volatile u_int32_t status; /* MIF status */
+ volatile u_int32_t smachine; /* MIF state machine */
+};
+
+#define FRAME_WRITE 0x50020000 /* start a frame write */
+#define FRAME_READ 0x60020000 /* start a frame read */
+#define TCVR_FAILURE 0x80000000 /* impossible value */
+
+/* Transceiver config register */
+#define TCVR_CFG_PSELECT 0x00000001 /* select PHY */
+#define TCVR_CFG_PENABLE 0x00000002 /* enable MIF polling */
+#define TCVR_CFG_BENABLE 0x00000004 /* enable bit bang */
+#define TCVR_CFG_PREGADDR 0x000000f8 /* poll register addr */
+#define TCVR_CFG_MDIO0 0x00000100 /* MDIO zero, data/attached */
+#define TCVR_CFG_MDIO1 0x00000200 /* MDIO one, data/attached */
+#define TCVR_CFG_PDADDR 0x00007c00 /* device phy addr polling */
+
+/* Here are some PHY addresses. */
+#define TCVR_PHYADDR_ETX 0 /* external transceiver */
+#define TCVR_PHYADDR_ITX 1 /* internal transceiver */
+
+/* Transceiver status register */
+#define TCVR_STAT_BASIC 0xffff0000 /* The "basic" part */
+#define TCVR_STAT_NORMAL 0x0000ffff /* The "non-basic" part */
+
+struct hme_rxd {
+ volatile u_int32_t rx_flags;
+ volatile u_int32_t rx_addr;
+};
+#define RXFLAG_OWN 0x80000000 /* desc owner: 1=hw,0=sw */
+#define RXFLAG_OVERFLOW 0x40000000 /* 1 = buffer over flow */
+#define RXFLAG_SIZE 0x3fff0000 /* desciptor size */
+#define RXFLAG_CSUM 0x0000ffff /* checksum mask */
+
+struct hme_txd {
+ volatile u_int32_t tx_flags;
+ volatile u_int32_t tx_addr;
+};
+#define TXFLAG_OWN 0x80000000 /* desc owner: 1=hw,0=sw */
+#define TXFLAG_SOP 0x40000000 /* 1 = start of pkt */
+#define TXFLAG_EOP 0x20000000 /* 1 = end of pkt */
+#define TXFLAG_CSENABLE 0x10000000 /* 1 = use hw checksums */
+#define TXFLAG_CSLOCATION 0x0ff00000 /* checksum location mask */
+#define TXFLAG_CSBUFBEGIN 0x000fc000 /* checksum begin mask */
+#define TXFLAG_SIZE 0x00003fff /* pkt size mask */
+
+#define RX_RING_SIZE 32 /* Must be 32, 64, 128, or 256 */
+#define TX_RING_SIZE 32 /* Must be 16<=x<=255, and divisible by 16 */
+#define RX_RING_MAX 256 /* maximum ring size: rx */
+#define TX_RING_MAX 256 /* maximum ring size: tx */
+#define RX_PKT_BUF_SZ 1600 /* size of a rx buffer */
+#define RX_OFFSET 2 /* packet offset */
+#define RX_CSUMLOC 0x00 /* checksum location */
+#define TX_PKT_BUF_SZ 1546 /* size of a tx buffer */
+#define RX_ALIGN_SIZE 64 /* rx packet buffers must align on 64 bytes */
+#define RX_ALIGN_MASK (~(RX_ALIGN_SIZE - 1))
+
+struct hme_desc {
+ struct hme_rxd hme_rxd[RX_RING_MAX];
+ struct hme_txd hme_txd[TX_RING_MAX];
+};
+
+struct hme_bufs {
+ char rx_buf[RX_RING_SIZE][RX_PKT_BUF_SZ];
+ char tx_buf[TX_RING_SIZE][TX_PKT_BUF_SZ];
+};
+
+/* hme flags */
+#define HME_FLAG_POLL 0x00000001 /* polling mif? */
+#define HME_FLAG_FENABLE 0x00000002 /* MII frame enabled? */
+#define HME_FLAG_LANCE 0x00000004 /* Lance mode IPG0? */
+#define HME_FLAG_RXENABLE 0x00000008 /* Receiver enabled? */
+#define HME_FLAG_AUTO 0x00000010 /* Auto-Neg? 0 = force */
+#define HME_FLAG_FULL 0x00000020 /* Full duplex enabled? */
+#define HME_FLAG_MACFULL 0x00000040 /* Full duplex in the MAC? */
+#define HME_FLAG_POLLENABLE 0x00000080 /* Try MIF polling? */
+#define HME_FLAG_RXCV 0x00000100 /* RXCV enable - XXX */
+#define HME_FLAG_INIT 0x00000200 /* Initialized once? */
+#define HME_FLAG_LINKUP 0x00000400 /* Is link up? */
+
+#define HME_FLAG_20_21 \
+ (HME_FLAG_POLLENABLE | HME_FLAG_FENABLE)
+#define HME_FLAG_NOT_A0 \
+ (HME_FLAG_POLLENABLE | HME_FLAG_FENABLE | HME_FLAG_LANCE | HME_FLAG_RXCV)
+
+/*
+ * Copies of the hardware registers
+ */
+struct hme_swr {
+ u_int32_t bmcr;
+ u_int32_t bmsr;
+ u_int32_t phyidr1;
+ u_int32_t phyidr2;
+ u_int32_t anar;
+ u_int32_t anlpar;
+ u_int32_t aner;
+};
+
+/*
+ * Transceiver type
+ */
+#define HME_TCVR_EXTERNAL 0
+#define HME_TCVR_INTERNAL 1
+#define HME_TCVR_NONE 2
+
+/*
+ * Autonegotiation time states
+ */
+#define HME_TIMER_DONE 0 /* not doing/waiting for anything */
+#define HME_TIMER_AUTONEG 1 /* autonegotiating */
+#define HME_TIMER_LINKUP 2 /* waiting for link up */
+
+/*
+ * National Semiconductor DP83840A chip definitions
+ * Documentation available from National at:
+ * http://www.national.com/pf/DP/DP83840A.html
+ */
+
+/*
+ * Register offsets
+ */
+#define DP83840_BMCR 0x00 /* Basic Mode Control Register */
+#define DP83840_BMSR 0x01 /* Basic Mode Status Register */
+#define DP83840_PHYIDR1 0x02 /* PHY Identifier Register #1 */
+#define DP83840_PHYIDR2 0x03 /* PHY Identifier Register #2 */
+#define DP83840_ANAR 0x04 /* Auto-Negotiation Advertisement Reg */
+#define DP83840_ANLPAR 0x05 /* Auto-Negotiation Partner Ability Reg */
+#define DP83840_ANER 0x06 /* Auto-Negotiation Expansion Register */
+ /* 0x07 - 0x11 Reserved */
+#define DP83840_DCR 0x12 /* Disconnect Counter Register */
+#define DP83840_FCSCR 0x13 /* False Carrier Sense Counter Register */
+ /* 0x14 Reserved */
+#define DP83840_RECR 0x15 /* Receive Error Counter Register */
+#define DP83840_SRR 0x16 /* Silicon Revision Register */
+#define DP83840_PCR 0x17 /* PCS Sub-Layer Configuration Register */
+#define DP83840_LBREMR 0x18 /* Loopback,Bypass,& Receiver Error Reg */
+#define DP83840_PAR 0x19 /* PHY Address Register */
+ /* 0x1a Reserved */
+#define DP83840_10BTSR 0x1b /* 10BaseT Status Register */
+#define DP83840_10BTCR 0x1c /* 10BaseT Configuration Register */
+ /* 0x1d - 0x1f Reserved */
+
+/*
+ * Basic Mode Control Register (BMCR)
+ */
+#define BMCR_RESET 0x8000 /* Software reset */
+#define BMCR_LOOPBACK 0x4000 /* Lookback enable */
+#define BMCR_SPEED 0x2000 /* 1=100Mb, 0=10Mb */
+#define BMCR_ANE 0x1000 /* Auto-Negiation enable */
+#define BMCR_PDOWN 0x0800 /* power down the chip */
+#define BMCR_ISOLATE 0x0400 /* Isolate the chip */
+#define BMCR_RAN 0x0200 /* Restart autonegotiation */
+#define BMCR_DUPLEX 0x0100 /* 1=full, 0=half */
+#define BMCR_COLLISONTEST 0x0080 /* Create collisions on TX */
+
+/*
+ * Basic Mode Status Register (BMSR)
+ */
+#define BMSR_100BASET4 0x8000 /* 100BaseT4 capable? */
+#define BMSR_100BASETX_FULL 0x4000 /* 100BaseTX full duplex? */
+#define BMSR_100BASETX_HALF 0x2000 /* 100BaseTX half duplex? */
+#define BMSR_10BASET_FULL 0x1000 /* 10BaseT full duplex? */
+#define BMSR_10BASET_HALF 0x0800 /* 10BaseT half duplex? */
+#define BMSR_ANCOMPLETE 0x0020 /* auto-negotiation complete? */
+#define BMSR_REMOTEFAULT 0x0010 /* Fault condition seen? */
+#define BMSR_ANC 0x0008 /* Can auto-negotiate? */
+#define BMSR_LINKSTATUS 0x0004 /* Link established? */
+#define BMSR_JABBER 0x0002 /* Jabber detected? */
+#define BMSR_EXTENDED 0x0001 /* Extended registers? */
+
+/*
+ * Auto-Negotiation Advertisement Register (ANAR)
+ */
+#define ANAR_NP 0x8000 /* Next page indicator */
+#define ANAR_ACK 0x4000 /* Acknowledge */
+#define ANAR_RF 0x2000 /* Remote Fault */
+#define ANAR_RSRV12 0x1000 /* reserved */
+#define ANAR_RSRV11 0x0800 /* reserved */
+#define ANAR_RSRV10 0x0400 /* reserved */
+#define ANAR_T4 0x0200 /* 100BaseT4 support? */
+#define ANAR_TX_FD 0x0100 /* 100BaseTX full duplex? */
+#define ANAR_TX 0x0080 /* 100BaseTX half duplex? */
+#define ANAR_10_FD 0x0040 /* 10BaseT full duplex? */
+#define ANAR_10 0x0020 /* 10BaseT full duplex? */
+#define ANAR_SELECTOR 0x001f /* protocol selector */
+
+/*
+ * Auto-Negotiation Link Partner Ability Register (ANLPAR)
+ */
+#define ANLPAR_NP 0x8000 /* Next page indictaion */
+#define ANLPAR_ACK 0x4000 /* Acknowledge */
+#define ANLPAR_RF 0x2000 /* Remote Fault */
+#define ANLPAR_RSRV12 0x1000 /* reserved */
+#define ANLPAR_RSRV11 0x0800 /* reserved */
+#define ANLPAR_RSRV10 0x0400 /* reserved */
+#define ANLPAR_T4 0x0200 /* 100BaseT4 support? */
+#define ANLPAR_TX_FD 0x0100 /* 100BaseTX full duplex? */
+#define ANLPAR_TX 0x0080 /* 100BaseTX half duplex? */
+#define ANLPAR_10_FD 0x0040 /* 10BaseT full duplex? */
+#define ANLPAR_10 0x0020 /* 10BaseT full duplex? */
+#define ANLPAR_SELECTOR 0x001f /* protocol selector */
+
+/*
+ * Auto-Negotiation Expansion Register (ANER)
+ */
+#define ANER_RSRV15 0x8000 /* reserved */
+#define ANER_RSRV14 0x4000 /* reserved */
+#define ANER_RSRV13 0x2000 /* reserved */
+#define ANER_RSRV12 0x1000 /* reserved */
+#define ANER_RSRV11 0x0800 /* reserved */
+#define ANER_RSRV10 0x0400 /* reserved */
+#define ANER_RSRV09 0x0200 /* reserved */
+#define ANER_RSRV08 0x0100 /* reserved */
+#define ANER_RSRV07 0x0080 /* reserved */
+#define ANER_RSRV06 0x0040 /* reserved */
+#define ANER_RSRV05 0x0020 /* reserved */
+#define ANER_MLF 0x0010 /* Multiple link fault */
+#define ANER_LP_NP_ABLE 0x0008 /* Link partner next page-able */
+#define ANER_NP_ABLE 0x0004 /* Next page-able */
+#define ANER_PAGE_RX 0x0002 /* Link Code Word Page Received */
+#define ANER_LP_AN_ABLE 0x0001 /* Link partner auto-neg-able */
+
+/*
+ * PCS Configuration Register (PCR)
+ */
+#define PCR_NRZI_EN 0x8000 /* NRZI coding enable */
+#define PCR_DESCR_TO_SEL 0x4000 /* Descrambler timeout select */
+#define PCR_DESCR_TO_DIS 0x2000 /* Descrambler timeout disable */
+#define PCR_REPEATER 0x1000 /* Repeater/Node Mode */
+#define PCR_ENCSEL 0x0800 /* Encoder Mode select */
+#define PCR_RSRV10 0x0400 /* reserved */
+#define PCR_RSRV09 0x0200 /* reserved */
+#define PCR_RSRV08 0x0100 /* reserved */
+#define PCR_CLK25MDIS 0x0080 /* CLK25M disbable */
+#define PCR_F_LINK_100 0x0040 /* Force good link in 100Mb/s */
+#define PCR_CIM_DIS 0x0020 /* Carrier integ. mon. disable */
+#define PCR_TX_OFF 0x0010 /* Force transmit off */
+#define PCR_RSRV03 0x0008 /* reserved */
+#define PCR_LED1_MODE 0x0004 /* Led1 mode select */
+#define PCR_LED4_MODE 0x0002 /* Led4 mode select */
+#define PCR_RSRV00 0x0001 /* reserved */
+
+/*
+ * Loopback, bypass, and receiver error mask register (LBREMR)
+ */
+#define LBREMR_BAD_SSD_EN 0x8000 /* BAD SSD enable */
+#define LBREMR_BP_4B5B 0x4000 /* Bypass 4B5B and 5B4B enc/dec */
+#define LBREMR_BP_SCR 0x2000 /* Bypass scramble/descramble */
+#define LBREMR_BP_ALIGN 0x1000 /* Bypass symbol alignment func */
+#define LBREMR_10BT_LPBK 0x0800 /* 10BaseT enc/dec loopback */
+#define LBREMR_RSRV10 0x0400 /* reserved */
+#define LBREMR_LB1 0x0200 /* Loopback control bit #2 */
+#define LBREMR_LB0 0x0100 /* Loopback control bit #1 */
+#define LBREMR_RSRV07 0x0080 /* reserved */
+#define LBREMR_ALT_CRS 0x0040 /* Alternate CRS operation */
+#define LBREMR_LBK_XMT_DIS 0x0020 /* 100Mb/s tx disable in loop */
+#define LBREMR_CODE_ERR 0x0010 /* Code errors */
+#define LBREMR_PE_ERR 0x0008 /* Premature end errors */
+#define LBREMR_LINK_ERR 0x0004 /* Link errors */
+#define LBREMR_PKT_ERR 0x0002 /* Packet errors */
+#define LBREMR_RSRV00 0x0001 /* reserved */
+
+/*
+ * PHY Address Register (PAR)
+ */
+#define PAR_RSRV15 0x8000 /* reserved */
+#define PAR_RSRV14 0x4000 /* reserved */
+#define PAR_RSRV13 0x2000 /* reserved */
+#define PAR_RSRV12 0x1000 /* reserved */
+#define PAR_DIS_CRS_JAB 0x0800 /* Disable CS during jabber */
+#define PAR_AN_EN_STAT 0x0400 /* Auto-Neg. mode status */
+#define PAR_RSRV09 0x0200 /* reserved */
+#define PAR_FEFI_EN 0x0100 /* Far end fault status enable */
+#define PAR_DUPLEX_STAT 0x0080 /* 1=full duplex, 0=half duplex */
+#define PAR_SPEED_10 0x0040 /* 1=10Mb/s, 0=100Mb/s */
+#define PAR_CIM_STATUS 0x0020 /* Carrier integrity mon. stat */
+#define PAR_PHYADDR4 0x0010 /* physical address bit 4 */
+#define PAR_PHYADDR3 0x0008 /* physical address bit 3 */
+#define PAR_PHYADDR2 0x0004 /* physical address bit 2 */
+#define PAR_PHYADDR1 0x0002 /* physical address bit 1 */
+#define PAR_PHYADDR0 0x0001 /* physical address bit 0 */
+
+/*
+ * 10BaseT status register (TENBTSR)
+ */
+#define TENBTSR10BT_SER 0x0200 /* 10BaseT Serial mode? */
+
+/*
+ * 10BaseT configuration register (TENBTCR)
+ */
+#define TENBTCR_LP_EN 0x0020 /* Link pulse enable */
+#define TENBTCR_HBE 0x0010 /* Heartbeat enable */
+#define TENBTCR_UTP_STP 0x0008 /* 1=UTP, 0=STP */
+#define TENBTCR_LSS 0x0004 /* Low squelch select */
+#define TENBTCR_RSRV01 0x0002 /* reserved */
+#define TENBTCR_JABEN 0x0001 /* Jabber enable */
diff --git a/sys/arch/sparc/dev/hmevar.h b/sys/arch/sparc/dev/hmevar.h
new file mode 100644
index 00000000000..cfc44033062
--- /dev/null
+++ b/sys/arch/sparc/dev/hmevar.h
@@ -0,0 +1,68 @@
+/* $OpenBSD: hmevar.h,v 1.1 1998/07/10 19:09:12 jason Exp $ */
+
+/*
+ * Copyright (c) 1998 Jason L. Wright (jason@thought.net)
+ * All rights reserved.
+ *
+ * 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 Jason L. Wright
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+struct hme_softc {
+ struct device sc_dev; /* base device */
+ struct arpcom sc_arpcom; /* ethernet common */
+ struct sbusdev sc_sd; /* sbus device */
+ struct intrhand sc_ih; /* interrupt vectoring */
+ int sc_node; /* which sbus node */
+
+ /*
+ * Register sets
+ */
+ struct hme_gr *sc_gr; /* global registers */
+ struct hme_txr *sc_txr; /* transmitter regs */
+ struct hme_rxr *sc_rxr; /* receiver registers */
+ struct hme_cr *sc_cr; /* configuration registers */
+ struct hme_tcvr *sc_tcvr; /* MIF registers */
+
+ struct hme_swr sc_sw; /* software copy registers */
+ int sc_burst; /* DMA burst size in effect */
+ int sc_rev; /* Card revision */
+
+ u_int32_t sc_flags; /* status flags */
+ u_int32_t sc_promisc; /* are we promiscuous? */
+ u_int32_t sc_phyaddr; /* PHY addr */
+ int sc_an_state; /* state of negotiation */
+ int sc_an_ticks; /* how long has passed? */
+ int sc_tcvr_type; /* transceiver type */
+
+ /*
+ * RX/TX ring buffers, descriptors, and counters
+ */
+ struct hme_desc *sc_desc, *sc_desc_dva; /* descriptors */
+ struct hme_bufs *sc_bufs, *sc_bufs_dva; /* buffers */
+ int sc_first_td, sc_last_td, sc_no_td; /* tx counters */
+ int sc_last_rd; /* rx counter */
+};