summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2009-06-15 18:22:41 +0000
committermarius <marius@FreeBSD.org>2009-06-15 18:22:41 +0000
commit6c0f8373ed31bb2300d516edbae32f2e9dbf72b3 (patch)
tree94a8433e796ffe8fced15b2a1a94604cbac0af7f
parent84d5b1472aacb5d5e2616dab2e337fd7ddd1d21f (diff)
downloadFreeBSD-src-6c0f8373ed31bb2300d516edbae32f2e9dbf72b3.zip
FreeBSD-src-6c0f8373ed31bb2300d516edbae32f2e9dbf72b3.tar.gz
Add cas(4), a driver for Sun Cassini/Cassini+ and National Semiconductor
DP83065 Saturn Gigabit Ethernet controllers. These are the successors of the Sun GEM controllers and still have a similar but extended transmit logic. As such this driver is based on gem(4). Thanks to marcel@ for providing a Sun Quad GigaSwift Ethernet UTP (QGE) card which was vital for getting this driver to work on architectures not using Open Firmware. Approved by: re (kib) MFC after: 2 weeks
-rw-r--r--sys/boot/forth/loader.conf1
-rw-r--r--sys/conf/NOTES2
-rw-r--r--sys/conf/files1
-rw-r--r--sys/dev/cas/if_cas.c2772
-rw-r--r--sys/dev/cas/if_casreg.h1002
-rw-r--r--sys/dev/cas/if_casvar.h260
-rw-r--r--sys/modules/Makefile1
-rw-r--r--sys/modules/cas/Makefile8
-rw-r--r--sys/sparc64/conf/GENERIC1
9 files changed, 4048 insertions, 0 deletions
diff --git a/sys/boot/forth/loader.conf b/sys/boot/forth/loader.conf
index aa159ca..45274f8 100644
--- a/sys/boot/forth/loader.conf
+++ b/sys/boot/forth/loader.conf
@@ -221,6 +221,7 @@ if_axe_load="NO" # ASIX Electronics AX88172 USB Ethernet
if_bce_load="NO" # Broadcom NetXtreme II Gigabit Ethernet
if_bfe_load="NO" # Broadcom BCM4401
if_bge_load="NO" # Broadcom BCM570x PCI Gigabit Ethernet
+if_cas_load="NO" # Sun Cassini/Cassini+ and NS DP83065 Saturn
if_cm_load="NO" # SMC (90c26, 90c56, 90c66)
if_cs_load="NO" # Crystal Semiconductor CS8920
if_cue_load="NO" # CATC USB-EL1210A USB Ethernet
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 0abfc54..6c2a8b6 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -1768,6 +1768,7 @@ device miibus
# BCM570x family of controllers, including the 3Com 3c996-T,
# the Netgear GA302T, the SysKonnect SK-9D21 and SK-9D41, and
# the embedded gigE NICs on Dell PowerEdge 2550 servers.
+# cas: Sun Cassini/Cassini+ and National Semiconductor DP83065 Saturn
# cm: Arcnet SMC COM90c26 / SMC COM90c56
# (and SMC COM90c66 in '56 compatibility mode) adapters.
# dc: Support for PCI fast ethernet adapters based on the DEC/Intel 21143
@@ -1907,6 +1908,7 @@ device ale # Atheros AR8121/AR8113/AR8114 Ethernet
device bce # Broadcom BCM5706/BCM5708 Gigabit Ethernet
device bfe # Broadcom BCM440x 10/100 Ethernet
device bge # Broadcom BCM570xx Gigabit Ethernet
+device cas # Sun Cassini/Cassini+ and NS DP83065 Saturn
device cxgb # Chelsio T3 10 Gigabit Ethernet
device cxgb_t3fw # Chelsio T3 10 Gigabit Ethernet firmware
device dc # DEC/Intel 21143 and various workalikes
diff --git a/sys/conf/files b/sys/conf/files
index fc7b52d..b074f86 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -738,6 +738,7 @@ dev/bwi/if_bwi_pci.c optional bwi pci
dev/cardbus/cardbus.c optional cardbus
dev/cardbus/cardbus_cis.c optional cardbus
dev/cardbus/cardbus_device.c optional cardbus
+dev/cas/if_cas.c optional cas
dev/cfi/cfi_core.c optional cfi
dev/cfi/cfi_dev.c optional cfi
dev/cfi/cfi_disk.c optional cfid
diff --git a/sys/dev/cas/if_cas.c b/sys/dev/cas/if_cas.c
new file mode 100644
index 0000000..cba28af
--- /dev/null
+++ b/sys/dev/cas/if_cas.c
@@ -0,0 +1,2772 @@
+/*-
+ * Copyright (C) 2001 Eduardo Horvath.
+ * Copyright (c) 2001-2003 Thomas Moestl
+ * Copyright (c) 2007-2009 Marius Strobl <marius@FreeBSD.org>
+ * 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.
+ *
+ * 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.
+ *
+ * from: NetBSD: gem.c,v 1.21 2002/06/01 23:50:58 lukem Exp
+ * from: FreeBSD: if_gem.c 182060 2008-08-23 15:03:26Z marius
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * driver for Sun Cassini/Cassini+ and National Semiconductor DP83065
+ * Saturn Gigabit Ethernet controllers
+ */
+
+#if 0
+#define CAS_DEBUG
+#endif
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/callout.h>
+#include <sys/endian.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/refcount.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/rman.h>
+
+#include <net/bpf.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/if_vlan_var.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <netinet/udp.h>
+
+#include <machine/bus.h>
+#if defined(__powerpc__) || defined(__sparc64__)
+#include <dev/ofw/openfirm.h>
+#include <machine/ofw_machdep.h>
+#endif
+#include <machine/resource.h>
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <dev/cas/if_casreg.h>
+#include <dev/cas/if_casvar.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+
+#include "miibus_if.h"
+
+#define RINGASSERT(n , min, max) \
+ CTASSERT(powerof2(n) && (n) >= (min) && (n) <= (max))
+
+RINGASSERT(CAS_NRXCOMP, 128, 32768);
+RINGASSERT(CAS_NRXDESC, 32, 8192);
+RINGASSERT(CAS_NRXDESC2, 32, 8192);
+RINGASSERT(CAS_NTXDESC, 32, 8192);
+
+#undef RINGASSERT
+
+#define CCDASSERT(m, a) \
+ CTASSERT((offsetof(struct cas_control_data, m) & ((a) - 1)) == 0)
+
+CCDASSERT(ccd_rxcomps, CAS_RX_COMP_ALIGN);
+CCDASSERT(ccd_rxdescs, CAS_RX_DESC_ALIGN);
+CCDASSERT(ccd_rxdescs2, CAS_RX_DESC_ALIGN);
+
+#undef CCDASSERT
+
+#define CAS_TRIES 10000
+
+/*
+ * According to documentation, the hardware has support for basic TCP
+ * checksum offloading only, in practice this can be also used for UDP
+ * however (i.e. the problem of previous Sun NICs that a checksum of 0x0
+ * is not converted to 0xffff no longer exists).
+ */
+#define CAS_CSUM_FEATURES (CSUM_TCP | CSUM_UDP)
+
+static inline void cas_add_rxdesc(struct cas_softc *sc, u_int idx);
+static int cas_attach(struct cas_softc *sc);
+static int cas_bitwait(struct cas_softc *sc, bus_addr_t r, uint32_t clr,
+ uint32_t set);
+static void cas_cddma_callback(void *xsc, bus_dma_segment_t *segs,
+ int nsegs, int error);
+static void cas_detach(struct cas_softc *sc);
+static int cas_disable_rx(struct cas_softc *sc);
+static int cas_disable_tx(struct cas_softc *sc);
+static void cas_eint(struct cas_softc *sc, u_int status);
+static void cas_free(void *arg1, void* arg2);
+static void cas_init(void *xsc);
+static void cas_init_locked(struct cas_softc *sc);
+static void cas_init_regs(struct cas_softc *sc);
+static void cas_intr(void *v);
+static int cas_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
+static int cas_load_txmbuf(struct cas_softc *sc, struct mbuf **m_head);
+static int cas_mediachange(struct ifnet *ifp);
+static void cas_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr);
+static void cas_meminit(struct cas_softc *sc);
+static void cas_mifinit(struct cas_softc *sc);
+static int cas_mii_readreg(device_t dev, int phy, int reg);
+static void cas_mii_statchg(device_t dev);
+static int cas_mii_writereg(device_t dev, int phy, int reg, int val);
+static void cas_reset(struct cas_softc *sc);
+static int cas_reset_rx(struct cas_softc *sc);
+static int cas_reset_tx(struct cas_softc *sc);
+static void cas_resume(struct cas_softc *sc);
+static u_int cas_descsize(u_int sz);
+static void cas_rint(struct cas_softc *sc);
+static void cas_rint_timeout(void *arg);
+static inline void cas_rxcksum(struct mbuf *m, uint16_t cksum);
+static inline void cas_rxcompinit(struct cas_rx_comp *rxcomp);
+static u_int cas_rxcompsize(u_int sz);
+static void cas_rxdma_callback(void *xsc, bus_dma_segment_t *segs,
+ int nsegs, int error);
+static void cas_setladrf(struct cas_softc *sc);
+static void cas_start(struct ifnet *ifp);
+static void cas_start_locked(struct ifnet *ifp);
+static void cas_stop(struct ifnet *ifp);
+static void cas_suspend(struct cas_softc *sc);
+static void cas_tick(void *arg);
+static void cas_tint(struct cas_softc *sc);
+static inline void cas_txkick(struct cas_softc *sc);
+static int cas_watchdog(struct cas_softc *sc);
+
+static devclass_t cas_devclass;
+
+MODULE_DEPEND(cas, ether, 1, 1, 1);
+MODULE_DEPEND(cas, miibus, 1, 1, 1);
+
+#ifdef CAS_DEBUG
+#include <sys/ktr.h>
+#define KTR_CAS KTR_CT2
+#endif
+
+static int
+cas_attach(struct cas_softc *sc)
+{
+ struct cas_txsoft *txs;
+ struct ifnet *ifp;
+ int error, i;
+ uint32_t v;
+
+ /* Set up ifnet structure. */
+ ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
+ if (ifp == NULL)
+ return (ENOSPC);
+ ifp->if_softc = sc;
+ if_initname(ifp, device_get_name(sc->sc_dev),
+ device_get_unit(sc->sc_dev));
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_start = cas_start;
+ ifp->if_ioctl = cas_ioctl;
+ ifp->if_init = cas_init;
+ IFQ_SET_MAXLEN(&ifp->if_snd, CAS_TXQUEUELEN);
+ ifp->if_snd.ifq_drv_maxlen = CAS_TXQUEUELEN;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ callout_init_mtx(&sc->sc_tick_ch, &sc->sc_mtx, 0);
+ callout_init_mtx(&sc->sc_rx_ch, &sc->sc_mtx, 0);
+
+ /* Make sure the chip is stopped. */
+ cas_reset(sc);
+
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ BUS_SPACE_MAXSIZE, 0, BUS_SPACE_MAXSIZE, 0, NULL, NULL,
+ &sc->sc_pdmatag);
+ if (error != 0)
+ goto fail_ifnet;
+
+ error = bus_dma_tag_create(sc->sc_pdmatag, 1, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ CAS_PAGE_SIZE, 1, CAS_PAGE_SIZE, 0, NULL, NULL, &sc->sc_rdmatag);
+ if (error != 0)
+ goto fail_ptag;
+
+ error = bus_dma_tag_create(sc->sc_pdmatag, 1, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ MCLBYTES * CAS_NTXSEGS, CAS_NTXSEGS, MCLBYTES,
+ BUS_DMA_ALLOCNOW, NULL, NULL, &sc->sc_tdmatag);
+ if (error != 0)
+ goto fail_rtag;
+
+ error = bus_dma_tag_create(sc->sc_pdmatag, CAS_TX_DESC_ALIGN, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
+ sizeof(struct cas_control_data), 1,
+ sizeof(struct cas_control_data), 0,
+ NULL, NULL, &sc->sc_cdmatag);
+ if (error != 0)
+ goto fail_ttag;
+
+ /*
+ * Allocate the control data structures, create and load the
+ * DMA map for it.
+ */
+ if ((error = bus_dmamem_alloc(sc->sc_cdmatag,
+ (void **)&sc->sc_control_data,
+ BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
+ &sc->sc_cddmamap)) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to allocate control data, error = %d\n", error);
+ goto fail_ctag;
+ }
+
+ sc->sc_cddma = 0;
+ if ((error = bus_dmamap_load(sc->sc_cdmatag, sc->sc_cddmamap,
+ sc->sc_control_data, sizeof(struct cas_control_data),
+ cas_cddma_callback, sc, 0)) != 0 || sc->sc_cddma == 0) {
+ device_printf(sc->sc_dev,
+ "unable to load control data DMA map, error = %d\n",
+ error);
+ goto fail_cmem;
+ }
+
+ /*
+ * Initialize the transmit job descriptors.
+ */
+ STAILQ_INIT(&sc->sc_txfreeq);
+ STAILQ_INIT(&sc->sc_txdirtyq);
+
+ /*
+ * Create the transmit buffer DMA maps.
+ */
+ error = ENOMEM;
+ for (i = 0; i < CAS_TXQUEUELEN; i++) {
+ txs = &sc->sc_txsoft[i];
+ txs->txs_mbuf = NULL;
+ txs->txs_ndescs = 0;
+ if ((error = bus_dmamap_create(sc->sc_tdmatag, 0,
+ &txs->txs_dmamap)) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to create TX DMA map %d, error = %d\n",
+ i, error);
+ goto fail_txd;
+ }
+ STAILQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q);
+ }
+
+ /*
+ * Allocate the receive buffers, create and load the DMA maps
+ * for them.
+ */
+ for (i = 0; i < CAS_NRXDESC; i++) {
+ if ((error = bus_dmamem_alloc(sc->sc_rdmatag,
+ &sc->sc_rxdsoft[i].rxds_buf, BUS_DMA_WAITOK,
+ &sc->sc_rxdsoft[i].rxds_dmamap)) != 0) {
+ device_printf(sc->sc_dev,
+ "unable to allocate RX buffer %d, error = %d\n",
+ i, error);
+ goto fail_rxmem;
+ }
+
+ sc->sc_rxdptr = i;
+ sc->sc_rxdsoft[i].rxds_paddr = 0;
+ if ((error = bus_dmamap_load(sc->sc_rdmatag,
+ sc->sc_rxdsoft[i].rxds_dmamap, sc->sc_rxdsoft[i].rxds_buf,
+ CAS_PAGE_SIZE, cas_rxdma_callback, sc, 0)) != 0 ||
+ sc->sc_rxdsoft[i].rxds_paddr == 0) {
+ device_printf(sc->sc_dev,
+ "unable to load RX DMA map %d, error = %d\n",
+ i, error);
+ goto fail_rxmap;
+ }
+ }
+
+ CAS_WRITE_4(sc, CAS_PCS_DATAPATH, CAS_PCS_DATAPATH_MII);
+
+ cas_mifinit(sc);
+
+ /*
+ * Look for an external PHY.
+ */
+ error = ENXIO;
+ v = CAS_READ_4(sc, CAS_MIF_CONF);
+ if ((v & CAS_MIF_CONF_MDI1) != 0) {
+ v |= CAS_MIF_CONF_PHY_SELECT;
+ CAS_WRITE_4(sc, CAS_MIF_CONF, v);
+ switch (sc->sc_variant) {
+ default:
+ sc->sc_phyad = -1;
+ break;
+ }
+ error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus,
+ cas_mediachange, cas_mediastatus);
+ }
+
+ /*
+ * Fall back on an internal PHY if no external PHY was found.
+ */
+ if (error != 0 && (v & CAS_MIF_CONF_MDI0) != 0) {
+ v &= ~CAS_MIF_CONF_PHY_SELECT;
+ CAS_WRITE_4(sc, CAS_MIF_CONF, v);
+ switch (sc->sc_variant) {
+ default:
+ sc->sc_phyad = -1;
+ break;
+ }
+ error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus,
+ cas_mediachange, cas_mediastatus);
+ }
+
+ /*
+ * Try the external PCS SERDES if we didn't find any PHYs.
+ */
+ if (error != 0) {
+ CAS_WRITE_4(sc, CAS_PCS_DATAPATH, CAS_PCS_DATAPATH_SERDES);
+ CAS_WRITE_4(sc, CAS_PCS_SERDES_CTRL, CAS_PCS_SERDES_CTRL_ESD);
+ CAS_WRITE_4(sc, CAS_PCS_CONF_EN, CAS_PCS_CONF_EN);
+ sc->sc_flags |= CAS_SERDES;
+ sc->sc_phyad = CAS_PHYAD_EXTERNAL;
+ error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus,
+ cas_mediachange, cas_mediastatus);
+ }
+
+ if (error != 0) {
+ device_printf(sc->sc_dev, "PHY probe failed: %d\n", error);
+ goto fail_rxmap;
+ }
+ sc->sc_mii = device_get_softc(sc->sc_miibus);
+
+ /*
+ * From this point forward, the attachment cannot fail. A failure
+ * before this point releases all resources that may have been
+ * allocated.
+ */
+
+ /* Announce FIFO sizes. */
+ v = CAS_READ_4(sc, CAS_TX_FIFO_SIZE);
+ device_printf(sc->sc_dev, "%ukB RX FIFO, %ukB TX FIFO\n",
+ CAS_RX_FIFO_SIZE / 1024, v / 16);
+
+ /* Attach the interface. */
+ ether_ifattach(ifp, sc->sc_enaddr);
+
+ /*
+ * Tell the upper layer(s) we support long frames/checksum offloads.
+ */
+ ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
+ ifp->if_capabilities = IFCAP_VLAN_MTU;
+ if ((sc->sc_flags & CAS_NO_CSUM) == 0) {
+ ifp->if_capabilities |= IFCAP_HWCSUM;
+ ifp->if_hwassist = CAS_CSUM_FEATURES;
+ }
+ ifp->if_capenable = ifp->if_capabilities;
+
+ return (0);
+
+ /*
+ * Free any resources we've allocated during the failed attach
+ * attempt. Do this in reverse order and fall through.
+ */
+ fail_rxmap:
+ for (i = 0; i < CAS_NRXDESC; i++)
+ if (sc->sc_rxdsoft[i].rxds_paddr != 0)
+ bus_dmamap_unload(sc->sc_rdmatag,
+ sc->sc_rxdsoft[i].rxds_dmamap);
+ fail_rxmem:
+ for (i = 0; i < CAS_NRXDESC; i++)
+ if (sc->sc_rxdsoft[i].rxds_buf != NULL)
+ bus_dmamem_free(sc->sc_rdmatag,
+ sc->sc_rxdsoft[i].rxds_buf,
+ sc->sc_rxdsoft[i].rxds_dmamap);
+ fail_txd:
+ for (i = 0; i < CAS_TXQUEUELEN; i++)
+ if (sc->sc_txsoft[i].txs_dmamap != NULL)
+ bus_dmamap_destroy(sc->sc_tdmatag,
+ sc->sc_txsoft[i].txs_dmamap);
+ bus_dmamap_unload(sc->sc_cdmatag, sc->sc_cddmamap);
+ fail_cmem:
+ bus_dmamem_free(sc->sc_cdmatag, sc->sc_control_data,
+ sc->sc_cddmamap);
+ fail_ctag:
+ bus_dma_tag_destroy(sc->sc_cdmatag);
+ fail_ttag:
+ bus_dma_tag_destroy(sc->sc_tdmatag);
+ fail_rtag:
+ bus_dma_tag_destroy(sc->sc_rdmatag);
+ fail_ptag:
+ bus_dma_tag_destroy(sc->sc_pdmatag);
+ fail_ifnet:
+ if_free(ifp);
+ return (error);
+}
+
+static void
+cas_detach(struct cas_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ int i;
+
+ CAS_LOCK(sc);
+ cas_stop(ifp);
+ CAS_UNLOCK(sc);
+ callout_drain(&sc->sc_tick_ch);
+ callout_drain(&sc->sc_rx_ch);
+ ether_ifdetach(ifp);
+ if_free(ifp);
+ device_delete_child(sc->sc_dev, sc->sc_miibus);
+
+ for (i = 0; i < CAS_NRXDESC; i++)
+ if (sc->sc_rxdsoft[i].rxds_dmamap != NULL)
+ bus_dmamap_sync(sc->sc_rdmatag,
+ sc->sc_rxdsoft[i].rxds_dmamap,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ for (i = 0; i < CAS_NRXDESC; i++)
+ if (sc->sc_rxdsoft[i].rxds_paddr != 0)
+ bus_dmamap_unload(sc->sc_rdmatag,
+ sc->sc_rxdsoft[i].rxds_dmamap);
+ for (i = 0; i < CAS_NRXDESC; i++)
+ if (sc->sc_rxdsoft[i].rxds_buf != NULL)
+ bus_dmamem_free(sc->sc_rdmatag,
+ sc->sc_rxdsoft[i].rxds_buf,
+ sc->sc_rxdsoft[i].rxds_dmamap);
+ for (i = 0; i < CAS_TXQUEUELEN; i++)
+ if (sc->sc_txsoft[i].txs_dmamap != NULL)
+ bus_dmamap_destroy(sc->sc_tdmatag,
+ sc->sc_txsoft[i].txs_dmamap);
+ CAS_CDSYNC(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_cdmatag, sc->sc_cddmamap);
+ bus_dmamem_free(sc->sc_cdmatag, sc->sc_control_data,
+ sc->sc_cddmamap);
+ bus_dma_tag_destroy(sc->sc_cdmatag);
+ bus_dma_tag_destroy(sc->sc_tdmatag);
+ bus_dma_tag_destroy(sc->sc_rdmatag);
+ bus_dma_tag_destroy(sc->sc_pdmatag);
+}
+
+static void
+cas_suspend(struct cas_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ CAS_LOCK(sc);
+ cas_stop(ifp);
+ CAS_UNLOCK(sc);
+}
+
+static void
+cas_resume(struct cas_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ CAS_LOCK(sc);
+ /*
+ * On resume all registers have to be initialized again like
+ * after power-on.
+ */
+ sc->sc_flags &= ~CAS_INITED;
+ if (ifp->if_flags & IFF_UP)
+ cas_init_locked(sc);
+ CAS_UNLOCK(sc);
+}
+
+static inline void
+cas_rxcksum(struct mbuf *m, uint16_t cksum)
+{
+ struct ether_header *eh;
+ struct ip *ip;
+ struct udphdr *uh;
+ uint16_t *opts;
+ int32_t hlen, len, pktlen;
+ uint32_t temp32;
+
+ pktlen = m->m_pkthdr.len;
+ if (pktlen < sizeof(struct ether_header) + sizeof(struct ip))
+ return;
+ eh = mtod(m, struct ether_header *);
+ if (eh->ether_type != htons(ETHERTYPE_IP))
+ return;
+ ip = (struct ip *)(eh + 1);
+ if (ip->ip_v != IPVERSION)
+ return;
+
+ hlen = ip->ip_hl << 2;
+ pktlen -= sizeof(struct ether_header);
+ if (hlen < sizeof(struct ip))
+ return;
+ if (ntohs(ip->ip_len) < hlen)
+ return;
+ if (ntohs(ip->ip_len) != pktlen)
+ return;
+ if (ip->ip_off & htons(IP_MF | IP_OFFMASK))
+ return; /* Cannot handle fragmented packet. */
+
+ switch (ip->ip_p) {
+ case IPPROTO_TCP:
+ if (pktlen < (hlen + sizeof(struct tcphdr)))
+ return;
+ break;
+ case IPPROTO_UDP:
+ if (pktlen < (hlen + sizeof(struct udphdr)))
+ return;
+ uh = (struct udphdr *)((uint8_t *)ip + hlen);
+ if (uh->uh_sum == 0)
+ return; /* no checksum */
+ break;
+ default:
+ return;
+ }
+
+ cksum = ~cksum;
+ /* checksum fixup for IP options */
+ len = hlen - sizeof(struct ip);
+ if (len > 0) {
+ opts = (uint16_t *)(ip + 1);
+ for (; len > 0; len -= sizeof(uint16_t), opts++) {
+ temp32 = cksum - *opts;
+ temp32 = (temp32 >> 16) + (temp32 & 65535);
+ cksum = temp32 & 65535;
+ }
+ }
+ m->m_pkthdr.csum_flags |= CSUM_DATA_VALID;
+ m->m_pkthdr.csum_data = cksum;
+}
+
+static void
+cas_cddma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ struct cas_softc *sc = xsc;
+
+ if (error != 0)
+ return;
+ if (nsegs != 1)
+ panic("%s: bad control buffer segment count", __func__);
+ sc->sc_cddma = segs[0].ds_addr;
+}
+
+static void
+cas_rxdma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
+{
+ struct cas_softc *sc = xsc;
+
+ if (error != 0)
+ return;
+ if (nsegs != 1)
+ panic("%s: bad RX buffer segment count", __func__);
+ sc->sc_rxdsoft[sc->sc_rxdptr].rxds_paddr = segs[0].ds_addr;
+}
+
+static void
+cas_tick(void *arg)
+{
+ struct cas_softc *sc = arg;
+ struct ifnet *ifp;
+ uint32_t v;
+
+ CAS_LOCK_ASSERT(sc, MA_OWNED);
+
+ ifp = sc->sc_ifp;
+ /*
+ * Unload collision and error counters.
+ */
+ ifp->if_collisions +=
+ CAS_READ_4(sc, CAS_MAC_NORM_COLL_CNT) +
+ CAS_READ_4(sc, CAS_MAC_FIRST_COLL_CNT);
+ v = CAS_READ_4(sc, CAS_MAC_EXCESS_COLL_CNT) +
+ CAS_READ_4(sc, CAS_MAC_LATE_COLL_CNT);
+ ifp->if_collisions += v;
+ ifp->if_oerrors += v;
+ ifp->if_ierrors +=
+ CAS_READ_4(sc, CAS_MAC_RX_LEN_ERR_CNT) +
+ CAS_READ_4(sc, CAS_MAC_RX_ALIGN_ERR) +
+ CAS_READ_4(sc, CAS_MAC_RX_CRC_ERR_CNT) +
+ CAS_READ_4(sc, CAS_MAC_RX_CODE_VIOL);
+
+ /*
+ * Then clear the hardware counters.
+ */
+ CAS_WRITE_4(sc, CAS_MAC_NORM_COLL_CNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_FIRST_COLL_CNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_EXCESS_COLL_CNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_LATE_COLL_CNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_RX_LEN_ERR_CNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_RX_ALIGN_ERR, 0);
+ CAS_WRITE_4(sc, CAS_MAC_RX_CRC_ERR_CNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_RX_CODE_VIOL, 0);
+
+ mii_tick(sc->sc_mii);
+
+ if (cas_watchdog(sc) == EJUSTRETURN)
+ return;
+
+ callout_reset(&sc->sc_tick_ch, hz, cas_tick, sc);
+}
+
+static int
+cas_bitwait(struct cas_softc *sc, bus_addr_t r, uint32_t clr, uint32_t set)
+{
+ int i;
+ uint32_t reg;
+
+ for (i = CAS_TRIES; i--; DELAY(100)) {
+ reg = CAS_READ_4(sc, r);
+ if ((reg & clr) == 0 && (reg & set) == set)
+ return (1);
+ }
+ return (0);
+}
+
+static void
+cas_reset(struct cas_softc *sc)
+{
+
+#ifdef CAS_DEBUG
+ CTR2(KTR_CAS, "%s: %s", device_get_name(sc->sc_dev), __func__);
+#endif
+ /* Disable all interrupts in order to avoid spurious ones. */
+ CAS_WRITE_4(sc, CAS_INTMASK, 0xffffffff);
+
+ cas_reset_rx(sc);
+ cas_reset_tx(sc);
+
+ /*
+ * Do a full reset modulo the result of the last auto-negotiation
+ * when using the SERDES.
+ */
+ CAS_WRITE_4(sc, CAS_RESET, CAS_RESET_RX | CAS_RESET_TX |
+ ((sc->sc_flags & CAS_SERDES) != 0 ? CAS_RESET_PCS_DIS : 0));
+ CAS_BARRIER(sc, CAS_RESET, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ DELAY(3000);
+ if (!cas_bitwait(sc, CAS_RESET, CAS_RESET_RX | CAS_RESET_TX, 0))
+ device_printf(sc->sc_dev, "cannot reset device\n");
+}
+
+static void
+cas_stop(struct ifnet *ifp)
+{
+ struct cas_softc *sc = ifp->if_softc;
+ struct cas_txsoft *txs;
+
+#ifdef CAS_DEBUG
+ CTR2(KTR_CAS, "%s: %s", device_get_name(sc->sc_dev), __func__);
+#endif
+
+ callout_stop(&sc->sc_tick_ch);
+ callout_stop(&sc->sc_rx_ch);
+
+ /* Disable all interrupts in order to avoid spurious ones. */
+ CAS_WRITE_4(sc, CAS_INTMASK, 0xffffffff);
+
+ cas_reset_tx(sc);
+ cas_reset_rx(sc);
+
+ /*
+ * Release any queued transmit buffers.
+ */
+ while ((txs = STAILQ_FIRST(&sc->sc_txdirtyq)) != NULL) {
+ STAILQ_REMOVE_HEAD(&sc->sc_txdirtyq, txs_q);
+ if (txs->txs_ndescs != 0) {
+ bus_dmamap_sync(sc->sc_tdmatag, txs->txs_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_tdmatag, txs->txs_dmamap);
+ if (txs->txs_mbuf != NULL) {
+ m_freem(txs->txs_mbuf);
+ txs->txs_mbuf = NULL;
+ }
+ }
+ STAILQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q);
+ }
+
+ /*
+ * Mark the interface down and cancel the watchdog timer.
+ */
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+ sc->sc_flags &= ~CAS_LINK;
+ sc->sc_wdog_timer = 0;
+}
+
+static int
+cas_reset_rx(struct cas_softc *sc)
+{
+
+ /*
+ * Resetting while DMA is in progress can cause a bus hang, so we
+ * disable DMA first.
+ */
+ cas_disable_rx(sc);
+ CAS_WRITE_4(sc, CAS_RX_CONF, 0);
+ CAS_BARRIER(sc, CAS_RX_CONF, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ if (!cas_bitwait(sc, CAS_RX_CONF, CAS_RX_CONF_RXDMA_EN, 0))
+ device_printf(sc->sc_dev, "cannot disable RX DMA\n");
+
+ /* Finally, reset the ERX. */
+ CAS_WRITE_4(sc, CAS_RESET, CAS_RESET_RX |
+ ((sc->sc_flags & CAS_SERDES) != 0 ? CAS_RESET_PCS_DIS : 0));
+ CAS_BARRIER(sc, CAS_RESET, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ if (!cas_bitwait(sc, CAS_RESET, CAS_RESET_RX | CAS_RESET_TX, 0)) {
+ device_printf(sc->sc_dev, "cannot reset receiver\n");
+ return (1);
+ }
+ return (0);
+}
+
+static int
+cas_reset_tx(struct cas_softc *sc)
+{
+
+ /*
+ * Resetting while DMA is in progress can cause a bus hang, so we
+ * disable DMA first.
+ */
+ cas_disable_tx(sc);
+ CAS_WRITE_4(sc, CAS_TX_CONF, 0);
+ CAS_BARRIER(sc, CAS_TX_CONF, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ if (!cas_bitwait(sc, CAS_TX_CONF, CAS_TX_CONF_TXDMA_EN, 0))
+ device_printf(sc->sc_dev, "cannot disable TX DMA\n");
+
+ /* Finally, reset the ETX. */
+ CAS_WRITE_4(sc, CAS_RESET, CAS_RESET_TX |
+ ((sc->sc_flags & CAS_SERDES) != 0 ? CAS_RESET_PCS_DIS : 0));
+ CAS_BARRIER(sc, CAS_RESET, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ if (!cas_bitwait(sc, CAS_RESET, CAS_RESET_RX | CAS_RESET_TX, 0)) {
+ device_printf(sc->sc_dev, "cannot reset transmitter\n");
+ return (1);
+ }
+ return (0);
+}
+
+static int
+cas_disable_rx(struct cas_softc *sc)
+{
+
+ CAS_WRITE_4(sc, CAS_MAC_RX_CONF,
+ CAS_READ_4(sc, CAS_MAC_RX_CONF) & ~CAS_MAC_RX_CONF_EN);
+ CAS_BARRIER(sc, CAS_MAC_RX_CONF, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ return (cas_bitwait(sc, CAS_MAC_RX_CONF, CAS_MAC_RX_CONF_EN, 0));
+}
+
+static int
+cas_disable_tx(struct cas_softc *sc)
+{
+
+ CAS_WRITE_4(sc, CAS_MAC_TX_CONF,
+ CAS_READ_4(sc, CAS_MAC_TX_CONF) & ~CAS_MAC_TX_CONF_EN);
+ CAS_BARRIER(sc, CAS_MAC_TX_CONF, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ return (cas_bitwait(sc, CAS_MAC_TX_CONF, CAS_MAC_TX_CONF_EN, 0));
+}
+
+static inline void
+cas_rxcompinit(struct cas_rx_comp *rxcomp)
+{
+
+ rxcomp->crc_word1 = 0;
+ rxcomp->crc_word2 = 0;
+ rxcomp->crc_word3 =
+ htole64(CAS_SET(ETHER_HDR_LEN + sizeof(struct ip), CAS_RC3_CSO));
+ rxcomp->crc_word4 = htole64(CAS_RC4_ZERO);
+}
+
+static void
+cas_meminit(struct cas_softc *sc)
+{
+ int i;
+
+ CAS_LOCK_ASSERT(sc, MA_OWNED);
+
+ /*
+ * Initialize the transmit descriptor ring.
+ */
+ for (i = 0; i < CAS_NTXDESC; i++) {
+ sc->sc_txdescs[i].cd_flags = 0;
+ sc->sc_txdescs[i].cd_buf_ptr = 0;
+ }
+ sc->sc_txfree = CAS_MAXTXFREE;
+ sc->sc_txnext = 0;
+ sc->sc_txwin = 0;
+
+ /*
+ * Initialize the receive completion ring.
+ */
+ for (i = 0; i < CAS_NRXCOMP; i++)
+ cas_rxcompinit(&sc->sc_rxcomps[i]);
+ sc->sc_rxcptr = 0;
+
+ /*
+ * Initialize the first receive descriptor ring. We leave
+ * the second one zeroed as we don't actually use it.
+ */
+ for (i = 0; i < CAS_NRXDESC; i++)
+ CAS_INIT_RXDESC(sc, i, i);
+ sc->sc_rxdptr = 0;
+
+ CAS_CDSYNC(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+}
+
+static u_int
+cas_descsize(u_int sz)
+{
+
+ switch (sz) {
+ case 32:
+ return (CAS_DESC_32);
+ case 64:
+ return (CAS_DESC_64);
+ case 128:
+ return (CAS_DESC_128);
+ case 256:
+ return (CAS_DESC_256);
+ case 512:
+ return (CAS_DESC_512);
+ case 1024:
+ return (CAS_DESC_1K);
+ case 2048:
+ return (CAS_DESC_2K);
+ case 4096:
+ return (CAS_DESC_4K);
+ case 8192:
+ return (CAS_DESC_8K);
+ default:
+ printf("%s: invalid descriptor ring size %d\n", __func__, sz);
+ return (CAS_DESC_32);
+ }
+}
+
+static u_int
+cas_rxcompsize(u_int sz)
+{
+
+ switch (sz) {
+ case 128:
+ return (CAS_RX_CONF_COMP_128);
+ case 256:
+ return (CAS_RX_CONF_COMP_256);
+ case 512:
+ return (CAS_RX_CONF_COMP_512);
+ case 1024:
+ return (CAS_RX_CONF_COMP_1K);
+ case 2048:
+ return (CAS_RX_CONF_COMP_2K);
+ case 4096:
+ return (CAS_RX_CONF_COMP_4K);
+ case 8192:
+ return (CAS_RX_CONF_COMP_8K);
+ case 16384:
+ return (CAS_RX_CONF_COMP_16K);
+ case 32768:
+ return (CAS_RX_CONF_COMP_32K);
+ default:
+ printf("%s: invalid dcompletion ring size %d\n", __func__, sz);
+ return (CAS_RX_CONF_COMP_128);
+ }
+}
+
+static void
+cas_init(void *xsc)
+{
+ struct cas_softc *sc = xsc;
+
+ CAS_LOCK(sc);
+ cas_init_locked(sc);
+ CAS_UNLOCK(sc);
+}
+
+/*
+ * Initialization of interface; set up initialization block
+ * and transmit/receive descriptor rings.
+ */
+static void
+cas_init_locked(struct cas_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ uint32_t v;
+
+ CAS_LOCK_ASSERT(sc, MA_OWNED);
+
+#ifdef CAS_DEBUG
+ CTR2(KTR_CAS, "%s: %s: calling stop", device_get_name(sc->sc_dev),
+ __func__);
+#endif
+ /*
+ * Initialization sequence. The numbered steps below correspond
+ * to the sequence outlined in section 6.3.5.1 in the Ethernet
+ * Channel Engine manual (part of the PCIO manual).
+ * See also the STP2002-STQ document from Sun Microsystems.
+ */
+
+ /* step 1 & 2. Reset the Ethernet Channel. */
+ cas_stop(ifp);
+ cas_reset(sc);
+#ifdef CAS_DEBUG
+ CTR2(KTR_CAS, "%s: %s: restarting", device_get_name(sc->sc_dev),
+ __func__);
+#endif
+
+ /* Re-initialize the MIF. */
+ cas_mifinit(sc);
+
+ /* step 3. Setup data structures in host memory. */
+ cas_meminit(sc);
+
+ /* step 4. TX MAC registers & counters */
+ cas_init_regs(sc);
+
+ /* step 5. RX MAC registers & counters */
+ cas_setladrf(sc);
+
+ /* step 6 & 7. Program Ring Base Addresses. */
+ CAS_WRITE_4(sc, CAS_TX_DESC3_BASE_HI,
+ (((uint64_t)CAS_CDTXDADDR(sc, 0)) >> 32));
+ CAS_WRITE_4(sc, CAS_TX_DESC3_BASE_LO,
+ CAS_CDTXDADDR(sc, 0) & 0xffffffff);
+
+ CAS_WRITE_4(sc, CAS_RX_COMP_BASE_HI,
+ (((uint64_t)CAS_CDRXCADDR(sc, 0)) >> 32));
+ CAS_WRITE_4(sc, CAS_RX_COMP_BASE_LO,
+ CAS_CDRXCADDR(sc, 0) & 0xffffffff);
+
+ CAS_WRITE_4(sc, CAS_RX_DESC_BASE_HI,
+ (((uint64_t)CAS_CDRXDADDR(sc, 0)) >> 32));
+ CAS_WRITE_4(sc, CAS_RX_DESC_BASE_LO,
+ CAS_CDRXDADDR(sc, 0) & 0xffffffff);
+
+ if ((sc->sc_flags & CAS_REG_PLUS) != 0) {
+ CAS_WRITE_4(sc, CAS_RX_DESC2_BASE_HI,
+ (((uint64_t)CAS_CDRXD2ADDR(sc, 0)) >> 32));
+ CAS_WRITE_4(sc, CAS_RX_DESC2_BASE_LO,
+ CAS_CDRXD2ADDR(sc, 0) & 0xffffffff);
+ }
+
+#ifdef CAS_DEBUG
+ CTR5(KTR_CAS,
+ "loading TXDR %lx, RXCR %lx, RXDR %lx, RXD2R %lx, cddma %lx",
+ CAS_CDTXDADDR(sc, 0), CAS_CDRXCADDR(sc, 0), CAS_CDRXDADDR(sc, 0),
+ CAS_CDRXD2ADDR(sc, 0), sc->sc_cddma);
+#endif
+
+ /* step 8. Global Configuration & Interrupt Masks */
+
+ /* Disable weighted round robin. */
+ CAS_WRITE_4(sc, CAS_CAW, CAS_CAW_RR_DIS);
+
+ /*
+ * Enable infinite bursts for revisions without PCI issues if
+ * applicable. Doing so greatly improves the TX performance on
+ * !__sparc64__.
+ */
+ CAS_WRITE_4(sc, CAS_INF_BURST,
+#if !defined(__sparc64__)
+ (sc->sc_flags & CAS_TABORT) == 0 ? CAS_INF_BURST_EN :
+#endif
+ 0);
+
+ /* Set up interrupts. */
+ CAS_WRITE_4(sc, CAS_INTMASK,
+ ~(CAS_INTR_TX_INT_ME | CAS_INTR_TX_ALL | CAS_INTR_TX_TAG_ERR |
+ CAS_INTR_RX_DONE | CAS_INTR_RX_BUF_NA | CAS_INTR_RX_TAG_ERR |
+ CAS_INTR_RX_COMP_FULL | CAS_INTR_RX_BUF_AEMPTY |
+ CAS_INTR_RX_COMP_AFULL | CAS_INTR_RX_LEN_MMATCH |
+ CAS_INTR_PCI_ERROR_INT
+#ifdef CAS_DEBUG
+ | CAS_INTR_PCS_INT | CAS_INTR_MIF
+#endif
+ ));
+ CAS_WRITE_4(sc, CAS_MAC_RX_MASK, ~CAS_MAC_RX_OVERFLOW);
+ CAS_WRITE_4(sc, CAS_MAC_TX_MASK,
+ ~(CAS_MAC_TX_UNDERRUN | CAS_MAC_TX_MAX_PKT_ERR));
+#ifdef CAS_DEBUG
+ CAS_WRITE_4(sc, CAS_MAC_CTRL_MASK,
+ ~(CAS_MAC_CTRL_PAUSE_RCVD | CAS_MAC_CTRL_PAUSE |
+ CAS_MAC_CTRL_NON_PAUSE));
+#else
+ CAS_WRITE_4(sc, CAS_MAC_CTRL_MASK,
+ CAS_MAC_CTRL_PAUSE_RCVD | CAS_MAC_CTRL_PAUSE |
+ CAS_MAC_CTRL_NON_PAUSE);
+#endif
+
+ /* Enable PCI error interrupts. */
+ CAS_WRITE_4(sc, CAS_ERROR_MASK,
+ ~(CAS_ERROR_DTRTO | CAS_ERROR_OTHER | CAS_ERROR_DMAW_ZERO |
+ CAS_ERROR_DMAR_ZERO | CAS_ERROR_RTRTO));
+
+ /* Enable PCI error interrupts in BIM configuration. */
+ CAS_WRITE_4(sc, CAS_BIM_CONF,
+ CAS_BIM_CONF_DPAR_EN | CAS_BIM_CONF_RMA_EN | CAS_BIM_CONF_RTA_EN);
+
+ /*
+ * step 9. ETX Configuration: encode receive descriptor ring size,
+ * enable DMA and disable pre-interrupt writeback completion.
+ */
+ v = cas_descsize(CAS_NTXDESC) << CAS_TX_CONF_DESC3_SHFT;
+ CAS_WRITE_4(sc, CAS_TX_CONF, v | CAS_TX_CONF_TXDMA_EN |
+ CAS_TX_CONF_RDPP_DIS | CAS_TX_CONF_PICWB_DIS);
+
+ /* step 10. ERX Configuration */
+
+ /*
+ * Encode receive completion and descriptor ring sizes, set the
+ * swivel offset.
+ */
+ v = cas_rxcompsize(CAS_NRXCOMP) << CAS_RX_CONF_COMP_SHFT;
+ v |= cas_descsize(CAS_NRXDESC) << CAS_RX_CONF_DESC_SHFT;
+ if ((sc->sc_flags & CAS_REG_PLUS) != 0)
+ v |= cas_descsize(CAS_NRXDESC2) << CAS_RX_CONF_DESC2_SHFT;
+ CAS_WRITE_4(sc, CAS_RX_CONF,
+ v | (ETHER_ALIGN << CAS_RX_CONF_SOFF_SHFT));
+
+ /* Set the PAUSE thresholds. We use the maximum OFF threshold. */
+ CAS_WRITE_4(sc, CAS_RX_PTHRS,
+ ((111 * 64) << CAS_RX_PTHRS_XOFF_SHFT) |
+ ((15 * 64) << CAS_RX_PTHRS_XON_SHFT));
+
+ /* RX blanking */
+ CAS_WRITE_4(sc, CAS_RX_BLANK,
+ (15 << CAS_RX_BLANK_TIME_SHFT) | (5 << CAS_RX_BLANK_PKTS_SHFT));
+
+ /* Set RX_COMP_AFULL threshold to half of the RX completions. */
+ CAS_WRITE_4(sc, CAS_RX_AEMPTY_THRS,
+ (CAS_NRXCOMP / 2) << CAS_RX_AEMPTY_COMP_SHFT);
+
+ /* Initialize the RX page size register as appropriate for 8k. */
+ CAS_WRITE_4(sc, CAS_RX_PSZ,
+ (CAS_RX_PSZ_8K << CAS_RX_PSZ_SHFT) |
+ (4 << CAS_RX_PSZ_MB_CNT_SHFT) |
+ (CAS_RX_PSZ_MB_STRD_2K << CAS_RX_PSZ_MB_STRD_SHFT) |
+ (CAS_RX_PSZ_MB_OFF_64 << CAS_RX_PSZ_MB_OFF_SHFT));
+
+ /* Disable RX random early detection. */
+ CAS_WRITE_4(sc, CAS_RX_RED, 0);
+
+ /* Zero the RX reassembly DMA table. */
+ for (v = 0; v <= CAS_RX_REAS_DMA_ADDR_LC; v++) {
+ CAS_WRITE_4(sc, CAS_RX_REAS_DMA_ADDR, v);
+ CAS_WRITE_4(sc, CAS_RX_REAS_DMA_DATA_LO, 0);
+ CAS_WRITE_4(sc, CAS_RX_REAS_DMA_DATA_MD, 0);
+ CAS_WRITE_4(sc, CAS_RX_REAS_DMA_DATA_HI, 0);
+ }
+
+ /* Ensure the RX control FIFO and RX IPP FIFO addresses are zero. */
+ CAS_WRITE_4(sc, CAS_RX_CTRL_FIFO, 0);
+ CAS_WRITE_4(sc, CAS_RX_IPP_ADDR, 0);
+
+ /* Finally, enable RX DMA. */
+ CAS_WRITE_4(sc, CAS_RX_CONF,
+ CAS_READ_4(sc, CAS_RX_CONF) | CAS_RX_CONF_RXDMA_EN);
+
+ /* step 11. Configure Media. */
+
+ /* step 12. RX_MAC Configuration Register */
+ v = CAS_READ_4(sc, CAS_MAC_RX_CONF) & ~CAS_MAC_RX_CONF_STRPPAD;
+ v |= CAS_MAC_RX_CONF_EN | CAS_MAC_RX_CONF_STRPFCS;
+ CAS_WRITE_4(sc, CAS_MAC_RX_CONF, 0);
+ CAS_BARRIER(sc, CAS_MAC_RX_CONF, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ if (!cas_bitwait(sc, CAS_MAC_RX_CONF, CAS_MAC_RX_CONF_EN, 0))
+ device_printf(sc->sc_dev, "cannot configure RX MAC\n");
+ CAS_WRITE_4(sc, CAS_MAC_RX_CONF, v);
+
+ /* step 13. TX_MAC Configuration Register */
+ v = CAS_READ_4(sc, CAS_MAC_TX_CONF);
+ v |= CAS_MAC_TX_CONF_EN;
+ CAS_WRITE_4(sc, CAS_MAC_TX_CONF, 0);
+ CAS_BARRIER(sc, CAS_MAC_TX_CONF, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ if (!cas_bitwait(sc, CAS_MAC_TX_CONF, CAS_MAC_TX_CONF_EN, 0))
+ device_printf(sc->sc_dev, "cannot configure TX MAC\n");
+ CAS_WRITE_4(sc, CAS_MAC_TX_CONF, v);
+
+ /* step 14. Issue Transmit Pending command. */
+
+ /* step 15. Give the reciever a swift kick. */
+ CAS_WRITE_4(sc, CAS_RX_KICK, CAS_NRXDESC - 4);
+ CAS_WRITE_4(sc, CAS_RX_COMP_TAIL, 0);
+ if ((sc->sc_flags & CAS_REG_PLUS) != 0)
+ CAS_WRITE_4(sc, CAS_RX_KICK2, CAS_NRXDESC2 - 4);
+
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+
+ mii_mediachg(sc->sc_mii);
+
+ /* Start the one second timer. */
+ sc->sc_wdog_timer = 0;
+ callout_reset(&sc->sc_tick_ch, hz, cas_tick, sc);
+}
+
+static int
+cas_load_txmbuf(struct cas_softc *sc, struct mbuf **m_head)
+{
+ bus_dma_segment_t txsegs[CAS_NTXSEGS];
+ struct cas_txsoft *txs;
+ struct ip *ip;
+ struct mbuf *m;
+ uint64_t cflags;
+ int error, nexttx, nsegs, offset, seg;
+
+ CAS_LOCK_ASSERT(sc, MA_OWNED);
+
+ /* Get a work queue entry. */
+ if ((txs = STAILQ_FIRST(&sc->sc_txfreeq)) == NULL) {
+ /* Ran out of descriptors. */
+ return (ENOBUFS);
+ }
+
+ cflags = 0;
+ if (((*m_head)->m_pkthdr.csum_flags & CAS_CSUM_FEATURES) != 0) {
+ if (M_WRITABLE(*m_head) == 0) {
+ m = m_dup(*m_head, M_DONTWAIT);
+ m_freem(*m_head);
+ *m_head = m;
+ if (m == NULL)
+ return (ENOBUFS);
+ }
+ offset = sizeof(struct ether_header);
+ m = m_pullup(*m_head, offset + sizeof(struct ip));
+ if (m == NULL) {
+ *m_head = NULL;
+ return (ENOBUFS);
+ }
+ ip = (struct ip *)(mtod(m, caddr_t) + offset);
+ offset += (ip->ip_hl << 2);
+ cflags = (offset << CAS_TD_CKSUM_START_SHFT) |
+ ((offset + m->m_pkthdr.csum_data) <<
+ CAS_TD_CKSUM_STUFF_SHFT) | CAS_TD_CKSUM_EN;
+ *m_head = m;
+ }
+
+ error = bus_dmamap_load_mbuf_sg(sc->sc_tdmatag, txs->txs_dmamap,
+ *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
+ if (error == EFBIG) {
+ m = m_collapse(*m_head, M_DONTWAIT, CAS_NTXSEGS);
+ if (m == NULL) {
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (ENOBUFS);
+ }
+ *m_head = m;
+ error = bus_dmamap_load_mbuf_sg(sc->sc_tdmatag,
+ txs->txs_dmamap, *m_head, txsegs, &nsegs,
+ BUS_DMA_NOWAIT);
+ if (error != 0) {
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (error);
+ }
+ } else if (error != 0)
+ return (error);
+ /* If nsegs is wrong then the stack is corrupt. */
+ KASSERT(nsegs <= CAS_NTXSEGS,
+ ("%s: too many DMA segments (%d)", __func__, nsegs));
+ if (nsegs == 0) {
+ m_freem(*m_head);
+ *m_head = NULL;
+ return (EIO);
+ }
+
+ /*
+ * Ensure we have enough descriptors free to describe
+ * the packet. Note, we always reserve one descriptor
+ * at the end of the ring as a termination point, in
+ * order to prevent wrap-around.
+ */
+ if (nsegs > sc->sc_txfree - 1) {
+ txs->txs_ndescs = 0;
+ bus_dmamap_unload(sc->sc_tdmatag, txs->txs_dmamap);
+ return (ENOBUFS);
+ }
+
+ txs->txs_ndescs = nsegs;
+ txs->txs_firstdesc = sc->sc_txnext;
+ nexttx = txs->txs_firstdesc;
+ for (seg = 0; seg < nsegs; seg++, nexttx = CAS_NEXTTX(nexttx)) {
+#ifdef CAS_DEBUG
+ CTR6(KTR_CAS,
+ "%s: mapping seg %d (txd %d), len %lx, addr %#lx (%#lx)",
+ __func__, seg, nexttx, txsegs[seg].ds_len,
+ txsegs[seg].ds_addr, htole64(txsegs[seg].ds_addr));
+#endif
+ sc->sc_txdescs[nexttx].cd_buf_ptr =
+ htole64(txsegs[seg].ds_addr);
+ KASSERT(txsegs[seg].ds_len <
+ CAS_TD_BUF_LEN_MASK >> CAS_TD_BUF_LEN_SHFT,
+ ("%s: segment size too large!", __func__));
+ sc->sc_txdescs[nexttx].cd_flags =
+ htole64(txsegs[seg].ds_len << CAS_TD_BUF_LEN_SHFT);
+ txs->txs_lastdesc = nexttx;
+ }
+
+ /* Set EOF on the last descriptor. */
+#ifdef CAS_DEBUG
+ CTR3(KTR_CAS, "%s: end of frame at segment %d, TX %d",
+ __func__, seg, nexttx);
+#endif
+ sc->sc_txdescs[txs->txs_lastdesc].cd_flags |=
+ htole64(CAS_TD_END_OF_FRAME);
+
+ /* Lastly set SOF on the first descriptor. */
+#ifdef CAS_DEBUG
+ CTR3(KTR_CAS, "%s: start of frame at segment %d, TX %d",
+ __func__, seg, nexttx);
+#endif
+ if (sc->sc_txwin += nsegs > CAS_NTXSEGS * 2 / 3) {
+ sc->sc_txwin = 0;
+ sc->sc_txdescs[txs->txs_firstdesc].cd_flags |=
+ htole64(cflags | CAS_TD_START_OF_FRAME | CAS_TD_INT_ME);
+ } else
+ sc->sc_txdescs[txs->txs_firstdesc].cd_flags |=
+ htole64(cflags | CAS_TD_START_OF_FRAME);
+
+ /* Sync the DMA map. */
+ bus_dmamap_sync(sc->sc_tdmatag, txs->txs_dmamap,
+ BUS_DMASYNC_PREWRITE);
+
+#ifdef CAS_DEBUG
+ CTR4(KTR_CAS, "%s: setting firstdesc=%d, lastdesc=%d, ndescs=%d",
+ __func__, txs->txs_firstdesc, txs->txs_lastdesc,
+ txs->txs_ndescs);
+#endif
+ STAILQ_REMOVE_HEAD(&sc->sc_txfreeq, txs_q);
+ STAILQ_INSERT_TAIL(&sc->sc_txdirtyq, txs, txs_q);
+ txs->txs_mbuf = *m_head;
+
+ sc->sc_txnext = CAS_NEXTTX(txs->txs_lastdesc);
+ sc->sc_txfree -= txs->txs_ndescs;
+
+ return (0);
+}
+
+static void
+cas_init_regs(struct cas_softc *sc)
+{
+ int i;
+ const u_char *laddr = IF_LLADDR(sc->sc_ifp);
+
+ CAS_LOCK_ASSERT(sc, MA_OWNED);
+
+ /* These registers are not cleared on reset. */
+ if ((sc->sc_flags & CAS_INITED) == 0) {
+ /* magic values */
+ CAS_WRITE_4(sc, CAS_MAC_IPG0, 0);
+ CAS_WRITE_4(sc, CAS_MAC_IPG1, 8);
+ CAS_WRITE_4(sc, CAS_MAC_IPG2, 4);
+
+ /* min frame length */
+ CAS_WRITE_4(sc, CAS_MAC_MIN_FRAME, ETHER_MIN_LEN);
+ /* max frame length and max burst size */
+ CAS_WRITE_4(sc, CAS_MAC_MAX_BF,
+ ((ETHER_MAX_LEN_JUMBO + ETHER_VLAN_ENCAP_LEN) <<
+ CAS_MAC_MAX_BF_FRM_SHFT) |
+ (0x2000 << CAS_MAC_MAX_BF_BST_SHFT));
+
+ /* more magic values */
+ CAS_WRITE_4(sc, CAS_MAC_PREAMBLE_LEN, 0x7);
+ CAS_WRITE_4(sc, CAS_MAC_JAM_SIZE, 0x4);
+ CAS_WRITE_4(sc, CAS_MAC_ATTEMPT_LIMIT, 0x10);
+ CAS_WRITE_4(sc, CAS_MAC_CTRL_TYPE, 0x8088);
+
+ /* random number seed */
+ CAS_WRITE_4(sc, CAS_MAC_RANDOM_SEED,
+ ((laddr[5] << 8) | laddr[4]) & 0x3ff);
+
+ /* secondary MAC addresses: 0:0:0:0:0:0 */
+ for (i = CAS_MAC_ADDR3; i <= CAS_MAC_ADDR41;
+ i += CAS_MAC_ADDR4 - CAS_MAC_ADDR3)
+ CAS_WRITE_4(sc, i, 0);
+
+ /* MAC control address: 01:80:c2:00:00:01 */
+ CAS_WRITE_4(sc, CAS_MAC_ADDR42, 0x0001);
+ CAS_WRITE_4(sc, CAS_MAC_ADDR43, 0xc200);
+ CAS_WRITE_4(sc, CAS_MAC_ADDR44, 0x0180);
+
+ /* MAC filter address: 0:0:0:0:0:0 */
+ CAS_WRITE_4(sc, CAS_MAC_AFILTER0, 0);
+ CAS_WRITE_4(sc, CAS_MAC_AFILTER1, 0);
+ CAS_WRITE_4(sc, CAS_MAC_AFILTER2, 0);
+ CAS_WRITE_4(sc, CAS_MAC_AFILTER_MASK1_2, 0);
+ CAS_WRITE_4(sc, CAS_MAC_AFILTER_MASK0, 0);
+
+ /* Zero the hash table. */
+ for (i = CAS_MAC_HASH0; i <= CAS_MAC_HASH15;
+ i += CAS_MAC_HASH1 - CAS_MAC_HASH0)
+ CAS_WRITE_4(sc, i, 0);
+
+ sc->sc_flags |= CAS_INITED;
+ }
+
+ /* Counters need to be zeroed. */
+ CAS_WRITE_4(sc, CAS_MAC_NORM_COLL_CNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_FIRST_COLL_CNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_EXCESS_COLL_CNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_LATE_COLL_CNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_DEFER_TMR_CNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_PEAK_ATTEMPTS, 0);
+ CAS_WRITE_4(sc, CAS_MAC_RX_FRAME_COUNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_RX_LEN_ERR_CNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_RX_ALIGN_ERR, 0);
+ CAS_WRITE_4(sc, CAS_MAC_RX_CRC_ERR_CNT, 0);
+ CAS_WRITE_4(sc, CAS_MAC_RX_CODE_VIOL, 0);
+
+ /* Set XOFF PAUSE time. */
+ CAS_WRITE_4(sc, CAS_MAC_SPC, 0x1BF0 << CAS_MAC_SPC_TIME_SHFT);
+
+ /* Set the station address. */
+ CAS_WRITE_4(sc, CAS_MAC_ADDR0, (laddr[4] << 8) | laddr[5]);
+ CAS_WRITE_4(sc, CAS_MAC_ADDR1, (laddr[2] << 8) | laddr[3]);
+ CAS_WRITE_4(sc, CAS_MAC_ADDR2, (laddr[0] << 8) | laddr[1]);
+
+ /* Enable MII outputs. */
+ CAS_WRITE_4(sc, CAS_MAC_XIF_CONF, CAS_MAC_XIF_CONF_TX_OE);
+}
+
+static void
+cas_start(struct ifnet *ifp)
+{
+ struct cas_softc *sc = ifp->if_softc;
+
+ CAS_LOCK(sc);
+ cas_start_locked(ifp);
+ CAS_UNLOCK(sc);
+}
+
+static inline void
+cas_txkick(struct cas_softc *sc)
+{
+
+ /*
+ * Update the TX kick register. This register has to point to the
+ * descriptor after the last valid one and for optimum performance
+ * should be incremented in multiples of 4 (the DMA engine fetches/
+ * updates descriptors in batches of 4).
+ */
+#ifdef CAS_DEBUG
+ CTR3(KTR_CAS, "%s: %s: kicking TX %d",
+ device_get_name(sc->sc_dev), __func__, sc->sc_txnext);
+#endif
+ CAS_CDSYNC(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ CAS_WRITE_4(sc, CAS_TX_KICK3, sc->sc_txnext);
+}
+
+static void
+cas_start_locked(struct ifnet *ifp)
+{
+ struct cas_softc *sc = ifp->if_softc;
+ struct mbuf *m;
+ int kicked, ntx;
+
+ CAS_LOCK_ASSERT(sc, MA_OWNED);
+
+ if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
+ IFF_DRV_RUNNING || (sc->sc_flags & CAS_LINK) == 0)
+ return;
+
+#ifdef CAS_DEBUG
+ CTR4(KTR_CAS, "%s: %s: txfree %d, txnext %d",
+ device_get_name(sc->sc_dev), __func__, sc->sc_txfree,
+ sc->sc_txnext);
+#endif
+ ntx = 0;
+ kicked = 0;
+ for (; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && sc->sc_txfree > 1;) {
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL)
+ break;
+ if (cas_load_txmbuf(sc, &m) != 0) {
+ if (m == NULL)
+ break;
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ IFQ_DRV_PREPEND(&ifp->if_snd, m);
+ break;
+ }
+ if ((sc->sc_txnext % 4) == 0) {
+ cas_txkick(sc);
+ kicked = 1;
+ } else
+ kicked = 0;
+ ntx++;
+ BPF_MTAP(ifp, m);
+ }
+
+ if (ntx > 0) {
+ if (kicked == 0)
+ cas_txkick(sc);
+#ifdef CAS_DEBUG
+ CTR2(KTR_CAS, "%s: packets enqueued, OWN on %d",
+ device_get_name(sc->sc_dev), sc->sc_txnext);
+#endif
+
+ /* Set a watchdog timer in case the chip flakes out. */
+ sc->sc_wdog_timer = 5;
+#ifdef CAS_DEBUG
+ CTR3(KTR_CAS, "%s: %s: watchdog %d",
+ device_get_name(sc->sc_dev), __func__,
+ sc->sc_wdog_timer);
+#endif
+ }
+}
+
+static void
+cas_tint(struct cas_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct cas_txsoft *txs;
+ int progress;
+ uint32_t txlast;
+#ifdef CAS_DEBUG
+ int i;
+
+ CAS_LOCK_ASSERT(sc, MA_OWNED);
+
+ CTR2(KTR_CAS, "%s: %s", device_get_name(sc->sc_dev), __func__);
+#endif
+
+ /*
+ * Go through our TX list and free mbufs for those
+ * frames that have been transmitted.
+ */
+ progress = 0;
+ CAS_CDSYNC(sc, BUS_DMASYNC_POSTREAD);
+ while ((txs = STAILQ_FIRST(&sc->sc_txdirtyq)) != NULL) {
+#ifdef CAS_DEBUG
+ if ((ifp->if_flags & IFF_DEBUG) != 0) {
+ printf(" txsoft %p transmit chain:\n", txs);
+ for (i = txs->txs_firstdesc;; i = CAS_NEXTTX(i)) {
+ printf("descriptor %d: ", i);
+ printf("cd_flags: 0x%016llx\t",
+ (long long)le64toh(
+ sc->sc_txdescs[i].cd_flags));
+ printf("cd_buf_ptr: 0x%016llx\n",
+ (long long)le64toh(
+ sc->sc_txdescs[i].cd_buf_ptr));
+ if (i == txs->txs_lastdesc)
+ break;
+ }
+ }
+#endif
+
+ /*
+ * In theory, we could harvest some descriptors before
+ * the ring is empty, but that's a bit complicated.
+ *
+ * CAS_TX_COMPn points to the last descriptor
+ * processed + 1.
+ */
+ txlast = CAS_READ_4(sc, CAS_TX_COMP3);
+#ifdef CAS_DEBUG
+ CTR4(KTR_CAS, "%s: txs->txs_firstdesc = %d, "
+ "txs->txs_lastdesc = %d, txlast = %d",
+ __func__, txs->txs_firstdesc, txs->txs_lastdesc, txlast);
+#endif
+ if (txs->txs_firstdesc <= txs->txs_lastdesc) {
+ if ((txlast >= txs->txs_firstdesc) &&
+ (txlast <= txs->txs_lastdesc))
+ break;
+ } else {
+ /* Ick -- this command wraps. */
+ if ((txlast >= txs->txs_firstdesc) ||
+ (txlast <= txs->txs_lastdesc))
+ break;
+ }
+
+#ifdef CAS_DEBUG
+ CTR1(KTR_CAS, "%s: releasing a descriptor", __func__);
+#endif
+ STAILQ_REMOVE_HEAD(&sc->sc_txdirtyq, txs_q);
+
+ sc->sc_txfree += txs->txs_ndescs;
+
+ bus_dmamap_sync(sc->sc_tdmatag, txs->txs_dmamap,
+ BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(sc->sc_tdmatag, txs->txs_dmamap);
+ if (txs->txs_mbuf != NULL) {
+ m_freem(txs->txs_mbuf);
+ txs->txs_mbuf = NULL;
+ }
+
+ STAILQ_INSERT_TAIL(&sc->sc_txfreeq, txs, txs_q);
+
+ ifp->if_opackets++;
+ progress = 1;
+ }
+
+#ifdef CAS_DEBUG
+ CTR4(KTR_CAS, "%s: CAS_TX_STATE_MACHINE %x CAS_TX_DESC_BASE %llx "
+ "CAS_TX_COMP3 %x",
+ __func__, CAS_READ_4(sc, CAS_TX_STATE_MACHINE),
+ ((long long)CAS_READ_4(sc, CAS_TX_DESC_BASE_HI3) << 32) |
+ CAS_READ_4(sc, CAS_TX_DESC_BASE_LO3),
+ CAS_READ_4(sc, CAS_TX_COMP3));
+#endif
+
+ if (progress) {
+ if (sc->sc_txfree == CAS_NTXDESC - 1)
+ sc->sc_txwin = 0;
+
+ /*
+ * We freed some descriptors, so reset IFF_DRV_OACTIVE
+ * and restart.
+ */
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ if (STAILQ_EMPTY(&sc->sc_txdirtyq))
+ sc->sc_wdog_timer = 0;
+ cas_start_locked(ifp);
+ }
+
+#ifdef CAS_DEBUG
+ CTR3(KTR_CAS, "%s: %s: watchdog %d",
+ device_get_name(sc->sc_dev), __func__, sc->sc_wdog_timer);
+#endif
+}
+
+static void
+cas_rint_timeout(void *arg)
+{
+ struct cas_softc *sc = arg;
+
+ CAS_LOCK_ASSERT(sc, MA_OWNED);
+
+ cas_rint(sc);
+}
+
+static void
+cas_rint(struct cas_softc *sc)
+{
+ struct cas_rxdsoft *rxds, *rxds2;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m, *m2;
+ uint64_t word1, word2, word3, word4;
+ uint32_t rxhead;
+ u_int idx, idx2, len, off, skip;
+
+ CAS_LOCK_ASSERT(sc, MA_OWNED);
+
+ callout_stop(&sc->sc_rx_ch);
+
+#ifdef CAS_DEBUG
+ CTR2(KTR_CAS, "%s: %s", device_get_name(sc->sc_dev), __func__);
+#endif
+
+#define PRINTWORD(n, delimiter) \
+ printf("word ## n: 0x%016llx%c", (long long)word ## n, delimiter)
+
+#define SKIPASSERT(n) \
+ KASSERT(sc->sc_rxcomps[sc->sc_rxcptr].crc_word ## n == 0, \
+ ("%s: word ## n not 0", __func__))
+
+#define WORDTOH(n) \
+ word ## n = le64toh(sc->sc_rxcomps[sc->sc_rxcptr].crc_word ## n)
+
+ /*
+ * Read the completion head register once. This limits
+ * how long the following loop can execute.
+ */
+ rxhead = CAS_READ_4(sc, CAS_RX_COMP_HEAD);
+#ifdef CAS_DEBUG
+ CTR4(KTR_CAS, "%s: sc->sc_rxcptr %d, sc->sc_rxdptr %d, head %d",
+ __func__, sc->rxcptr, sc->sc_rxdptr, rxhead);
+#endif
+ skip = 0;
+ CAS_CDSYNC(sc, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ for (; sc->sc_rxcptr != rxhead;
+ sc->sc_rxcptr = CAS_NEXTRXCOMP(sc->sc_rxcptr)) {
+ if (skip != 0) {
+ SKIPASSERT(1);
+ SKIPASSERT(2);
+ SKIPASSERT(3);
+
+ --skip;
+ goto skip;
+ }
+
+ WORDTOH(1);
+ WORDTOH(2);
+ WORDTOH(3);
+ WORDTOH(4);
+
+#ifdef CAS_DEBUG
+ if ((ifp->if_flags & IFF_DEBUG) != 0) {
+ printf(" completion %d: ", sc->sc_rxcptr);
+ PRINTWORD(1, '\t');
+ PRINTWORD(2, '\t');
+ PRINTWORD(3, '\t');
+ PRINTWORD(4, '\n');
+ }
+#endif
+
+ if (__predict_false(
+ (word1 & CAS_RC1_TYPE_MASK) == CAS_RC1_TYPE_HW ||
+ (word4 & CAS_RC4_ZERO) != 0)) {
+ /*
+ * The descriptor is still marked as owned, although
+ * it is supposed to have completed. This has been
+ * observed on some machines. Just exiting here
+ * might leave the packet sitting around until another
+ * one arrives to trigger a new interrupt, which is
+ * generally undesirable, so set up a timeout.
+ */
+ callout_reset(&sc->sc_rx_ch, CAS_RXOWN_TICKS,
+ cas_rint_timeout, sc);
+ break;
+ }
+
+ if (__predict_false(
+ (word4 & (CAS_RC4_BAD | CAS_RC4_LEN_MMATCH)) != 0)) {
+ ifp->if_ierrors++;
+ device_printf(sc->sc_dev,
+ "receive error: CRC error\n");
+ continue;
+ }
+
+ KASSERT(CAS_GET(word1, CAS_RC1_DATA_SIZE) == 0 ||
+ CAS_GET(word2, CAS_RC2_HDR_SIZE) == 0,
+ ("%s: data and header present", __func__));
+ KASSERT((word1 & CAS_RC1_SPLIT_PKT) == 0 ||
+ CAS_GET(word2, CAS_RC2_HDR_SIZE) == 0,
+ ("%s: split and header present", __func__));
+ KASSERT(CAS_GET(word1, CAS_RC1_DATA_SIZE) == 0 ||
+ (word1 & CAS_RC1_RELEASE_HDR) == 0,
+ ("%s: data present but header release", __func__));
+ KASSERT(CAS_GET(word2, CAS_RC2_HDR_SIZE) == 0 ||
+ (word1 & CAS_RC1_RELEASE_DATA) == 0,
+ ("%s: header present but data release", __func__));
+
+ if ((len = CAS_GET(word2, CAS_RC2_HDR_SIZE)) != 0) {
+ idx = CAS_GET(word2, CAS_RC2_HDR_INDEX);
+ off = CAS_GET(word2, CAS_RC2_HDR_OFF);
+#ifdef CAS_DEBUG
+ CTR4(KTR_CAS, "%s: hdr at idx %d, off %d, len %d",
+ __func__, idx, off, len);
+#endif
+ rxds = &sc->sc_rxdsoft[idx];
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m != NULL) {
+ refcount_acquire(&rxds->rxds_refcount);
+ bus_dmamap_sync(sc->sc_rdmatag,
+ rxds->rxds_dmamap, BUS_DMASYNC_POSTREAD);
+ MEXTADD(m, (caddr_t)rxds->rxds_buf +
+ off * 256 + ETHER_ALIGN, len, cas_free,
+#if __FreeBSD_version < 800016
+ rxds,
+#else
+ sc, (void *)(uintptr_t)idx,
+#endif
+ M_RDONLY, EXT_NET_DRV);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ m = NULL;
+ }
+ }
+ if (m != NULL) {
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = len;
+ ifp->if_ipackets++;
+ if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
+ cas_rxcksum(m, CAS_GET(word4,
+ CAS_RC4_TCP_CSUM));
+ /* Pass it on. */
+ CAS_UNLOCK(sc);
+ (*ifp->if_input)(ifp, m);
+ CAS_LOCK(sc);
+ } else
+ ifp->if_ierrors++;
+
+ if ((word1 & CAS_RC1_RELEASE_HDR) != 0 &&
+ refcount_release(&rxds->rxds_refcount) != 0)
+ cas_add_rxdesc(sc, idx);
+ } else if ((len = CAS_GET(word1, CAS_RC1_DATA_SIZE)) != 0) {
+ idx = CAS_GET(word1, CAS_RC1_DATA_INDEX);
+ off = CAS_GET(word1, CAS_RC1_DATA_OFF);
+#ifdef CAS_DEBUG
+ CTR4(KTR_CAS, "%s: data at idx %d, off %d, len %d",
+ __func__, idx, off, len);
+#endif
+ rxds = &sc->sc_rxdsoft[idx];
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m != NULL) {
+ refcount_acquire(&rxds->rxds_refcount);
+ off += ETHER_ALIGN;
+ m->m_len = min(CAS_PAGE_SIZE - off, len);
+ bus_dmamap_sync(sc->sc_rdmatag,
+ rxds->rxds_dmamap, BUS_DMASYNC_POSTREAD);
+ MEXTADD(m, (caddr_t)rxds->rxds_buf + off,
+ m->m_len, cas_free,
+#if __FreeBSD_version < 800016
+ rxds,
+#else
+ sc, (void *)(uintptr_t)idx,
+#endif
+ M_RDONLY, EXT_NET_DRV);
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
+ m = NULL;
+ }
+ }
+ idx2 = 0;
+ rxds2 = NULL;
+ if ((word1 & CAS_RC1_SPLIT_PKT) != 0) {
+ KASSERT((word1 & CAS_RC1_RELEASE_NEXT) != 0,
+ ("%s: split but no release next",
+ __func__));
+
+ idx2 = CAS_GET(word2, CAS_RC2_NEXT_INDEX);
+#ifdef CAS_DEBUG
+ CTR2(KTR_CAS, "%s: split at idx %d",
+ __func__, idx2);
+#endif
+ rxds2 = &sc->sc_rxdsoft[idx2];
+ MGET(m2, M_DONTWAIT, MT_DATA);
+ if (m2 != NULL) {
+ refcount_acquire(
+ &rxds2->rxds_refcount);
+ m2->m_len = len - m->m_len;
+ bus_dmamap_sync(sc->sc_rdmatag,
+ rxds2->rxds_dmamap,
+ BUS_DMASYNC_POSTREAD);
+ MEXTADD(m2, (caddr_t)rxds2->rxds_buf,
+ m2->m_len, cas_free,
+#if __FreeBSD_version < 800016
+ rxds2,
+#else
+ sc, (void *)(uintptr_t)idx2,
+#endif
+ M_RDONLY, EXT_NET_DRV);
+ if ((m2->m_flags & M_EXT) == 0) {
+ m_freem(m2);
+ m2 = NULL;
+ }
+ }
+ if (m2 != NULL)
+ m->m_next = m2;
+ else {
+ m_freem(m);
+ m = NULL;
+ }
+ }
+ if (m != NULL) {
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = len;
+ ifp->if_ipackets++;
+ if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
+ cas_rxcksum(m, CAS_GET(word4,
+ CAS_RC4_TCP_CSUM));
+ /* Pass it on. */
+ CAS_UNLOCK(sc);
+ (*ifp->if_input)(ifp, m);
+ CAS_LOCK(sc);
+ } else
+ ifp->if_ierrors++;
+
+ if ((word1 & CAS_RC1_RELEASE_DATA) != 0 &&
+ refcount_release(&rxds->rxds_refcount) != 0)
+ cas_add_rxdesc(sc, idx);
+ if ((word1 & CAS_RC1_SPLIT_PKT) != 0 &&
+ refcount_release(&rxds2->rxds_refcount) != 0)
+ cas_add_rxdesc(sc, idx2);
+ }
+
+ skip = CAS_GET(word1, CAS_RC1_SKIP);
+
+ skip:
+ cas_rxcompinit(&sc->sc_rxcomps[sc->sc_rxcptr]);
+ }
+ CAS_CDSYNC(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ CAS_WRITE_4(sc, CAS_RX_COMP_TAIL, sc->sc_rxcptr);
+
+#undef PRINTWORD
+#undef SKIPASSERT
+#undef WORDTOH
+
+#ifdef CAS_DEBUG
+ CTR4(KTR_CAS, "%s: done sc->sc_rxcptr %d, sc->sc_rxdptr %d, head %d",
+ __func__, sc->rxcptr, sc->sc_rxdptr,
+ CAS_READ_4(sc, CAS_RX_COMP_HEAD));
+#endif
+}
+
+static void
+cas_free(void *arg1, void *arg2)
+{
+ struct cas_rxdsoft *rxds;
+ struct cas_softc *sc;
+ u_int idx, locked;
+
+#if __FreeBSD_version < 800016
+ rxds = arg2;
+ sc = rxds->rxds_sc;
+ idx = rxds->rxds_idx;
+#else
+ sc = arg1;
+ idx = (uintptr_t)arg2;
+ rxds = &sc->sc_rxdsoft[idx];
+#endif
+ if (refcount_release(&rxds->rxds_refcount) == 0)
+ return;
+
+ /*
+ * NB: this function can be called via m_freem(9) within
+ * this driver!
+ */
+ if ((locked = CAS_LOCK_OWNED(sc)) == 0)
+ CAS_LOCK(sc);
+ cas_add_rxdesc(sc, idx);
+ if (locked == 0)
+ CAS_UNLOCK(sc);
+}
+
+static inline void
+cas_add_rxdesc(struct cas_softc *sc, u_int idx)
+{
+
+ CAS_LOCK_ASSERT(sc, MA_OWNED);
+
+ bus_dmamap_sync(sc->sc_rdmatag, sc->sc_rxdsoft[idx].rxds_dmamap,
+ BUS_DMASYNC_PREREAD);
+ CAS_UPDATE_RXDESC(sc, sc->sc_rxdptr, idx);
+ sc->sc_rxdptr = CAS_NEXTRXDESC(sc->sc_rxdptr);
+
+ /*
+ * Update the RX kick register. This register has to point to the
+ * descriptor after the last valid one (before the current batch)
+ * and for optimum performance should be incremented in multiples
+ * of 4 (the DMA engine fetches/updates descriptors in batches of 4).
+ */
+ if ((sc->sc_rxdptr % 4) == 0) {
+ CAS_CDSYNC(sc, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+ CAS_WRITE_4(sc, CAS_RX_KICK,
+ (sc->sc_rxdptr + CAS_NRXDESC - 4) & CAS_NRXDESC_MASK);
+ }
+}
+
+static void
+cas_eint(struct cas_softc *sc, u_int status)
+{
+
+ sc->sc_ifp->if_ierrors++;
+
+ device_printf(sc->sc_dev, "%s: status 0x%x", __func__, status);
+ if ((status & CAS_INTR_PCI_ERROR_INT) != 0) {
+ status = CAS_READ_4(sc, CAS_ERROR_STATUS);
+ printf(", PCI bus error 0x%x", status);
+ if ((status & CAS_ERROR_OTHER) != 0) {
+ status = pci_read_config(sc->sc_dev, PCIR_STATUS, 2);
+ printf(", PCI status 0x%x", status);
+ pci_write_config(sc->sc_dev, PCIR_STATUS, status, 2);
+ }
+ }
+ printf("\n");
+
+ cas_init_locked(sc);
+ cas_start_locked(sc->sc_ifp);
+}
+
+static void
+cas_intr(void *v)
+{
+ struct cas_softc *sc = v;
+ uint32_t status, status2;
+
+ status = CAS_READ_4(sc, CAS_STATUS);
+ if (__predict_false((status & CAS_INTR_SUMMARY) == 0))
+ return;
+
+ CAS_LOCK(sc);
+
+#ifdef CAS_DEBUG
+ CTR4(KTR_CAS, "%s: %s: cplt %x, status %x",
+ device_get_name(sc->sc_dev), __func__,
+ (status >> CAS_STATUS_TX_COMP3_SHIFT), (u_int)status);
+
+ /*
+ * PCS interrupts must be cleared, otherwise no traffic is passed!
+ */
+ if ((status & CAS_INTR_PCS_INT) != 0) {
+ status2 =
+ CAS_READ_4(sc, CAS_PCS_INTR_STATUS) |
+ CAS_READ_4(sc, CAS_PCS_INTR_STATUS);
+ if ((status2 & CAS_PCS_INTR_LINK) != 0)
+ device_printf(sc->sc_dev,
+ "%s: PCS link status changed\n", __func__);
+ }
+ if ((status & CAS_MAC_CTRL_STATUS) != 0) {
+ status2 = CAS_READ_4(sc, CAS_MAC_CTRL_STATUS);
+ if ((status2 & CAS_MAC_CTRL_PAUSE) != 0)
+ device_printf(sc->sc_dev,
+ "%s: PAUSE received (PAUSE time %d slots)\n",
+ __func__,
+ (status2 & CAS_MAC_CTRL_STATUS_PT_MASK) >>
+ CAS_MAC_CTRL_STATUS_PT_SHFT);
+ if ((status2 & CAS_MAC_CTRL_PAUSE) != 0)
+ device_printf(sc->sc_dev,
+ "%s: transited to PAUSE state\n", __func__);
+ if ((status2 & CAS_MAC_CTRL_NON_PAUSE) != 0)
+ device_printf(sc->sc_dev,
+ "%s: transited to non-PAUSE state\n", __func__);
+ }
+ if ((status & CAS_INTR_MIF) != 0)
+ device_printf(sc->sc_dev, "%s: MIF interrupt\n", __func__);
+#endif
+
+ if (__predict_false((status &
+ (CAS_INTR_TX_TAG_ERR | CAS_INTR_RX_TAG_ERR |
+ CAS_INTR_RX_LEN_MMATCH | CAS_INTR_PCI_ERROR_INT)) != 0)) {
+ cas_eint(sc, status);
+ CAS_UNLOCK(sc);
+ return;
+ }
+
+ if (__predict_false(status & CAS_INTR_TX_MAC_INT)) {
+ status2 = CAS_READ_4(sc, CAS_MAC_TX_STATUS);
+ if ((status2 &
+ (CAS_MAC_TX_UNDERRUN | CAS_MAC_TX_MAX_PKT_ERR)) != 0)
+ sc->sc_ifp->if_oerrors++;
+ else if ((status2 & ~CAS_MAC_TX_FRAME_XMTD) != 0)
+ device_printf(sc->sc_dev,
+ "MAC TX fault, status %x\n", status2);
+ }
+
+ if (__predict_false(status & CAS_INTR_RX_MAC_INT)) {
+ status2 = CAS_READ_4(sc, CAS_MAC_RX_STATUS);
+ if ((status2 & CAS_MAC_RX_OVERFLOW) != 0)
+ sc->sc_ifp->if_ierrors++;
+ else if ((status2 & ~CAS_MAC_RX_FRAME_RCVD) != 0)
+ device_printf(sc->sc_dev,
+ "MAC RX fault, status %x\n", status2);
+ }
+
+ if ((status &
+ (CAS_INTR_RX_DONE | CAS_INTR_RX_BUF_NA | CAS_INTR_RX_COMP_FULL |
+ CAS_INTR_RX_BUF_AEMPTY | CAS_INTR_RX_COMP_AFULL)) != 0) {
+ cas_rint(sc);
+ if (__predict_false((status &
+ (CAS_INTR_RX_BUF_NA | CAS_INTR_RX_COMP_FULL |
+ CAS_INTR_RX_BUF_AEMPTY | CAS_INTR_RX_COMP_AFULL)) != 0))
+ device_printf(sc->sc_dev,
+ "RX fault, status %x\n", status);
+ }
+
+ if ((status &
+ (CAS_INTR_TX_INT_ME | CAS_INTR_TX_ALL | CAS_INTR_TX_DONE)) != 0)
+ cas_tint(sc);
+
+ CAS_UNLOCK(sc);
+}
+
+static int
+cas_watchdog(struct cas_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+
+ CAS_LOCK_ASSERT(sc, MA_OWNED);
+
+#ifdef CAS_DEBUG
+ CTR4(KTR_CAS,
+ "%s: CAS_RX_CONFIG %x CAS_MAC_RX_STATUS %x CAS_MAC_RX_CONFIG %x",
+ __func__, CAS_READ_4(sc, CAS_RX_CONFIG),
+ CAS_READ_4(sc, CAS_MAC_RX_STATUS),
+ CAS_READ_4(sc, CAS_MAC_RX_CONFIG));
+ CTR4(KTR_CAS,
+ "%s: CAS_TX_CONFIG %x CAS_MAC_TX_STATUS %x CAS_MAC_TX_CONFIG %x",
+ __func__, CAS_READ_4(sc, CAS_TX_CONFIG),
+ CAS_READ_4(sc, CAS_MAC_TX_STATUS),
+ CAS_READ_4(sc, CAS_MAC_TX_CONFIG));
+#endif
+
+ if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0)
+ return (0);
+
+ if ((sc->sc_flags & CAS_LINK) != 0)
+ device_printf(sc->sc_dev, "device timeout\n");
+ else if (bootverbose)
+ device_printf(sc->sc_dev, "device timeout (no link)\n");
+ ++ifp->if_oerrors;
+
+ /* Try to get more packets going. */
+ cas_init_locked(sc);
+ cas_start_locked(ifp);
+ return (EJUSTRETURN);
+}
+
+static void
+cas_mifinit(struct cas_softc *sc)
+{
+
+ /* Configure the MIF in frame mode. */
+ CAS_WRITE_4(sc, CAS_MIF_CONF,
+ CAS_READ_4(sc, CAS_MIF_CONF) & ~CAS_MIF_CONF_BB_MODE);
+}
+
+/*
+ * MII interface
+ *
+ * The MII interface supports at least three different operating modes:
+ *
+ * Bitbang mode is implemented using data, clock and output enable registers.
+ *
+ * Frame mode is implemented by loading a complete frame into the frame
+ * register and polling the valid bit for completion.
+ *
+ * Polling mode uses the frame register but completion is indicated by
+ * an interrupt.
+ *
+ */
+static int
+cas_mii_readreg(device_t dev, int phy, int reg)
+{
+ struct cas_softc *sc;
+ int n;
+ uint32_t v;
+
+#ifdef CAS_DEBUG_PHY
+ printf("%s: phy %d reg %d\n", __func__, phy, reg);
+#endif
+
+ sc = device_get_softc(dev);
+ if (sc->sc_phyad != -1 && phy != sc->sc_phyad)
+ return (0);
+
+ if ((sc->sc_flags & CAS_SERDES) != 0) {
+ switch (reg) {
+ case MII_BMCR:
+ reg = CAS_PCS_CTRL;
+ break;
+ case MII_BMSR:
+ reg = CAS_PCS_STATUS;
+ break;
+ case MII_PHYIDR1:
+ case MII_PHYIDR2:
+ return (0);
+ case MII_ANAR:
+ reg = CAS_PCS_ANAR;
+ break;
+ case MII_ANLPAR:
+ reg = CAS_PCS_ANLPAR;
+ break;
+ case MII_EXTSR:
+ return (EXTSR_1000XFDX | EXTSR_1000XHDX);
+ default:
+ device_printf(sc->sc_dev,
+ "%s: unhandled register %d\n", __func__, reg);
+ return (0);
+ }
+ return (CAS_READ_4(sc, reg));
+ }
+
+ /* Construct the frame command. */
+ v = CAS_MIF_FRAME_READ |
+ (phy << CAS_MIF_FRAME_PHY_SHFT) |
+ (reg << CAS_MIF_FRAME_REG_SHFT);
+
+ CAS_WRITE_4(sc, CAS_MIF_FRAME, v);
+ CAS_BARRIER(sc, CAS_MIF_FRAME, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ for (n = 0; n < 100; n++) {
+ DELAY(1);
+ v = CAS_READ_4(sc, CAS_MIF_FRAME);
+ if (v & CAS_MIF_FRAME_TA_LSB)
+ return (v & CAS_MIF_FRAME_DATA);
+ }
+
+ device_printf(sc->sc_dev, "%s: timed out\n", __func__);
+ return (0);
+}
+
+static int
+cas_mii_writereg(device_t dev, int phy, int reg, int val)
+{
+ struct cas_softc *sc;
+ int n;
+ uint32_t v;
+
+#ifdef CAS_DEBUG_PHY
+ printf("%s: phy %d reg %d val %x\n", phy, reg, val, __func__);
+#endif
+
+ sc = device_get_softc(dev);
+ if (sc->sc_phyad != -1 && phy != sc->sc_phyad)
+ return (0);
+
+ if ((sc->sc_flags & CAS_SERDES) != 0) {
+ switch (reg) {
+ case MII_BMSR:
+ reg = CAS_PCS_STATUS;
+ break;
+ case MII_BMCR:
+ reg = CAS_PCS_CTRL;
+ if ((val & CAS_PCS_CTRL_RESET) == 0)
+ break;
+ CAS_WRITE_4(sc, CAS_PCS_CTRL, val);
+ CAS_BARRIER(sc, CAS_PCS_CTRL, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ if (!cas_bitwait(sc, CAS_PCS_CTRL,
+ CAS_PCS_CTRL_RESET, 0))
+ device_printf(sc->sc_dev,
+ "cannot reset PCS\n");
+ /* FALLTHROUGH */
+ case MII_ANAR:
+ CAS_WRITE_4(sc, CAS_PCS_CONF, 0);
+ CAS_BARRIER(sc, CAS_PCS_CONF, 4,
+ BUS_SPACE_BARRIER_WRITE);
+ CAS_WRITE_4(sc, CAS_PCS_ANAR, val);
+ CAS_WRITE_4(sc, CAS_PCS_SERDES_CTRL,
+ CAS_PCS_SERDES_CTRL_ESD);
+ CAS_WRITE_4(sc, CAS_PCS_CONF,
+ CAS_PCS_CONF_EN);
+ return (0);
+ case MII_ANLPAR:
+ reg = CAS_PCS_ANLPAR;
+ break;
+ default:
+ device_printf(sc->sc_dev,
+ "%s: unhandled register %d\n", __func__, reg);
+ return (0);
+ }
+ CAS_WRITE_4(sc, reg, val);
+ return (0);
+ }
+
+ /* Construct the frame command. */
+ v = CAS_MIF_FRAME_WRITE |
+ (phy << CAS_MIF_FRAME_PHY_SHFT) |
+ (reg << CAS_MIF_FRAME_REG_SHFT) |
+ (val & CAS_MIF_FRAME_DATA);
+
+ CAS_WRITE_4(sc, CAS_MIF_FRAME, v);
+ CAS_BARRIER(sc, CAS_MIF_FRAME, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ for (n = 0; n < 100; n++) {
+ DELAY(1);
+ v = CAS_READ_4(sc, CAS_MIF_FRAME);
+ if (v & CAS_MIF_FRAME_TA_LSB)
+ return (1);
+ }
+
+ device_printf(sc->sc_dev, "%s: timed out\n", __func__);
+ return (0);
+}
+
+static void
+cas_mii_statchg(device_t dev)
+{
+ struct cas_softc *sc;
+ struct ifnet *ifp;
+ int gigabit;
+ uint32_t rxcfg, txcfg, v;
+
+ sc = device_get_softc(dev);
+ ifp = sc->sc_ifp;
+
+ CAS_LOCK_ASSERT(sc, MA_OWNED);
+
+#ifdef CAS_DEBUG
+ if ((ifp->if_flags & IFF_DEBUG) != 0)
+ device_printf(sc->sc_dev, "%s: status change: PHY = %d\n",
+ __func__, sc->sc_phyad);
+#endif
+
+ if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) != 0 &&
+ IFM_SUBTYPE(sc->sc_mii->mii_media_active) != IFM_NONE)
+ sc->sc_flags |= CAS_LINK;
+ else
+ sc->sc_flags &= ~CAS_LINK;
+
+ switch (IFM_SUBTYPE(sc->sc_mii->mii_media_active)) {
+ case IFM_1000_SX:
+ case IFM_1000_LX:
+ case IFM_1000_CX:
+ case IFM_1000_T:
+ gigabit = 1;
+ break;
+ default:
+ gigabit = 0;
+ }
+
+ /*
+ * The configuration done here corresponds to the steps F) and
+ * G) and as far as enabling of RX and TX MAC goes also step H)
+ * of the initialization sequence outlined in section 11.2.1 of
+ * the Cassini+ ASIC Specification.
+ */
+
+ rxcfg = CAS_READ_4(sc, CAS_MAC_RX_CONF);
+ rxcfg &= ~(CAS_MAC_RX_CONF_EN | CAS_MAC_RX_CONF_CARR);
+ txcfg = CAS_MAC_TX_CONF_EN_IPG0 | CAS_MAC_TX_CONF_NGU |
+ CAS_MAC_TX_CONF_NGUL;
+ if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) != 0)
+ txcfg |= CAS_MAC_TX_CONF_ICARR | CAS_MAC_TX_CONF_ICOLLIS;
+ else if (gigabit != 0) {
+ rxcfg |= CAS_MAC_RX_CONF_CARR;
+ txcfg |= CAS_MAC_TX_CONF_CARR;
+ }
+ CAS_WRITE_4(sc, CAS_MAC_TX_CONF, 0);
+ CAS_BARRIER(sc, CAS_MAC_TX_CONF, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ if (!cas_bitwait(sc, CAS_MAC_TX_CONF, CAS_MAC_TX_CONF_EN, 0))
+ device_printf(sc->sc_dev, "cannot disable TX MAC\n");
+ CAS_WRITE_4(sc, CAS_MAC_TX_CONF, txcfg);
+ CAS_WRITE_4(sc, CAS_MAC_RX_CONF, 0);
+ CAS_BARRIER(sc, CAS_MAC_RX_CONF, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ if (!cas_bitwait(sc, CAS_MAC_RX_CONF, CAS_MAC_RX_CONF_EN, 0))
+ device_printf(sc->sc_dev, "cannot disable RX MAC\n");
+ CAS_WRITE_4(sc, CAS_MAC_RX_CONF, rxcfg);
+
+ v = CAS_READ_4(sc, CAS_MAC_CTRL_CONF) &
+ ~(CAS_MAC_CTRL_CONF_TXP | CAS_MAC_CTRL_CONF_RXP);
+#ifdef notyet
+ if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) &
+ IFM_ETH_RXPAUSE) != 0)
+ v |= CAS_MAC_CTRL_CONF_RXP;
+ if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) &
+ IFM_ETH_TXPAUSE) != 0)
+ v |= CAS_MAC_CTRL_CONF_TXP;
+#endif
+ CAS_WRITE_4(sc, CAS_MAC_CTRL_CONF, v);
+
+ /*
+ * All supported chips have a bug causing incorrect checksum
+ * to be calculated when letting them strip the FCS in half-
+ * duplex mode. In theory we could disable FCS stripping and
+ * manually adjust the checksum accordingly. It seems to make
+ * more sense to optimze for the common case and just disable
+ * hardware checksumming in half-duplex mode though.
+ */
+ if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) == 0) {
+ ifp->if_capenable &= ~IFCAP_HWCSUM;
+ ifp->if_hwassist = 0;
+ } else if ((sc->sc_flags & CAS_NO_CSUM) == 0) {
+ ifp->if_capenable = ifp->if_capabilities;
+ ifp->if_hwassist = CAS_CSUM_FEATURES;
+ }
+
+ if (sc->sc_variant == CAS_SATURN) {
+ if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) == 0)
+ /* silicon bug workaround */
+ CAS_WRITE_4(sc, CAS_MAC_PREAMBLE_LEN, 0x41);
+ else
+ CAS_WRITE_4(sc, CAS_MAC_PREAMBLE_LEN, 0x7);
+ }
+
+ if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) == 0 &&
+ gigabit != 0)
+ CAS_WRITE_4(sc, CAS_MAC_SLOT_TIME,
+ CAS_MAC_SLOT_TIME_CARR);
+ else
+ CAS_WRITE_4(sc, CAS_MAC_SLOT_TIME,
+ CAS_MAC_SLOT_TIME_NORM);
+
+ /* XIF Configuration */
+ v = CAS_MAC_XIF_CONF_TX_OE | CAS_MAC_XIF_CONF_LNKLED;
+ if ((sc->sc_flags & CAS_SERDES) == 0) {
+ if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) == 0)
+ v |= CAS_MAC_XIF_CONF_NOECHO;
+ v |= CAS_MAC_XIF_CONF_BUF_OE;
+ }
+ if (gigabit != 0)
+ v |= CAS_MAC_XIF_CONF_GMII;
+ if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) & IFM_FDX) != 0)
+ v |= CAS_MAC_XIF_CONF_FDXLED;
+ CAS_WRITE_4(sc, CAS_MAC_XIF_CONF, v);
+
+ if ((sc->sc_ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
+ (sc->sc_flags & CAS_LINK) != 0) {
+ CAS_WRITE_4(sc, CAS_MAC_TX_CONF,
+ txcfg | CAS_MAC_TX_CONF_EN);
+ CAS_WRITE_4(sc, CAS_MAC_RX_CONF,
+ rxcfg | CAS_MAC_RX_CONF_EN);
+ }
+}
+
+static int
+cas_mediachange(struct ifnet *ifp)
+{
+ struct cas_softc *sc = ifp->if_softc;
+ int error;
+
+ /* XXX add support for serial media. */
+
+ CAS_LOCK(sc);
+ error = mii_mediachg(sc->sc_mii);
+ CAS_UNLOCK(sc);
+ return (error);
+}
+
+static void
+cas_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct cas_softc *sc = ifp->if_softc;
+
+ CAS_LOCK(sc);
+ if ((ifp->if_flags & IFF_UP) == 0) {
+ CAS_UNLOCK(sc);
+ return;
+ }
+
+ mii_pollstat(sc->sc_mii);
+ ifmr->ifm_active = sc->sc_mii->mii_media_active;
+ ifmr->ifm_status = sc->sc_mii->mii_media_status;
+ CAS_UNLOCK(sc);
+}
+
+static int
+cas_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct cas_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int error;
+
+ error = 0;
+ switch (cmd) {
+ case SIOCSIFFLAGS:
+ CAS_LOCK(sc);
+ if ((ifp->if_flags & IFF_UP) != 0) {
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
+ ((ifp->if_flags ^ sc->sc_ifflags) &
+ (IFF_ALLMULTI | IFF_PROMISC)) != 0)
+ cas_setladrf(sc);
+ else
+ cas_init_locked(sc);
+ } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
+ cas_stop(ifp);
+ sc->sc_ifflags = ifp->if_flags;
+ CAS_UNLOCK(sc);
+ break;
+ case SIOCSIFCAP:
+ CAS_LOCK(sc);
+ if ((sc->sc_flags & CAS_NO_CSUM) != 0) {
+ error = EINVAL;
+ CAS_UNLOCK(sc);
+ break;
+ }
+ ifp->if_capenable = ifr->ifr_reqcap;
+ if ((ifp->if_capenable & IFCAP_TXCSUM) != 0)
+ ifp->if_hwassist = CAS_CSUM_FEATURES;
+ else
+ ifp->if_hwassist = 0;
+ CAS_UNLOCK(sc);
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ CAS_LOCK(sc);
+ cas_setladrf(sc);
+ CAS_UNLOCK(sc);
+ break;
+ case SIOCSIFMTU:
+ if ((ifr->ifr_mtu < ETHERMIN) ||
+ (ifr->ifr_mtu > ETHERMTU_JUMBO))
+ error = EINVAL;
+ else
+ ifp->if_mtu = ifr->ifr_mtu;
+ break;
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media, cmd);
+ break;
+ default:
+ error = ether_ioctl(ifp, cmd, data);
+ break;
+ }
+
+ return (error);
+}
+
+static void
+cas_setladrf(struct cas_softc *sc)
+{
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ifmultiaddr *inm;
+ int i;
+ uint32_t hash[16];
+ uint32_t crc, v;
+
+ CAS_LOCK_ASSERT(sc, MA_OWNED);
+
+ /* Get the current RX configuration. */
+ v = CAS_READ_4(sc, CAS_MAC_RX_CONF);
+
+ /*
+ * Turn off promiscuous mode, promiscuous group mode (all multicast),
+ * and hash filter. Depending on the case, the right bit will be
+ * enabled.
+ */
+ v &= ~(CAS_MAC_RX_CONF_PROMISC | CAS_MAC_RX_CONF_HFILTER |
+ CAS_MAC_RX_CONF_PGRP);
+
+ CAS_WRITE_4(sc, CAS_MAC_RX_CONF, v);
+ CAS_BARRIER(sc, CAS_MAC_RX_CONF, 4,
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
+ if (!cas_bitwait(sc, CAS_MAC_RX_CONF, CAS_MAC_RX_CONF_HFILTER, 0))
+ device_printf(sc->sc_dev, "cannot disable RX hash filter\n");
+
+ if ((ifp->if_flags & IFF_PROMISC) != 0) {
+ v |= CAS_MAC_RX_CONF_PROMISC;
+ goto chipit;
+ }
+ if ((ifp->if_flags & IFF_ALLMULTI) != 0) {
+ v |= CAS_MAC_RX_CONF_PGRP;
+ goto chipit;
+ }
+
+ /*
+ * Set up multicast address filter by passing all multicast
+ * addresses through a crc generator, and then using the high
+ * order 8 bits as an index into the 256 bit logical address
+ * filter. The high order 4 bits selects the word, while the
+ * other 4 bits select the bit within the word (where bit 0
+ * is the MSB).
+ */
+
+ /* Clear the hash table. */
+ memset(hash, 0, sizeof(hash));
+
+ IF_ADDR_LOCK(ifp);
+ TAILQ_FOREACH(inm, &ifp->if_multiaddrs, ifma_link) {
+ if (inm->ifma_addr->sa_family != AF_LINK)
+ continue;
+ crc = ether_crc32_le(LLADDR((struct sockaddr_dl *)
+ inm->ifma_addr), ETHER_ADDR_LEN);
+
+ /* We just want the 8 most significant bits. */
+ crc >>= 24;
+
+ /* Set the corresponding bit in the filter. */
+ hash[crc >> 4] |= 1 << (15 - (crc & 15));
+ }
+ IF_ADDR_UNLOCK(ifp);
+
+ v |= CAS_MAC_RX_CONF_HFILTER;
+
+ /* Now load the hash table into the chip (if we are using it). */
+ for (i = 0; i < 16; i++)
+ CAS_WRITE_4(sc,
+ CAS_MAC_HASH0 + i * (CAS_MAC_HASH1 - CAS_MAC_HASH0),
+ hash[i]);
+
+ chipit:
+ CAS_WRITE_4(sc, CAS_MAC_RX_CONF, v);
+}
+
+static int cas_pci_attach(device_t dev);
+static int cas_pci_detach(device_t dev);
+static int cas_pci_probe(device_t dev);
+static int cas_pci_resume(device_t dev);
+static int cas_pci_suspend(device_t dev);
+
+static device_method_t cas_pci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, cas_pci_probe),
+ DEVMETHOD(device_attach, cas_pci_attach),
+ DEVMETHOD(device_detach, cas_pci_detach),
+ DEVMETHOD(device_suspend, cas_pci_suspend),
+ DEVMETHOD(device_resume, cas_pci_resume),
+ /* Use the suspend handler here, it is all that is required. */
+ DEVMETHOD(device_shutdown, cas_pci_suspend),
+
+ /* bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+ DEVMETHOD(bus_driver_added, bus_generic_driver_added),
+
+ /* MII interface */
+ DEVMETHOD(miibus_readreg, cas_mii_readreg),
+ DEVMETHOD(miibus_writereg, cas_mii_writereg),
+ DEVMETHOD(miibus_statchg, cas_mii_statchg),
+
+ KOBJMETHOD_END
+};
+
+static driver_t cas_pci_driver = {
+ "cas",
+ cas_pci_methods,
+ sizeof(struct cas_softc)
+};
+
+DRIVER_MODULE(cas, pci, cas_pci_driver, cas_devclass, 0, 0);
+DRIVER_MODULE(miibus, cas, miibus_driver, miibus_devclass, 0, 0);
+MODULE_DEPEND(cas, pci, 1, 1, 1);
+
+static const struct cas_pci_dev {
+ uint32_t cpd_devid;
+ uint8_t cpd_revid;
+ int cpd_variant;
+ const char *cpd_desc;
+} const cas_pci_devlist[] = {
+ { 0x0035100b, 0x0, CAS_SATURN, "NS DP83065 Saturn Gigabit Ethernet" },
+ { 0xabba108e, 0x10, CAS_CASPLUS, "Sun Cassini+ Gigabit Ethernet" },
+ { 0xabba108e, 0x0, CAS_CAS, "Sun Cassini Gigabit Ethernet" },
+ { 0, 0, 0, NULL }
+};
+
+static int
+cas_pci_probe(device_t dev)
+{
+ int i;
+
+ for (i = 0; cas_pci_devlist[i].cpd_desc != NULL; i++) {
+ if (pci_get_devid(dev) == cas_pci_devlist[i].cpd_devid &&
+ pci_get_revid(dev) >= cas_pci_devlist[i].cpd_revid) {
+ device_set_desc(dev, cas_pci_devlist[i].cpd_desc);
+ return (BUS_PROBE_DEFAULT);
+ }
+ }
+
+ return (ENXIO);
+}
+
+static struct resource_spec cas_pci_res_spec[] = {
+ { SYS_RES_IRQ, 0, RF_SHAREABLE | RF_ACTIVE }, /* CAS_RES_INTR */
+ { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, /* CAS_RES_MEM */
+ { -1, 0 }
+};
+
+static int
+cas_pci_attach(device_t dev)
+{
+ struct cas_softc *sc;
+ int i;
+#if !(defined(__powerpc__) || defined(__sparc64__))
+ u_char enaddr[4][ETHER_ADDR_LEN];
+ char lma[sizeof("local-mac-address")];
+ int found, j;
+#endif
+
+ sc = device_get_softc(dev);
+ sc->sc_variant = CAS_UNKNOWN;
+ for (i = 0; cas_pci_devlist[i].cpd_desc != NULL; i++) {
+ if (pci_get_devid(dev) == cas_pci_devlist[i].cpd_devid &&
+ pci_get_revid(dev) >= cas_pci_devlist[i].cpd_revid) {
+ sc->sc_variant = cas_pci_devlist[i].cpd_variant;
+ break;
+ }
+ }
+ if (sc->sc_variant == CAS_UNKNOWN) {
+ device_printf(dev, "unknown adaptor\n");
+ return (ENXIO);
+ }
+
+ pci_enable_busmaster(dev);
+
+ sc->sc_dev = dev;
+ if (sc->sc_variant == CAS_CAS && pci_get_devid(dev) < 0x02)
+ /* Hardware checksumming may hang TX. */
+ sc->sc_flags |= CAS_NO_CSUM;
+ if (sc->sc_variant == CAS_CASPLUS || sc->sc_variant == CAS_SATURN)
+ sc->sc_flags |= CAS_REG_PLUS;
+ if (sc->sc_variant == CAS_CAS ||
+ (sc->sc_variant == CAS_CASPLUS && pci_get_revid(dev) < 0x11))
+ sc->sc_flags |= CAS_TABORT;
+ if (bootverbose)
+ device_printf(dev, "flags=0x%x\n", sc->sc_flags);
+
+ if (bus_alloc_resources(dev, cas_pci_res_spec, sc->sc_res)) {
+ device_printf(dev, "failed to allocate resources\n");
+ bus_release_resources(dev, cas_pci_res_spec, sc->sc_res);
+ return (ENXIO);
+ }
+
+ CAS_LOCK_INIT(sc, device_get_nameunit(dev));
+
+#if defined(__powerpc__) || defined(__sparc64__)
+ OF_getetheraddr(dev, sc->sc_enaddr);
+#else
+ /*
+ * Dig out VPD (vital product data) and read the MAX address.
+ * The VPD resides in the PCI Expansion ROM (PCI FCode) and
+ * can't be accessed via the PCI capability pointer.
+ * SUNW,pci-ce and SUNW,pci-qge use the Enhanced VPD format
+ * described in US Patent 7149820.
+ */
+
+#define PCI_ROMHDR_SIZE 0x1c
+#define PCI_ROMHDR_SIG 0x00
+#define PCI_ROMHDR_SIG_MAGIC 0xaa55 /* little endian */
+#define PCI_ROMHDR_PTR_DATA 0x18
+#define PCI_ROM_SIZE 0x18
+#define PCI_ROM_SIG 0x00
+#define PCI_ROM_SIG_MAGIC 0x52494350 /* "PCIR", endian */
+ /* reversed */
+#define PCI_ROM_VENDOR 0x04
+#define PCI_ROM_DEVICE 0x06
+#define PCI_ROM_PTR_VPD 0x08
+#define PCI_VPDRES_BYTE0 0x00
+#define PCI_VPDRES_ISLARGE(x) ((x) & 0x80)
+#define PCI_VPDRES_LARGE_NAME(x) ((x) & 0x7f)
+#define PCI_VPDRES_LARGE_LEN_LSB 0x01
+#define PCI_VPDRES_LARGE_LEN_MSB 0x02
+#define PCI_VPDRES_LARGE_SIZE 0x03
+#define PCI_VPDRES_TYPE_ID_STRING 0x02 /* large */
+#define PCI_VPDRES_TYPE_VPD 0x10 /* large */
+#define PCI_VPD_KEY0 0x00
+#define PCI_VPD_KEY1 0x01
+#define PCI_VPD_LEN 0x02
+#define PCI_VPD_SIZE 0x03
+
+#define CAS_ROM_READ_1(sc, offs) \
+ CAS_READ_1((sc), CAS_PCI_ROM_OFFSET + (offs))
+#define CAS_ROM_READ_2(sc, offs) \
+ CAS_READ_2((sc), CAS_PCI_ROM_OFFSET + (offs))
+#define CAS_ROM_READ_4(sc, offs) \
+ CAS_READ_4((sc), CAS_PCI_ROM_OFFSET + (offs))
+
+ found = 0;
+ /* Enable PCI Expansion ROM access. */
+ CAS_WRITE_4(sc, CAS_BIM_LDEV_OEN,
+ CAS_BIM_LDEV_OEN_PAD | CAS_BIM_LDEV_OEN_PROM);
+
+ /* Read PCI Expansion ROM header. */
+ if (CAS_ROM_READ_2(sc, PCI_ROMHDR_SIG) != PCI_ROMHDR_SIG_MAGIC ||
+ (i = CAS_ROM_READ_2(sc, PCI_ROMHDR_PTR_DATA)) <
+ PCI_ROMHDR_SIZE) {
+ device_printf(dev, "unexpected PCI Expansion ROM header\n");
+ goto fail_prom;
+ }
+
+ /* Read PCI Expansion ROM data. */
+ if (CAS_ROM_READ_4(sc, i + PCI_ROM_SIG) != PCI_ROM_SIG_MAGIC ||
+ CAS_ROM_READ_2(sc, i + PCI_ROM_VENDOR) != pci_get_vendor(dev) ||
+ CAS_ROM_READ_2(sc, i + PCI_ROM_DEVICE) != pci_get_device(dev) ||
+ (j = CAS_ROM_READ_2(sc, i + PCI_ROM_PTR_VPD)) <
+ i + PCI_ROM_SIZE) {
+ device_printf(dev, "unexpected PCI Expansion ROM data\n");
+ goto fail_prom;
+ }
+
+ /* Read PCI VPD. */
+ next:
+ if (PCI_VPDRES_ISLARGE(CAS_ROM_READ_1(sc,
+ j + PCI_VPDRES_BYTE0)) == 0) {
+ device_printf(dev, "no large PCI VPD\n");
+ goto fail_prom;
+ }
+
+ i = (CAS_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_LEN_MSB) << 8) |
+ CAS_ROM_READ_1(sc, j + PCI_VPDRES_LARGE_LEN_LSB);
+ switch (PCI_VPDRES_LARGE_NAME(CAS_ROM_READ_1(sc,
+ j + PCI_VPDRES_BYTE0))) {
+ case PCI_VPDRES_TYPE_ID_STRING:
+ /* Skip identifier string. */
+ j += PCI_VPDRES_LARGE_SIZE + i;
+ goto next;
+ case PCI_VPDRES_TYPE_VPD:
+ for (j += PCI_VPDRES_LARGE_SIZE; i > 0;
+ i -= PCI_VPD_SIZE + CAS_ROM_READ_1(sc, j + PCI_VPD_LEN),
+ j += PCI_VPD_SIZE + CAS_ROM_READ_1(sc, j + PCI_VPD_LEN)) {
+ if (CAS_ROM_READ_1(sc, j + PCI_VPD_KEY0) != 'Z')
+ /* no Enhanced VPD */
+ continue;
+ if (CAS_ROM_READ_1(sc, j + PCI_VPD_SIZE) != 'I')
+ /* no instance property */
+ continue;
+ if (CAS_ROM_READ_1(sc, j + PCI_VPD_SIZE + 3) != 'B')
+ /* no byte array */
+ continue;
+ if (CAS_ROM_READ_1(sc, j + PCI_VPD_SIZE + 4) !=
+ ETHER_ADDR_LEN)
+ continue;
+ bus_read_region_1(sc->sc_res[CAS_RES_MEM],
+ CAS_PCI_ROM_OFFSET + j + PCI_VPD_SIZE + 5,
+ lma, sizeof(lma));
+ if (strcmp(lma, "local-mac-address") != 0)
+ continue;
+ bus_read_region_1(sc->sc_res[CAS_RES_MEM],
+ CAS_PCI_ROM_OFFSET + j + PCI_VPD_SIZE + 5 +
+ sizeof(lma), enaddr[found],
+ sizeof(enaddr[found]));
+ if (found++ == 4)
+ break;
+ }
+ break;
+ default:
+ device_printf(dev, "unexpected PCI VPD\n");
+ goto fail_prom;
+ }
+
+ fail_prom:
+ CAS_WRITE_4(sc, CAS_BIM_LDEV_OEN, 0);
+
+ if (found == 0) {
+ device_printf(dev, "could not determine Ethernet address\n");
+ goto fail;
+ }
+ i = 0;
+ if (found > 1 && pci_get_slot(dev) < sizeof(enaddr) / sizeof(*enaddr))
+ i = pci_get_slot(dev);
+ memcpy(sc->sc_enaddr, enaddr[i], ETHER_ADDR_LEN);
+#endif
+
+ if (cas_attach(sc) != 0) {
+ device_printf(dev, "could not be attached\n");
+ goto fail;
+ }
+
+ if (bus_setup_intr(dev, sc->sc_res[CAS_RES_INTR], INTR_TYPE_NET |
+ INTR_MPSAFE, NULL, cas_intr, sc, &sc->sc_ih) != 0) {
+ device_printf(dev, "failed to set up interrupt\n");
+ cas_detach(sc);
+ goto fail;
+ }
+ return (0);
+
+ fail:
+ CAS_LOCK_DESTROY(sc);
+ bus_release_resources(dev, cas_pci_res_spec, sc->sc_res);
+ return (ENXIO);
+}
+
+static int
+cas_pci_detach(device_t dev)
+{
+ struct cas_softc *sc;
+
+ sc = device_get_softc(dev);
+ bus_teardown_intr(dev, sc->sc_res[CAS_RES_INTR], sc->sc_ih);
+ cas_detach(sc);
+ CAS_LOCK_DESTROY(sc);
+ bus_release_resources(dev, cas_pci_res_spec, sc->sc_res);
+ return (0);
+}
+
+static int
+cas_pci_suspend(device_t dev)
+{
+
+ cas_suspend(device_get_softc(dev));
+ return (0);
+}
+
+static int
+cas_pci_resume(device_t dev)
+{
+
+ cas_resume(device_get_softc(dev));
+ return (0);
+}
diff --git a/sys/dev/cas/if_casreg.h b/sys/dev/cas/if_casreg.h
new file mode 100644
index 0000000..97250e0
--- /dev/null
+++ b/sys/dev/cas/if_casreg.h
@@ -0,0 +1,1002 @@
+/*-
+ * Copyright (C) 2001 Eduardo Horvath.
+ * Copyright (c) 2008 Marius Strobl <marius@FreeBSD.org>
+ * 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.
+ *
+ * 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.
+ *
+ * from: NetBSD: gemreg.h,v 1.8 2005/12/11 12:21:26 christos Exp
+ * from: FreeBSD: if_gemreg.h 174987 2007-12-30 01:32:03Z marius
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IF_CASREG_H
+#define _IF_CASREG_H
+
+/*
+ * register definitions for Sun Cassini/Cassini+ and National Semiconductor
+ * DP83065 Saturn Gigabit Ethernet controllers
+ */
+
+/* global resources */
+#define CAS_CAW 0x0004 /* core arbitration weight */
+#define CAS_INF_BURST 0x0008 /* infinite burst enable */
+#define CAS_STATUS 0x000c /* interrupt status */
+#define CAS_INTMASK 0x0010 /* interrupt mask */
+#define CAS_CLEAR_ALIAS 0x0014 /* clear mask alias */
+#define CAS_STATUS_ALIAS 0x001c /* interrupt status alias */
+#define CAS_ERROR_STATUS 0x1000 /* PCI error status */
+#define CAS_ERROR_MASK 0x1004 /* PCI error mask */
+#define CAS_BIM_CONF 0x1008 /* BIM configuration */
+#define CAS_BIM_DIAG 0x100c /* BIM diagnostic */
+#define CAS_RESET 0x1010 /* software reset */
+#define CAS_BIM_LDEV_OEN 0x1020 /* BIM local device output enable */
+#define CAS_BIM_BUF_ADDR 0x1024 /* BIM buffer address */
+#define CAS_BIM_BUF_DATA_LO 0x1028 /* BIM buffer data low */
+#define CAS_BIM_BUF_DATA_HI 0x102c /* BIM buffer data high */
+#define CAS_BIM_RAM_BIST 0x1030 /* BIM RAM BIST control/status */
+#define CAS_PROBE_MUX_SELECT 0x1034 /* PROBE MUX SELECT */
+#define CAS_INTMASK2 0x1038 /* interrupt mask 2 for INTB */
+#define CAS_STATUS2 0x103c /* interrupt status 2 for INTB */
+#define CAS_CLEAR_ALIAS2 0x1040 /* clear mask alias 2 for INTB */
+#define CAS_STATUS_ALIAS2 0x1044 /* interrupt status alias 2 for INTB */
+#define CAS_INTMASK3 0x1048 /* interrupt mask 3 for INTC */
+#define CAS_STATUS3 0x104c /* interrupt status 3 for INTC */
+#define CAS_CLEAR_ALIAS3 0x1050 /* clear mask alias 3 for INTC */
+#define CAS_STATUS_ALIAS3 0x1054 /* interrupt status alias 3 for INTC */
+#define CAS_INTMASK4 0x1058 /* interrupt mask 4 for INTD */
+#define CAS_STATUS4 0x105c /* interrupt status 4 for INTD */
+#define CAS_CLEAR_ALIAS4 0x1060 /* clear mask alias 4 for INTD */
+#define CAS_STATUS_ALIAS4 0x1064 /* interrupt status alias 4 for INTD */
+
+#define CAS_CAW_RX_WGHT_MASK 0x00000003 /* RX DMA factor for... */
+#define CAS_CAW_RX_WGHT_SHFT 0 /* ...weighted round robin */
+#define CAS_CAW_TX_WGHT_MASK 0x0000000c /* RX DMA factor for... */
+#define CAS_CAW_TX_WGHT_SHFT 2 /* ...weighted round robin */
+#define CAS_CAW_RR_DIS 0x00000010 /* weighted round robin dis. */
+
+#define CAS_INF_BURST_EN 0x00000001 /* Allow bursts > cachline. */
+
+/*
+ * shared interrupt bits for CAS_STATUS, CAS_INTMASK, CAS_CLEAR_ALIAS and
+ * CAS_STATUS_ALIAS
+ * Bits 0-9 of CAS_STATUS auto-clear when read. CAS_CLEAR_ALIAS specifies
+ * which of bits 0-9 auto-clear when reading CAS_STATUS_ALIAS.
+ */
+#define CAS_INTR_TX_INT_ME 0x00000001 /* Frame w/ INT_ME set sent. */
+#define CAS_INTR_TX_ALL 0x00000002 /* TX frames trans. to FIFO. */
+#define CAS_INTR_TX_DONE 0x00000004 /* Any TX frame transferred. */
+#define CAS_INTR_TX_TAG_ERR 0x00000008 /* TX FIFO tag corrupted. */
+#define CAS_INTR_RX_DONE 0x00000010 /* >=1 RX frames transferred. */
+#define CAS_INTR_RX_BUF_NA 0x00000020 /* RX buffer not available */
+#define CAS_INTR_RX_TAG_ERR 0x00000040 /* RX FIFO tag corrupted. */
+#define CAS_INTR_RX_COMP_FULL 0x00000080 /* RX completion ring full */
+#define CAS_INTR_RX_BUF_AEMPTY 0x00000100 /* RX desc. ring almost empty */
+#define CAS_INTR_RX_COMP_AFULL 0x00000200 /* RX cmpl. ring almost full */
+#define CAS_INTR_RX_LEN_MMATCH 0x00000400 /* length field mismatch */
+#define CAS_INTR_SUMMARY 0x00001000 /* summary interrupt bit */
+#define CAS_INTR_PCS_INT 0x00002000 /* PCS interrupt */
+#define CAS_INTR_TX_MAC_INT 0x00004000 /* TX MAC interrupt */
+#define CAS_INTR_RX_MAC_INT 0x00008000 /* RX MAC interrupt */
+#define CAS_INTR_MAC_CTRL_INT 0x00010000 /* MAC control interrupt */
+#define CAS_INTR_MIF 0x00020000 /* MIF interrupt */
+#define CAS_INTR_PCI_ERROR_INT 0x00040000 /* PCI error interrupt */
+
+#define CAS_STATUS_TX_COMP3_MASK 0xfff80000 /* TX completion 3 */
+#define CAS_STATUS_TX_COMP3_SHFT 19
+
+/* CAS_ERROR_STATUS and CAS_ERROR_MASK PCI error bits */
+#define CAS_ERROR_DTRTO 0x00000002 /* delayed trans. timeout */
+#define CAS_ERROR_OTHER 0x00000004 /* errors (see PCIR_STATUS) */
+#define CAS_ERROR_DMAW_ZERO 0x00000008 /* zero count DMA write */
+#define CAS_ERROR_DMAR_ZERO 0x00000010 /* zero count DMA read */
+#define CAS_ERROR_RTRTO 0x00000020 /* 255 retries exceeded */
+
+#define CAS_BIM_CONF_BD64_DIS 0x00000004 /* 64-bit mode disable */
+#define CAS_BIM_CONF_M66EN 0x00000008 /* PCI clock is 66MHz (ro). */
+#define CAS_BIM_CONF_BUS32_WIDE 0x00000010 /* PCI bus is 32-bit (ro). */
+#define CAS_BIM_CONF_DPAR_EN 0x00000020 /* parity error intr. enable */
+#define CAS_BIM_CONF_RMA_EN 0x00000040 /* master abort intr. enable */
+#define CAS_BIM_CONF_RTA_EN 0x00000080 /* target abort intr. enable */
+#define CAS_BIM_CONF_DIS_BIM 0x00000200 /* Stop PCI DMA transactions. */
+#define CAS_BIM_CONF_BIM_DIS 0x00000400 /* BIM was stopped (ro). */
+#define CAS_BIM_CONF_BLOCK_PERR 0x00000800 /* Block PERR# to PCI bus. */
+
+#define CAS_BIM_DIAG_BRST_SM 0x0000007f /* burst ctrl. state machine */
+#define CAS_BIM_DIAG_MSTR_SM 0x3fffff00
+
+#define CAS_RESET_TX 0x00000001 /* Reset TX DMA engine. */
+#define CAS_RESET_RX 0x00000002 /* Reset RX DMA engine. */
+#define CAS_RESET_RSTOUT 0x00000004 /* Force PCI RSTOUT#. */
+#define CAS_RESET_PCS_DIS 0x00000008 /* PCS reset disable */
+#define CAS_RESET_BREQ_SM 0x00007f00 /* breq state machine */
+#define CAS_RESET_PCIARB 0x00070000 /* PCI arbitration state */
+#define CAS_RESET_RDPCI 0x00300000 /* read PCI state */
+#define CAS_RESET_RDARB 0x00c00000 /* read arbitration state */
+#define CAS_RESET_WRPCI 0x06000000 /* write PCI state */
+#define CAS_RESET_WRARB 0x38000000 /* write arbitration state */
+
+#define CAS_BIM_LDEV_OEN_PAD 0x00000001 /* addr. bus, RW and OE */
+#define CAS_BIM_LDEV_OEN_PROM 0x00000002 /* PROM chip select */
+#define CAS_BIM_LDEV_OEN_EXT 0x00000004 /* secondary local bus device */
+#define CAS_BIM_LDEV_OEN_SOFT_0 0x00000008 /* soft. progr. ctrl. bit 0 */
+#define CAS_BIM_LDEV_OEN_SOFT_1 0x00000010 /* soft. progr. ctrl. bit 1 */
+#define CAS_BIM_LDEV_OEN_HWRST 0x00000020 /* hw. reset (Cassini+ only) */
+
+#define CAS_BIM_BUF_ADDR_INDEX 0x0000003f /* buffer entry index */
+#define CAS_BIM_BUF_ADDR_RDWR 0x00000040 /* 0: read, 1: write access */
+
+#define CAS_BIM_RAM_BIST_START 0x00000001 /* Start BIST on read buffer. */
+#define CAS_BIM_RAM_BIST_SUM 0x00000004 /* read buffer pass summary */
+#define CAS_BIM_RAM_BIST_LO 0x00000010 /* read buf. low bank passes */
+#define CAS_BIM_RAM_BIST_HI 0x00000020 /* read buf. high bank passes */
+
+#define CAS_PROBE_MUX_SELECT_LO 0x0000000f /* P_A[7:0] */
+#define CAS_PROBE_MUX_SELECT_HI 0x000000f0 /* P_A[15:8] */
+#define CAS_PROBE_MUX_SELECT_SB 0x000000f0 /* txdma_wr address and size */
+#define CAS_PROBE_MUX_SELECT_EN 0xf0000000 /* enable probe on P_A[15:0] */
+
+/*
+ * interrupt bits for CAS_INTMASK[2-4], CAS_STATUS[2-4], CAS_CLEAR_ALIAS[2-4]
+ * and CAS_STATUS_ALIAS[2-4].
+ * CAS_STATUS[2-4] auto-clear when read. CAS_CLEAR_ALIAS[2-4] specifies which
+ * of bits 0-9 auto-clear when reading the corresponding CAS_STATUS_ALIAS[2-4].
+ */
+#define CAS_INTRN_RX_DONE 0x00000001 /* >=1 RX frames transferred. */
+#define CAS_INTRN_RX_COMP_FULL 0x00000002 /* RX completion ring full */
+#define CAS_INTRN_RX_COMP_AFULL 0x00000004 /* RX cmpl. ring almost full */
+#define CAS_INTRN_RX_BUF_NA 0x00000008 /* RX buffer not available */
+#define CAS_INTRN_RX_BUF_AEMPTY 0x00000010 /* RX desc. ring almost empty */
+
+/* INTn enable bit for CAS_INTMASK[2-4] */
+#define CAS_INTMASKN_EN 0x00000080 /* INT[B-D] enable */
+
+/* TX DMA registers */
+#define CAS_TX_CONF 0x2004 /* TX configuration */
+#define CAS_TX_FIFO_WR 0x2014 /* FIFO write pointer */
+#define CAS_TX_FIFO_SDWR 0x2018 /* FIFO shadow write pointer */
+#define CAS_TX_FIFO_RD 0x201c /* FIFO read pointer */
+#define CAS_TX_FIFO_SDRD 0x2020 /* FIFO shadow read pointer */
+#define CAS_TX_FIFO_PKT_CNT 0x2024 /* FIFO packet counter */
+#define CAS_TX_SM1 0x2028 /* TX state machine 1 */
+#define CAS_TX_SM2 0x202c /* TX state machine 2 */
+#define CAS_TX_DATA_PTR_LO 0x2030 /* TX data pointer low */
+#define CAS_TX_DATA_PTR_HI 0x2034 /* TX data pointer high */
+#define CAS_TX_KICK1 0x2038 /* TX kick 1 */
+#define CAS_TX_KICK2 0x203c /* TX kick 2 */
+#define CAS_TX_KICK3 0x2040 /* TX kick 3 */
+#define CAS_TX_KICK4 0x2044 /* TX kick 4 */
+#define CAS_TX_COMP1 0x2048 /* TX completion 1 */
+#define CAS_TX_COMP2 0x204c /* TX completion 2 */
+#define CAS_TX_COMP3 0x2050 /* TX completion 3 */
+#define CAS_TX_COMP4 0x2054 /* TX completion 4 */
+#define CAS_TX_COMPWB_BASE_LO 0x2058 /* TX completion writeback base low */
+#define CAS_TX_COMPWB_BASE_HI 0x205c /* TX completion writeback base high */
+#define CAS_TX_DESC1_BASE_LO 0x2060 /* TX descriptor ring 1 base low */
+#define CAS_TX_DESC1_BASE_HI 0x2064 /* TX descriptor ring 1 base high */
+#define CAS_TX_DESC2_BASE_LO 0x2068 /* TX descriptor ring 2 base low */
+#define CAS_TX_DESC2_BASE_HI 0x206c /* TX descriptor ring 2 base high */
+#define CAS_TX_DESC3_BASE_LO 0x2070 /* TX descriptor ring 2 base low */
+#define CAS_TX_DESC3_BASE_HI 0x2074 /* TX descriptor ring 2 base high */
+#define CAS_TX_DESC4_BASE_LO 0x2078 /* TX descriptor ring 2 base low */
+#define CAS_TX_DESC4_BASE_HI 0x207c /* TX descriptor ring 2 base high */
+#define CAS_TX_MAXBURST1 0x2080 /* TX MaxBurst 1 */
+#define CAS_TX_MAXBURST2 0x2084 /* TX MaxBurst 2 */
+#define CAS_TX_MAXBURST3 0x2088 /* TX MaxBurst 3 */
+#define CAS_TX_MAXBURST4 0x208c /* TX MaxBurst 4 */
+#define CAS_TX_FIFO_ADDR 0x2104 /* TX FIFO address */
+#define CAS_TX_FIFO_TAG 0x2108 /* TX FIFO tag */
+#define CAS_TX_FIFO_DATA_LO 0x210c /* TX FIFO data low */
+#define CAS_TX_FIFO_DATA_HI_T1 0x2110 /* TX FIFO data highT1 */
+#define CAS_TX_FIFO_DATA_HI_T0 0x2114 /* TX FIFO data highT0 */
+#define CAS_TX_FIFO_SIZE 0x2118 /* TX FIFO size in 64 byte multiples */
+#define CAS_TX_RAM_BIST 0x211c /* TX RAM BIST control/status */
+
+#define CAS_TX_CONF_TXDMA_EN 0x00000001 /* TX DMA enable */
+#define CAS_TX_CONF_FIFO_PIO 0x00000002 /* Allow TX FIFO PIO access. */
+#define CAS_TX_CONF_DESC1_MASK 0x0000003c /* TX descriptor ring 1 size */
+#define CAS_TX_CONF_DESC1_SHFT 2
+#define CAS_TX_CONF_DESC2_MASK 0x000003c0 /* TX descriptor ring 2 size */
+#define CAS_TX_CONF_DESC2_SHFT 6
+#define CAS_TX_CONF_DESC3_MASK 0x00003c00 /* TX descriptor ring 3 size */
+#define CAS_TX_CONF_DESC3_SHFT 10
+#define CAS_TX_CONF_DESC4_MASK 0x0003c000 /* TX descriptor ring 4 size */
+#define CAS_TX_CONF_DESC4_SHFT 14
+#define CAS_TX_CONF_PACED 0x00100000 /* ALL intr. on FIFO empty */
+#define CAS_TX_CONF_RDPP_DIS 0x01000000 /* Should always be set. */
+#define CAS_TX_CONF_COMPWB_Q1 0x02000000 /* Completion writeback... */
+#define CAS_TX_CONF_COMPWB_Q2 0x04000000 /* ...happens at the end... */
+#define CAS_TX_CONF_COMPWB_Q3 0x08000000 /* ...of every packet in... */
+#define CAS_TX_CONF_COMPWB_Q4 0x10000000 /* ...queue n. */
+#define CAS_TX_CONF_PICWB_DIS 0x20000000 /* pre-intr. compl. W/B dis. */
+#define CAS_TX_CONF_CTX_MASK 0xc0000000 /* test port selection */
+#define CAS_TX_CONF_CTX_SHFT 30
+
+#define CAS_TX_COMPWB_ALIGN 2048 /* TX compl. W/B alignment */
+
+#define CAS_TX_DESC_ALIGN 2048 /* TX descriptor alignment */
+
+/* descriptor ring size bits for both CAS_TX_CONF and CAS_RX_CONF */
+#define CAS_DESC_32 0x0 /* 32 descriptors */
+#define CAS_DESC_64 0x1 /* 64 descriptors */
+#define CAS_DESC_128 0x2 /* 128 descriptors */
+#define CAS_DESC_256 0x3 /* 256 descriptors */
+#define CAS_DESC_512 0x4 /* 512 descriptors */
+#define CAS_DESC_1K 0x5 /* 1k descriptors */
+#define CAS_DESC_2K 0x6 /* 2k descriptors */
+#define CAS_DESC_4K 0x7 /* 4k descriptors */
+#define CAS_DESC_8K 0x8 /* 8k descriptors */
+
+#define CAS_TX_SM1_CHAIN 0x000003ff /* chaining state machine */
+#define CAS_TX_SM1_CKSUM 0x00000c00 /* checksum state machine */
+#define CAS_TX_SM1_TX_FIFO_LOAD 0x0003f000 /* TX FIFO load state machine */
+#define CAS_TX_SM1_TX_FIFO_UNLD 0x003c0000 /* TX FIFO unload state mach. */
+#define CAS_TX_SM1_CACHE_CTRL 0x03c00000 /* cache control state mach. */
+#define CAS_TX_SM1_CBQARB 0x03c00000 /* CBQ arbiter state machine */
+
+#define CAS_TX_SM2_COMPWB 0x00000007 /* compl. WB state machine */
+#define CAS_TX_SM2_SUB_LOAD 0x00000038 /* sub load state machine */
+#define CAS_TX_SM2_KICK 0x000000c0 /* kick state machine */
+
+#define CAS_TX_RAM_BIST_START 0x00000001 /* Start RAM BIST process. */
+#define CAS_TX_RAM_BIST_SUMMARY 0x00000002 /* All RAM okay */
+#define CAS_TX_RAM_BIST_RAM32B 0x00000004 /* RAM32B okay */
+#define CAS_TX_RAM_BIST_RAM33B 0x00000008 /* RAM33B okay */
+#define CAS_TX_RAM_BIST_RAM32A 0x00000010 /* RAM32A okay */
+#define CAS_TX_RAM_BIST_RAM33A 0x00000020 /* RAM33A okay */
+#define CAS_TX_RAM_BIST_SM 0x000001c0 /* RAM BIST state machine */
+
+/* RX DMA registers */
+#define CAS_RX_CONF 0x4000 /* RX configuration */
+#define CAS_RX_PSZ 0x4004 /* RX page size */
+#define CAS_RX_FIFO_WR 0x4008 /* RX FIFO write pointer */
+#define CAS_RX_FIFO_RD 0x400c /* RX FIFO read pointer */
+#define CAS_RX_IPP_WR 0x4010 /* RX IPP FIFO write pointer */
+#define CAS_RX_IPP_SDWR 0x4014 /* RX IPP FIFO shadow write pointer */
+#define CAS_RX_IPP_RD 0x4018 /* RX IPP FIFO read pointer */
+#define CAS_RX_DEBUG 0x401c /* RX debug */
+#define CAS_RX_PTHRS 0x4020 /* RX PAUSE threshold */
+#define CAS_RX_KICK 0x4024 /* RX kick */
+#define CAS_RX_DESC_BASE_LO 0x4028 /* RX descriptor ring base low */
+#define CAS_RX_DESC_BASE_HI 0x402c /* RX descriptor ring base high */
+#define CAS_RX_COMP_BASE_LO 0x4030 /* RX completion ring base low */
+#define CAS_RX_COMP_BASE_HI 0x4034 /* RX completion ring base high */
+#define CAS_RX_COMP 0x4038 /* RX completion */
+#define CAS_RX_COMP_HEAD 0x403c /* RX completion head */
+#define CAS_RX_COMP_TAIL 0x4040 /* RX completion tail */
+#define CAS_RX_BLANK 0x4044 /* RX blanking for ISR read */
+#define CAS_RX_AEMPTY_THRS 0x4048 /* RX almost empty threshold */
+#define CAS_RX_RED 0x4048 /* RX random early detection enable */
+#define CAS_RX_FF 0x4050 /* RX FIFO fullness */
+#define CAS_RX_IPP_PKT_CNT 0x4054 /* RX IPP packet counter */
+#define CAS_RX_WORKING_DMA_LO 0x4058 /* RX working DMA pointer low */
+#define CAS_RX_WORKING_DMA_HI 0x405c /* RX working DMA pointer high */
+#define CAS_RX_BIST 0x4060 /* RX BIST */
+#define CAS_RX_CTRL_FIFO_WR 0x4064 /* RX control FIFO write pointer */
+#define CAS_RX_CTRL_FIFO_RD 0x4068 /* RX control FIFO read pointer */
+#define CAS_RX_BLANK_ALIAS 0x406c /* RX blanking for ISR read alias */
+#define CAS_RX_FIFO_ADDR 0x4080 /* RX FIFO address */
+#define CAS_RX_FIFO_TAG 0x4084 /* RX FIFO tag */
+#define CAS_RX_FIFO_DATA_LO 0x4088 /* RX FIFO data low */
+#define CAS_RX_FIFO_DATA_HI_T0 0x408c /* RX FIFO data highT0 */
+#define CAS_RX_FIFO_DATA_HI_T1 0x4090 /* RX FIFO data highT1 */
+#define CAS_RX_CTRL_FIFO 0x4094 /* RX control FIFO and batching FIFO */
+#define CAS_RX_CTRL_FIFO_LO 0x4098 /* RX control FIFO data low */
+#define CAS_RX_CTRL_FIFO_MD 0x409c /* RX control FIFO data mid */
+#define CAS_RX_CTRL_FIFO_HI 0x4100 /* RX control FIFO data high, flowID */
+#define CAS_RX_IPP_ADDR 0x4104 /* RX IPP FIFO address */
+#define CAS_RX_IPP_TAG 0x4108 /* RX IPP FIFO tag */
+#define CAS_RX_IPP_DATA_LO 0x410c /* RX IPP FIFO data low */
+#define CAS_RX_IPP_DATA_HI_T0 0x4110 /* RX IPP FIFO data highT0 */
+#define CAS_RX_IPP_DATA_HI_T1 0x4114 /* RX IPP FIFO data highT1 */
+#define CAS_RX_HDR_PAGE_LO 0x4118 /* RX header page pointer low */
+#define CAS_RX_HDR_PAGE_HIGH 0x411c /* RX header page pointer high */
+#define CAS_RX_MTU_PAGE_LO 0x4120 /* RX MTU page pointer low */
+#define CAS_RX_MTU_PAGE_HIGH 0x4124 /* RX MTU page pointer high */
+#define CAS_RX_REAS_DMA_ADDR 0x4128 /* RX reassembly DMA table address */
+#define CAS_RX_REAS_DMA_DATA_LO 0x412c /* RX reassembly DMA table data low */
+#define CAS_RX_REAS_DMA_DATA_MD 0x4130 /* RX reassembly DMA table data mid */
+#define CAS_RX_REAS_DMA_DATA_HI 0x4134 /* RX reassembly DMA table data high */
+/* The rest of the RX DMA registers are Cassini+/Saturn only. */
+#define CAS_RX_DESC2_BASE_LO 0x4200 /* RX descriptor ring 2 base low */
+#define CAS_RX_DESC2_BASE_HI 0x4204 /* RX descriptor ring 2 base high */
+#define CAS_RX_COMP2_BASE_LO 0x4208 /* RX completion ring 2 base low */
+#define CAS_RX_COMP2_BASE_HI 0x420c /* RX completion ring 2 base high */
+#define CAS_RX_COMP3_BASE_LO 0x4210 /* RX completion ring 3 base low */
+#define CAS_RX_COMP3_BASE_HI 0x4214 /* RX completion ring 3 base high */
+#define CAS_RX_COMP4_BASE_LO 0x4218 /* RX completion ring 4 base low */
+#define CAS_RX_COMP4_BASE_HI 0x421c /* RX completion ring 4 base high */
+#define CAS_RX_KICK2 0x4220 /* RX kick 2 */
+#define CAS_RX_COMP2 0x4224 /* RX completion 2 */
+#define CAS_RX_COMP_HEAD2 0x4228 /* RX completion head 2 */
+#define CAS_RX_COMP_TAIL2 0x422c /* RX completion tail 2 */
+#define CAS_RX_COMP_HEAD3 0x4230 /* RX completion head 3 */
+#define CAS_RX_COMP_TAIL3 0x4234 /* RX completion tail 3 */
+#define CAS_RX_COMP_HEAD4 0x4238 /* RX completion head 4 */
+#define CAS_RX_COMP_TAIL4 0x423c /* RX completion tail 4 */
+#define CAS_RX_AEMPTY_THRS2 0x4048 /* RX almost empty threshold 2 */
+
+#define CAS_RX_CONF_RXDMA_EN 0x00000001 /* RX DMA enable */
+#define CAS_RX_CONF_DESC_MASK 0x0000001e /* RX descriptor ring size */
+#define CAS_RX_CONF_DESC_SHFT 1
+#define CAS_RX_CONF_COMP_MASK 0x000001e0 /* RX complition ring size */
+#define CAS_RX_CONF_COMP_SHFT 5
+#define CAS_RX_CONF_BATCH_DIS 0x00000200 /* descriptor batching dis. */
+#define CAS_RX_CONF_SOFF_MASK 0x00001c00 /* swivel offset */
+#define CAS_RX_CONF_SOFF_SHFT 10
+/* The RX descriptor ring 2 is Cassini+/Saturn only. */
+#define CAS_RX_CONF_DESC2_MASK 0x000f0000 /* RX descriptor ring 2 size */
+#define CAS_RX_CONF_DESC2_SHFT 16
+
+#define CAS_RX_CONF_COMP_128 0x0 /* 128 descriptors */
+#define CAS_RX_CONF_COMP_256 0x1 /* 256 descriptors */
+#define CAS_RX_CONF_COMP_512 0x2 /* 512 descriptors */
+#define CAS_RX_CONF_COMP_1K 0x3 /* 1k descriptors */
+#define CAS_RX_CONF_COMP_2K 0x4 /* 2k descriptors */
+#define CAS_RX_CONF_COMP_4K 0x5 /* 4k descriptors */
+#define CAS_RX_CONF_COMP_8K 0x6 /* 8k descriptors */
+#define CAS_RX_CONF_COMP_16K 0x7 /* 16k descriptors */
+#define CAS_RX_CONF_COMP_32K 0x8 /* 32k descriptors */
+
+#define CAS_RX_PSZ_MASK 0x00000003 /* RX page size */
+#define CAS_RX_PSZ_SHFT 0
+#define CAS_RX_PSZ_MB_CNT_MASK 0x00007800 /* number of MTU buffers */
+#define CAS_RX_PSZ_MB_CNT_SHFT 11
+#define CAS_RX_PSZ_MB_STRD_MASK 0x18000000 /* MTU buffer stride */
+#define CAS_RX_PSZ_MB_STRD_SHFT 27
+#define CAS_RX_PSZ_MB_OFF_MASK 0xc0000000 /* MTU buffer offset */
+#define CAS_RX_PSZ_MB_OFF_SHFT 30
+
+#define CAS_RX_PSZ_2K 0x0 /* page size 2Kbyte */
+#define CAS_RX_PSZ_4K 0x1 /* page size 4Kbyte */
+#define CAS_RX_PSZ_8K 0x2 /* page size 8Kbyte */
+#define CAS_RX_PSZ_16K 0x3 /* page size 16Kbyte*/
+
+#define CAS_RX_PSZ_MB_STRD_1K 0x0 /* MTU buffer stride 1Kbyte */
+#define CAS_RX_PSZ_MB_STRD_2K 0x1 /* MTU buffer stride 2Kbyte */
+#define CAS_RX_PSZ_MB_STRD_4K 0x2 /* MTU buffer stride 4Kbyte */
+#define CAS_RX_PSZ_MB_STRD_8K 0x3 /* MTU buffer stride 8Kbyte */
+
+#define CAS_RX_PSZ_MB_OFF_0 0x0 /* MTU buf. offset 0 bytes */
+#define CAS_RX_PSZ_MB_OFF_64 0x1 /* MTU buf. offset 64 bytes */
+#define CAS_RX_PSZ_MB_OFF_96 0x2 /* MTU buf. offset 96 bytes */
+#define CAS_RX_PSZ_MB_OFF_128 0x3 /* MTU buf. offset 128 bytes */
+
+#define CAS_RX_DESC_ALIGN 8192 /* RX descriptor alignment */
+
+#define CAS_RX_COMP_ALIGN 8192 /* RX complition alignment */
+
+/* The RX PAUSE thresholds are specified in multiples of 64 bytes. */
+#define CAS_RX_PTHRS_XOFF_MASK 0x000001ff /* XOFF PAUSE */
+#define CAS_RX_PTHRS_XOFF_SHFT 0
+#define CAS_RX_PTHRS_XON_MASK 0x001ff000 /* XON PAUSE */
+#define CAS_RX_PTHRS_XON_SHFT 12
+
+/*
+ * CAS_RX_BLANK and CAS_RX_BLANK_ALIAS bits
+ * CAS_RX_BLANK is loaded each time CAS_STATUS is read and CAS_RX_BLANK_ALIAS
+ * is read each time CAS_STATUS_ALIAS is read. The blanking time is specified
+ * in multiples of 512 core ticks (which runs at 125MHz).
+ */
+#define CAS_RX_BLANK_PKTS_MASK 0x000001ff /* RX blanking packets */
+#define CAS_RX_BLANK_PKTS_SHFT 0
+#define CAS_RX_BLANK_TIME_MASK 0x3ffff000 /* RX blanking time */
+#define CAS_RX_BLANK_TIME_SHFT 12
+
+/* CAS_RX_AEMPTY_THRS and CAS_RX_AEMPTY_THRS2 bits */
+#define CAS_RX_AEMPTY_THRS_MASK 0x00001fff /* RX_BUF_AEMPTY threshold */
+#define CAS_RX_AEMPTY_THRS_SHFT 0
+#define CAS_RX_AEMPTY_COMP_MASK 0x0fffe000 /* RX_COMP_AFULL threshold */
+#define CAS_RX_AEMPTY_COMP_SHFT 13
+
+/* The RX random early detection probability is in 12.5% granularity. */
+#define CAS_RX_RED_4K_6K_MASK 0x000000ff /* 4K < FIFO threshold < 6K */
+#define CAS_RX_RED_4K_6K_SHFT 0
+#define CAS_RX_RED_6K_8K_MASK 0x0000ff00 /* 6K < FIFO threshold < 8K */
+#define CAS_RX_RED_6K_8K_SHFT 8
+#define CAS_RX_RED_8K_10K_MASK 0x00ff0000 /* 8K < FIFO threshold < 10K */
+#define CAS_RX_RED_8K_10K_SHFT 16
+#define CAS_RX_RED_10K_12K_MASK 0xff000000 /* 10K < FIFO threshold < 12K */
+#define CAS_RX_RED_10K_12K_SHFT 24
+
+/* CAS_RX_FF_IPP_MASK and CAS_RX_FF_FIFO_MASK are in 8 bytes granularity. */
+#define CAS_RX_FF_PKT_MASK 0x000000ff /* # of packets in RX FIFO */
+#define CAS_RX_FF_PKT_SHFT 0
+#define CAS_RX_FF_IPP_MASK 0x0007ff00 /* IPP FIFO level */
+#define CAS_RX_FF_IPP_SHFT 8
+#define CAS_RX_FF_FIFO_MASK 0x3ff80000 /* RX FIFO level */
+#define CAS_RX_FF_FIFO_SHFT 19
+
+#define CAS_RX_BIST_START 0x00000001 /* Start BIST process. */
+#define CAS_RX_BIST_SUMMARY 0x00000002 /* All okay */
+#define CAS_RX_BIST_SM 0x00007800 /* BIST state machine */
+#define CAS_RX_BIST_REAS_27 0x00008000 /* Reas 27 okay */
+#define CAS_RX_BIST_REAS_26B 0x00010000 /* Reas 26B okay */
+#define CAS_RX_BIST_REAS_26A 0x00020000 /* Reas 26A okay */
+#define CAS_RX_BIST_CTRL_33 0x00040000 /* Control FIFO 33 okay */
+#define CAS_RX_BIST_CTRL_32 0x00080000 /* Control FIFO 32 okay */
+#define CAS_RX_BIST_IPP_33C 0x00100000 /* IPP 33C okay */
+#define CAS_RX_BIST_IPP_32C 0x00200000 /* IPP 32C okay */
+#define CAS_RX_BIST_IPP_33B 0x00400000 /* IPP 33B okay */
+#define CAS_RX_BIST_IPP_32B 0x00800000 /* IPP 32B okay */
+#define CAS_RX_BIST_IPP_33A 0x01000000 /* IPP 33A okay */
+#define CAS_RX_BIST_IPP_32A 0x02000000 /* IPP 32A okay */
+#define CAS_RX_BIST_33C 0x04000000 /* 33C okay */
+#define CAS_RX_BIST_32C 0x08000000 /* 32C okay */
+#define CAS_RX_BIST_33B 0x10000000 /* 33B okay */
+#define CAS_RX_BIST_32B 0x20000000 /* 32B okay */
+#define CAS_RX_BIST_33A 0x40000000 /* 33A okay */
+#define CAS_RX_BIST_32A 0x80000000 /* 32A okay */
+
+#define CAS_RX_REAS_DMA_ADDR_LC 0x0000003f /* reas. table location sel. */
+
+/* header parser registers */
+#define CAS_HP_CONF 0x4140 /* HP configuration */
+#define CAS_HP_IR_ADDR 0x4144 /* HP instruction RAM address */
+#define CAS_HP_IR_DATA_LO 0x4148 /* HP instruction RAM data low */
+#define CAS_HP_IR_DATA_MD 0x414c /* HP instruction RAM data mid */
+#define CAS_HP_IR_DATA_HI 0x4150 /* HP instruction RAM data high */
+#define CAS_HP_DR_FDB 0x4154 /* HP data RAM and flow DB address */
+#define CAS_HP_DR_DATA 0x4158 /* HP data RAM data */
+#define CAS_HP_FLOW_DB1 0x415c /* HP flow database 1 */
+#define CAS_HP_FLOW_DB2 0x4160 /* HP flow database 2 */
+#define CAS_HP_FLOW_DB3 0x4164 /* HP flow database 3 */
+#define CAS_HP_FLOW_DB4 0x4168 /* HP flow database 4 */
+#define CAS_HP_FLOW_DB5 0x416c /* HP flow database 5 */
+#define CAS_HP_FLOW_DB6 0x4170 /* HP flow database 6 */
+#define CAS_HP_FLOW_DB7 0x4174 /* HP flow database 7 */
+#define CAS_HP_FLOW_DB8 0x4178 /* HP flow database 8 */
+#define CAS_HP_FLOW_DB9 0x417c /* HP flow database 9 */
+#define CAS_HP_FLOW_DB10 0x4180 /* HP flow database 10 */
+#define CAS_HP_FLOW_DB11 0x4184 /* HP flow database 11 */
+#define CAS_HP_FLOW_DB12 0x4188 /* HP flow database 12 */
+#define CAS_HP_SM 0x418c /* HP state machine */
+#define CAS_HP_STATUS1 0x4190 /* HP status 1 */
+#define CAS_HP_STATUS2 0x4194 /* HP status 2 */
+#define CAS_HP_STATUS3 0x4198 /* HP status 3 */
+#define CAS_HP_RAM_BIST 0x419c /* HP RAM BIST */
+
+#define CAS_HP_CONF_PARSE_EN 0x00000001 /* header parsing enable */
+#define CAS_HP_CONF_NCPU_MASK 0x000000fc /* #CPUs (0x0: 64) */
+#define CAS_HP_CONF_NCPU_SHFT 2
+#define CAS_HP_CONF_SINC_DIS 0x00000100 /* SYN inc. seq. number dis. */
+#define CAS_HP_CONF_TPT_MASK 0x000ffe00 /* TCP payload threshold */
+#define CAS_HP_CONF_TPT_SHFT 9
+
+#define CAS_HP_DR_FDB_DR_MASK 0x0000001f /* data RAM location sel. */
+#define CAS_HP_DR_FDB_DR_SHFT 0
+#define CAS_HP_DR_FDB_FDB_MASK 0x00003f00 /* flow DB location sel. */
+#define CAS_HP_DR_FDB_FDB_SHFT 8
+
+#define CAS_HP_STATUS1_OP_MASK 0x00000007 /* HRP opcode */
+#define CAS_HP_STATUS1_OP_SHFT 0
+#define CAS_HP_STATUS1_LB_MASK 0x000001f8 /* load balancing CPU number */
+#define CAS_HP_STATUS1_LB_SHFT 3
+#define CAS_HP_STATUS1_L3O_MASK 0x0000fe00 /* layer 3 offset */
+#define CAS_HP_STATUS1_L3O_SHFT 9
+#define CAS_HP_STATUS1_SAP_MASK 0xffff0000 /* ethertype */
+#define CAS_HP_STATUS1_SAP_SHFT 16
+
+#define CAS_HP_STATUS2_TSZ_MASK 0x0000ffff /* TCP payload size */
+#define CAS_HP_STATUS2_TSZ_SHFT 0
+#define CAS_HP_STATUS2_TO_MASK 0x007f0000 /* TCP payload offset */
+#define CAS_HP_STATUS2_TO_SHFT 16
+#define CAS_HP_STATUS2_FID_MASK 0x1f800000 /* flow ID */
+#define CAS_HP_STATUS2_FID_SHFT 23
+#define CAS_HP_STATUS2_AR2_MASK 0xe0000000 /* accu_R2[6:4] */
+#define CAS_HP_STATUS2_AR2_SHFT 29
+
+#define CAS_HP_STATUS3_TCP_NCHK 0x00000001 /* TCP no payload check */
+#define CAS_HP_STATUS3_TCP_CHK 0x00000002 /* TCP payload check */
+#define CAS_HP_STATUS3_SYN_FLAG 0x00000004 /* SYN flag */
+#define CAS_HP_STATUS3_TCP_FLAG 0x00000008 /* TCP flag check */
+#define CAS_HP_STATUS3_CTRL_PF 0x00000010 /* control packet flag */
+#define CAS_HP_STATUS3_NASSIST 0x00000020 /* no assist */
+#define CAS_HP_STATUS3_MASK_PT 0x00000040 /* Mask payload threshold. */
+#define CAS_HP_STATUS3_FRC_TPC 0x00000080 /* Force TCP payload check. */
+#define CAS_HP_STATUS3_MASK_DLZ 0x00000100 /* Mask data length equal 0. */
+#define CAS_HP_STATUS3_FRC_TNPC 0x00000200 /* Force TCP no payload chk. */
+#define CAS_HP_STATUS3_JMBHS_EN 0x00000400 /* jumbo header split enable */
+#define CAS_HP_STATUS3_BWO_REAS 0x00000800 /* batching w/o reassembly */
+#define CAS_HP_STATUS3_FRC_DROP 0x00001000 /* force drop */
+#define CAS_HP_STATUS3_AR1_MASK 0x000fe000 /* accu_R1 */
+#define CAS_HP_STATUS3_AR1_SHFT 13
+#define CAS_HP_STATUS3_CSO_MASK 0x07f00000 /* checksum start offset */
+#define CAS_HP_STATUS3_CSO_SHFT 19
+#define CAS_HP_STATUS3_AR2_MASK 0xf0000000 /* accu_R2[3:0] */
+#define CAS_HP_STATUS3_AR2_SHFT 28
+
+#define CAS_HP_RAM_BIST_START 0x00000001 /* Start RAM BIST process. */
+#define CAS_HP_RAM_BIST_SUMMARY 0x00000002 /* all RAM okay */
+#define CAS_HP_RAM_BIST_TCPSEQ 0x00020000 /* TCP seqeunce RAM okay */
+#define CAS_HP_RAM_BIST_FID31 0x00040000 /* flow ID RAM3 bank 1 okay */
+#define CAS_HP_RAM_BIST_FID21 0x00080000 /* flow ID RAM2 bank 1 okay */
+#define CAS_HP_RAM_BIST_FID11 0x00100000 /* flow ID RAM1 bank 1 okay */
+#define CAS_HP_RAM_BIST_FID01 0x00200000 /* flow ID RAM0 bank 1 okay */
+#define CAS_HP_RAM_BIST_FID30 0x00400000 /* flow ID RAM3 bank 0 okay */
+#define CAS_HP_RAM_BIST_FID20 0x00800000 /* flow ID RAM2 bank 0 okay */
+#define CAS_HP_RAM_BIST_FID10 0x01000000 /* flow ID RAM1 bank 0 okay */
+#define CAS_HP_RAM_BIST_FID00 0x02000000 /* flow ID RAM0 bank 0 okay */
+#define CAS_HP_RAM_BIST_AGE1 0x04000000 /* aging RAM1 okay */
+#define CAS_HP_RAM_BIST_AGE0 0x08000000 /* aging RAM0 okay */
+#define CAS_HP_RAM_BIST_IR2 0x10000000 /* instruction RAM2 okay */
+#define CAS_HP_RAM_BIST_IR1 0x20000000 /* instruction RAM1 okay */
+#define CAS_HP_RAM_BIST_IR0 0x40000000 /* instruction RAM0 okay */
+#define CAS_HP_RAM_BIST_DR 0x80000000 /* data RAM okay */
+
+/* MAC registers */
+#define CAS_MAC_TXRESET 0x6000 /* TX MAC software reset command */
+#define CAS_MAC_RXRESET 0x6004 /* RX MAC software reset command */
+#define CAS_MAC_SPC 0x6008 /* send PAUSE command */
+#define CAS_MAC_TX_STATUS 0x6010 /* TX MAC status */
+#define CAS_MAC_RX_STATUS 0x6014 /* RX MAC status */
+#define CAS_MAC_CTRL_STATUS 0x6018 /* MAC control status */
+#define CAS_MAC_TX_MASK 0x6020 /* TX MAC mask */
+#define CAS_MAC_RX_MASK 0x6024 /* RX MAC mask */
+#define CAS_MAC_CTRL_MASK 0x6028 /* MAC control mask */
+#define CAS_MAC_TX_CONF 0x6030 /* TX MAC configuration */
+#define CAS_MAC_RX_CONF 0x6034 /* RX MAC configuration */
+#define CAS_MAC_CTRL_CONF 0x6038 /* MAC control configuration */
+#define CAS_MAC_XIF_CONF 0x603c /* XIF configuration */
+#define CAS_MAC_IPG0 0x6040 /* inter packet gap 0 */
+#define CAS_MAC_IPG1 0x6044 /* inter packet gap 1 */
+#define CAS_MAC_IPG2 0x6048 /* inter packet gap 2 */
+#define CAS_MAC_SLOT_TIME 0x604c /* slot time */
+#define CAS_MAC_MIN_FRAME 0x6050 /* minimum frame size */
+#define CAS_MAC_MAX_BF 0x6054 /* maximum bust and frame size */
+#define CAS_MAC_PREAMBLE_LEN 0x6058 /* PA size */
+#define CAS_MAC_JAM_SIZE 0x605c /* jam size */
+#define CAS_MAC_ATTEMPT_LIMIT 0x6060 /* attempt limit */
+#define CAS_MAC_CTRL_TYPE 0x6064 /* MAC control type */
+#define CAS_MAC_ADDR0 0x6080 /* MAC address 0 */
+#define CAS_MAC_ADDR1 0x6084 /* MAC address 1 */
+#define CAS_MAC_ADDR2 0x6088 /* MAC address 2 */
+#define CAS_MAC_ADDR3 0x608c /* MAC address 3 */
+#define CAS_MAC_ADDR4 0x6090 /* MAC address 4 */
+#define CAS_MAC_ADDR5 0x6094 /* MAC address 5 */
+#define CAS_MAC_ADDR6 0x6098 /* MAC address 6 */
+#define CAS_MAC_ADDR7 0x609c /* MAC address 7 */
+#define CAS_MAC_ADDR8 0x60a0 /* MAC address 8 */
+#define CAS_MAC_ADDR9 0x60a4 /* MAC address 9 */
+#define CAS_MAC_ADDR10 0x60a8 /* MAC address 10 */
+#define CAS_MAC_ADDR11 0x60ac /* MAC address 11 */
+#define CAS_MAC_ADDR12 0x60b0 /* MAC address 12 */
+#define CAS_MAC_ADDR13 0x60b4 /* MAC address 13 */
+#define CAS_MAC_ADDR14 0x60b8 /* MAC address 14 */
+#define CAS_MAC_ADDR15 0x60bc /* MAC address 15 */
+#define CAS_MAC_ADDR16 0x60c0 /* MAC address 16 */
+#define CAS_MAC_ADDR17 0x60c4 /* MAC address 17 */
+#define CAS_MAC_ADDR18 0x60c8 /* MAC address 18 */
+#define CAS_MAC_ADDR19 0x60cc /* MAC address 19 */
+#define CAS_MAC_ADDR20 0x60d0 /* MAC address 20 */
+#define CAS_MAC_ADDR21 0x60d4 /* MAC address 21 */
+#define CAS_MAC_ADDR22 0x60d8 /* MAC address 22 */
+#define CAS_MAC_ADDR23 0x60dc /* MAC address 23 */
+#define CAS_MAC_ADDR24 0x60e0 /* MAC address 24 */
+#define CAS_MAC_ADDR25 0x60e4 /* MAC address 25 */
+#define CAS_MAC_ADDR26 0x60e8 /* MAC address 26 */
+#define CAS_MAC_ADDR27 0x60ec /* MAC address 27 */
+#define CAS_MAC_ADDR28 0x60f0 /* MAC address 28 */
+#define CAS_MAC_ADDR29 0x60f4 /* MAC address 29 */
+#define CAS_MAC_ADDR30 0x60f8 /* MAC address 30 */
+#define CAS_MAC_ADDR31 0x60fc /* MAC address 31 */
+#define CAS_MAC_ADDR32 0x6100 /* MAC address 32 */
+#define CAS_MAC_ADDR33 0x6104 /* MAC address 33 */
+#define CAS_MAC_ADDR34 0x6108 /* MAC address 34 */
+#define CAS_MAC_ADDR35 0x610c /* MAC address 35 */
+#define CAS_MAC_ADDR36 0x6110 /* MAC address 36 */
+#define CAS_MAC_ADDR37 0x6114 /* MAC address 37 */
+#define CAS_MAC_ADDR38 0x6118 /* MAC address 38 */
+#define CAS_MAC_ADDR39 0x611c /* MAC address 39 */
+#define CAS_MAC_ADDR40 0x6120 /* MAC address 40 */
+#define CAS_MAC_ADDR41 0x6124 /* MAC address 41 */
+#define CAS_MAC_ADDR42 0x6128 /* MAC address 42 */
+#define CAS_MAC_ADDR43 0x612c /* MAC address 43 */
+#define CAS_MAC_ADDR44 0x6130 /* MAC address 44 */
+#define CAS_MAC_AFILTER0 0x614c /* address filter 0 */
+#define CAS_MAC_AFILTER1 0x6150 /* address filter 1 */
+#define CAS_MAC_AFILTER2 0x6154 /* address filter 2 */
+#define CAS_MAC_AFILTER_MASK1_2 0x6158 /* address filter 2 & 1 mask*/
+#define CAS_MAC_AFILTER_MASK0 0x615c /* address filter 0 mask */
+#define CAS_MAC_HASH0 0x6160 /* hash table 0 */
+#define CAS_MAC_HASH1 0x6164 /* hash table 1 */
+#define CAS_MAC_HASH2 0x6168 /* hash table 2 */
+#define CAS_MAC_HASH3 0x616c /* hash table 3 */
+#define CAS_MAC_HASH4 0x6170 /* hash table 4 */
+#define CAS_MAC_HASH5 0x6174 /* hash table 5 */
+#define CAS_MAC_HASH6 0x6178 /* hash table 6 */
+#define CAS_MAC_HASH7 0x617c /* hash table 7 */
+#define CAS_MAC_HASH8 0x6180 /* hash table 8 */
+#define CAS_MAC_HASH9 0x6184 /* hash table 9 */
+#define CAS_MAC_HASH10 0x6188 /* hash table 10 */
+#define CAS_MAC_HASH11 0x618c /* hash table 11 */
+#define CAS_MAC_HASH12 0x6190 /* hash table 12 */
+#define CAS_MAC_HASH13 0x6194 /* hash table 13 */
+#define CAS_MAC_HASH14 0x6198 /* hash table 14 */
+#define CAS_MAC_HASH15 0x619c /* hash table 15 */
+#define CAS_MAC_NORM_COLL_CNT 0x61a0 /* normal collision counter */
+#define CAS_MAC_FIRST_COLL_CNT 0x61a4 /* 1st attempt suc. collision counter */
+#define CAS_MAC_EXCESS_COLL_CNT 0x61a8 /* excess collision counter */
+#define CAS_MAC_LATE_COLL_CNT 0x61ac /* late collision counter */
+#define CAS_MAC_DEFER_TMR_CNT 0x61b0 /* defer timer */
+#define CAS_MAC_PEAK_ATTEMPTS 0x61b4 /* peak attempts */
+#define CAS_MAC_RX_FRAME_COUNT 0x61b8 /* receive frame counter */
+#define CAS_MAC_RX_LEN_ERR_CNT 0x61bc /* length error counter */
+#define CAS_MAC_RX_ALIGN_ERR 0x61c0 /* alignment error counter */
+#define CAS_MAC_RX_CRC_ERR_CNT 0x61c4 /* FCS error counter */
+#define CAS_MAC_RX_CODE_VIOL 0x61c8 /* RX code violation error counter */
+#define CAS_MAC_RANDOM_SEED 0x61cc /* random number seed */
+#define CAS_MAC_MAC_STATE 0x61d0 /* MAC state machine */
+
+#define CAS_MAC_SPC_TIME_MASK 0x0000ffff /* PAUSE time value */
+#define CAS_MAC_SPC_TIME_SHFT 0
+#define CAS_MAC_SPC_SEND 0x00010000 /* Send PAUSE frame. */
+
+/* CAS_MAC_TX_STATUS and CAS_MAC_TX_MASK register bits */
+#define CAS_MAC_TX_FRAME_XMTD 0x00000001 /* Frame transmitted. */
+#define CAS_MAC_TX_UNDERRUN 0x00000002 /* TX data starvation */
+#define CAS_MAC_TX_MAX_PKT_ERR 0x00000004 /* frame > CAS_MAC_MAX_FRAME */
+#define CAS_MAC_TX_NCC_EXP 0x00000008 /* normal coll. counter wrap */
+#define CAS_MAC_TX_ECC_EXP 0x00000010 /* excess coll. counter wrap */
+#define CAS_MAC_TX_LCC_EXP 0x00000020 /* late coll. counter wrap */
+#define CAS_MAC_TX_FCC_EXP 0x00000040 /* 1st coll. counter wrap */
+#define CAS_MAC_TX_DEFER_EXP 0x00000080 /* defer timer wrap */
+#define CAS_MAC_TX_PEAK_EXP 0x00000100 /* peak attempts counter wrap */
+
+/* CAS_MAC_RX_STATUS and CAS_MAC_RX_MASK register bits */
+#define CAS_MAC_RX_FRAME_RCVD 0x00000001 /* Frame received. */
+#define CAS_MAC_RX_OVERFLOW 0x00000002 /* RX FIFO overflow */
+#define CAS_MAC_RX_FRAME_EXP 0x00000004 /* RX frame counter wrap */
+#define CAS_MAC_RX_ALIGN_EXP 0x00000008 /* alignment error cntr. wrap */
+#define CAS_MAC_RX_CRC_EXP 0x00000010 /* CRC error counter wrap */
+#define CAS_MAC_RX_LEN_EXP 0x00000020 /* length error counter wrap */
+#define CAS_MAC_RX_VIOL_EXP 0x00000040 /* code violation cntr. wrap */
+
+/* CAS_MAC_CTRL_STATUS and CAS_MAC_CTRL_MASK register bits */
+#define CAS_MAC_CTRL_PAUSE_RCVD 0x00000001 /* PAUSE received. */
+#define CAS_MAC_CTRL_PAUSE 0x00000002 /* PAUSE state entered. */
+#define CAS_MAC_CTRL_NON_PAUSE 0x00000004 /* PAUSE state left. */
+
+#define CAS_MAC_CTRL_STATUS_PT_MASK 0xffff0000 /* PAUSE time */
+#define CAS_MAC_CTRL_STATUS_PT_SHFT 16
+
+#define CAS_MAC_TX_CONF_EN 0x00000001 /* TX enable */
+#define CAS_MAC_TX_CONF_ICARR 0x00000002 /* Ignore carrier sense. */
+#define CAS_MAC_TX_CONF_ICOLLIS 0x00000004 /* Ignore collisions. */
+#define CAS_MAC_TX_CONF_EN_IPG0 0x00000008 /* extend RX-to-TX IPG */
+#define CAS_MAC_TX_CONF_NGU 0x00000010 /* Never give up. */
+#define CAS_MAC_TX_CONF_NGUL 0x00000020 /* never give up limit */
+#define CAS_MAC_TX_CONF_NBOFF 0x00000040 /* Disable backoff algorithm. */
+#define CAS_MAC_TX_CONF_SDOWN 0x00000080 /* CSMA/CD slow down */
+#define CAS_MAC_TX_CONF_NO_FCS 0x00000100 /* Don't generate FCS. */
+#define CAS_MAC_TX_CONF_CARR 0x00000200 /* carrier extension enable */
+
+#define CAS_MAC_RX_CONF_EN 0x00000001 /* RX enable */
+#define CAS_MAC_RX_CONF_STRPPAD 0x00000002 /* Must not be set. */
+#define CAS_MAC_RX_CONF_STRPFCS 0x00000004 /* Strip FCS bytes. */
+#define CAS_MAC_RX_CONF_PROMISC 0x00000008 /* promiscuous mode enable */
+#define CAS_MAC_RX_CONF_PGRP 0x00000010 /* promiscuous group mode en. */
+#define CAS_MAC_RX_CONF_HFILTER 0x00000020 /* hash filter enable */
+#define CAS_MAC_RX_CONF_AFILTER 0x00000040 /* address filter enable */
+#define CAS_MAC_RX_CONF_DIS_DOE 0x00000080 /* disable discard on error */
+#define CAS_MAC_RX_CONF_CARR 0x00000100 /* carrier extension enable */
+
+#define CAS_MAC_CTRL_CONF_TXP 0x00000001 /* send PAUSE enable */
+#define CAS_MAC_CTRL_CONF_RXP 0x00000002 /* receive PAUSE enable */
+#define CAS_MAC_CTRL_CONF_PASSP 0x00000004 /* Pass PAUSE up to RX DMA. */
+
+#define CAS_MAC_XIF_CONF_TX_OE 0x00000001 /* MII TX output drivers en. */
+#define CAS_MAC_XIF_CONF_ILBK 0x00000002 /* MII internal loopback en. */
+#define CAS_MAC_XIF_CONF_NOECHO 0x00000004 /* Disable echo. */
+#define CAS_MAC_XIF_CONF_GMII 0x00000008 /* GMII (vs. MII) mode enable */
+#define CAS_MAC_XIF_CONF_BUF_OE 0x00000010 /* MII_BUF_OE enable */
+#define CAS_MAC_XIF_CONF_LNKLED 0x00000020 /* Force LINKLED# active. */
+#define CAS_MAC_XIF_CONF_FDXLED 0x00000040 /* Force FDPLXLED# active. */
+
+/*
+ * The value of CAS_MAC_SLOT_TIME specifies the PAUSE time unit and depends
+ * on whether carrier extension is enabled.
+ */
+#define CAS_MAC_SLOT_TIME_CARR 0x200 /* slot time for carr. ext. */
+#define CAS_MAC_SLOT_TIME_NORM 0x40 /* slot time otherwise */
+
+#define CAS_MAC_MAX_BF_FRM_MASK 0x00007fff /* maximum frame size */
+#define CAS_MAC_MAX_BF_FRM_SHFT 0
+#define CAS_MAC_MAX_BF_BST_MASK 0x3fff0000 /* maximum burst size */
+#define CAS_MAC_MAX_BF_BST_SHFT 16
+
+/*
+ * MIF registers
+ * The bit-bang registers use the low bit only.
+ */
+#define CAS_MIF_BB_CLOCK 0x6200 /* MIF bit-bang clock */
+#define CAS_MIF_BB_DATA 0x6204 /* MIF bit-bang data */
+#define CAS_MIF_BB_OUTPUT_EN 0x6208 /* MIF bit-bang output enable */
+#define CAS_MIF_FRAME 0x620c /* MIF frame/output */
+#define CAS_MIF_CONF 0x6210 /* MIF configuration */
+#define CAS_MIF_MASK 0x6214 /* MIF mask */
+#define CAS_MIF_STATUS 0x6218 /* MIF status */
+#define CAS_MIF_SM 0x621c /* MIF state machine */
+
+#define CAS_MIF_FRAME_DATA 0x0000ffff /* instruction payload */
+#define CAS_MIF_FRAME_TA_LSB 0x00010000 /* turn around LSB */
+#define CAS_MIF_FRAME_TA_MSB 0x00020000 /* turn around MSB */
+#define CAS_MIF_FRAME_REG_MASK 0x007c0000 /* register address */
+#define CAS_MIF_FRAME_REG_SHFT 18
+#define CAS_MIF_FRAME_PHY_MASK 0x0f800000 /* PHY address */
+#define CAS_MIF_FRAME_PHY_SHFT 23
+#define CAS_MIF_FRAME_OP_WRITE 0x10000000 /* write opcode */
+#define CAS_MIF_FRAME_OP_READ 0x20000000 /* read opcode */
+#define CAS_MIF_FRAME_OP_MASK \
+ (CAS_MIF_FRAME_OP_WRITE | CAS_MIF_FRAME_OP_READ)
+#define CAS_MIF_FRAME_ST 0x40000000 /* start of frame */
+#define CAS_MIF_FRAME_ST_MASK 0xc0000000 /* start of frame */
+
+#define CAS_MIF_FRAME_READ \
+ (CAS_MIF_FRAME_TA_MSB | CAS_MIF_FRAME_OP_READ | CAS_MIF_FRAME_ST)
+#define CAS_MIF_FRAME_WRITE \
+ (CAS_MIF_FRAME_TA_MSB | CAS_MIF_FRAME_OP_WRITE | CAS_MIF_FRAME_ST)
+
+#define CAS_MIF_CONF_PHY_SELECT 0x00000001 /* PHY select, 0: MDIO_0 */
+#define CAS_MIF_CONF_POLL_EN 0x00000002 /* polling mechanism enable */
+#define CAS_MIF_CONF_BB_MODE 0x00000004 /* bit-bang mode enable */
+#define CAS_MIF_CONF_PREG_MASK 0x000000f8 /* polled register */
+#define CAS_MIF_CONF_PREG_SHFT 3
+#define CAS_MIF_CONF_MDI0 0x00000100 /* MDIO_0 data/attached */
+#define CAS_MIF_CONF_MDI1 0x00000200 /* MDIO_1 data/attached */
+#define CAS_MIF_CONF_PPHY_MASK 0x00007c00 /* polled PHY */
+#define CAS_MIF_CONF_PPHY_SHFT 10
+
+/* CAS_MIF_MASK and CAS_MIF_STATUS bits */
+#define CAS_MIF_POLL_STATUS_MASK 0x0000ffff /* polling status */
+#define CAS_MIF_POLL_STATUS_SHFT 0
+#define CAS_MIF_POLL_DATA_MASK 0xffff0000 /* polling data */
+#define CAS_MIF_POLL_DATA_SHFT 8
+
+#define CAS_MIF_SM_CTRL_MASK 0x00000007 /* ctrl. state machine state */
+#define CAS_MIF_SM_CTRL_SHFT 0
+#define CAS_MIF_SM_EXEC_MASK 0x00000060 /* exec. state machine state */
+
+/* PCS/Serialink registers */
+#define CAS_PCS_CTRL 0x9000 /* PCS MII control (PCS "BMCR") */
+#define CAS_PCS_STATUS 0x9004 /* PCS MII status (PCS "BMSR") */
+#define CAS_PCS_ANAR 0x9008 /* PCS MII advertisement */
+#define CAS_PCS_ANLPAR 0x900c /* PCS MII link partner ability */
+#define CAS_PCS_CONF 0x9010 /* PCS configuration */
+#define CAS_PCS_SM 0x9014 /* PCS state machine */
+#define CAS_PCS_INTR_STATUS 0x9018 /* PCS interrupt status */
+#define CAS_PCS_DATAPATH 0x9050 /* datapath mode */
+#define CAS_PCS_SERDES_CTRL 0x9054 /* SERDES control */
+#define CAS_PCS_OUTPUT_SELECT 0x9058 /* shared output select */
+#define CAS_PCS_SERDES_STATUS 0x905c /* SERDES state */
+#define CAS_PCS_PKT_CNT 0x9060 /* PCS packet counter */
+
+#define CAS_PCS_CTRL_1000M 0x00000040 /* 1000Mbps speed select */
+#define CAS_PCS_CTRL_COLL_TEST 0x00000080 /* collision test */
+#define CAS_PCS_CTRL_FDX 0x00000100 /* full-duplex, always 0 */
+#define CAS_PCS_CTRL_RANEG 0x00000200 /* restart auto-negotiation */
+#define CAS_PCS_CTRL_ISOLATE 0x00000400 /* isolate PHY from MII */
+#define CAS_PCS_CTRL_POWERDOWN 0x00000800 /* power down */
+#define CAS_PCS_CTRL_ANEG_EN 0x00001000 /* auto-negotiation enable */
+#define CAS_PCS_CTRL_10_100M 0x00002000 /* 10/100Mbps speed select */
+#define CAS_PCS_CTRL_RESET 0x00008000 /* Reset PCS. */
+
+#define CAS_PCS_STATUS_EXTCAP 0x00000001 /* extended capability */
+#define CAS_PCS_STATUS_JABBER 0x00000002 /* jabber condition detected */
+#define CAS_PCS_STATUS_LINK 0x00000004 /* link status */
+#define CAS_PCS_STATUS_ANEG_ABL 0x00000008 /* auto-negotiation ability */
+#define CAS_PCS_STATUS_REM_FLT 0x00000010 /* remote fault detected */
+#define CAS_PCS_STATUS_ANEG_CPT 0x00000020 /* auto-negotiate complete */
+#define CAS_PCS_STATUS_EXTENDED 0x00000100 /* extended status */
+
+/* CAS_PCS_ANAR and CAS_PCS_ANLPAR register bits */
+#define CAS_PCS_ANEG_FDX 0x00000020 /* full-duplex */
+#define CAS_PCS_ANEG_HDX 0x00000040 /* half-duplex */
+#define CAS_PCS_ANEG_PAUSE 0x00000080 /* symmetric PAUSE */
+#define CAS_PCS_ANEG_ASM_DIR 0x00000100 /* asymmetric PAUSE */
+#define CAS_PCS_ANEG_RFLT_FAIL 0x00001000 /* remote fault - fail */
+#define CAS_PCS_ANEG_RFLT_OFF 0x00002000 /* remote fault - off-line */
+#define CAS_PCS_ANEG_RFLT_MASK \
+ (CAS_PCS_ANEG_RFLT_FAIL | CAS_PCS_ANEG_RFLT_OFF)
+#define CAS_PCS_ANEG_ACK 0x00004000 /* acknowledge */
+#define CAS_PCS_ANEG_NEXT_PAGE 0x00008000 /* next page */
+
+#define CAS_PCS_CONF_EN 0x00000001 /* Enable PCS. */
+#define CAS_PCS_CONF_SDO 0x00000002 /* signal detect override */
+#define CAS_PCS_CONF_SDL 0x00000004 /* signal detect active-low */
+#define CAS_PCS_CONF_JS_NORM 0x00000000 /* jitter study - normal op. */
+#define CAS_PCS_CONF_JS_HF 0x00000008 /* jitter study - HF test */
+#define CAS_PCS_CONF_JS_LF 0x00000010 /* jitter study - LF test */
+#define CAS_PCS_CONF_JS_MASK (CAS_PCS_CONF_JS_HF | CAS_PCS_CONF_JS_LF)
+#define CAS_PCS_CONF_ANEG_TO 0x00000020 /* auto-neg. timer override */
+
+#define CAS_PCS_SM_TX_CTRL_MASK 0x0000000f /* TX control state */
+#define CAS_PCS_SM_TX_CTRL_SHFT 0
+#define CAS_PCS_SM_RX_CTRL_MASK 0x000000f0 /* RX control state */
+#define CAS_PCS_SM_RX_CTRL_SHFT 4
+#define CAS_PCS_SM_WSYNC_MASK 0x00000700 /* word sync. state */
+#define CAS_PCS_SM_WSYNC_SHFT 8
+#define CAS_PCS_SM_SEQ_MASK 0x00001800 /* sequence detection state */
+#define CAS_PCS_SM_SEQ_SHFT 11
+#define CAS_PCS_SM_LINK_UP 0x00016000
+#define CAS_PCS_SM_LINK_MASK 0x0001e000 /* link configuration state */
+#define CAS_PCS_SM_LINK_SHFT 13
+#define CAS_PCS_SM_LOSS_C 0x00100000 /* link-loss due to C codes */
+#define CAS_PCS_SM_LOSS_SYNC 0x00200000 /* link-loss due to sync-loss */
+#define CAS_PCS_SM_LOS 0x00400000 /* loss of signal */
+#define CAS_PCS_SM_NLINK_BREAK 0x01000000 /* no link due to breaklink */
+#define CAS_PCS_SM_NLINK_SERDES 0x02000000 /* no link due to SERDES */
+#define CAS_PCS_SM_NLINK_C 0x04000000 /* no link due to bad C codes */
+#define CAS_PCS_SM_NLINK_SYNC 0x08000000 /* no link due to word sync. */
+#define CAS_PCS_SM_NLINK_WAIT_C 0x10000000 /* no link, waiting for ack. */
+#define CAS_PCS_SM_NLINK_NIDLE 0x20000000 /* no link due to no idle */
+
+/*
+ * CAS_PCS_INTR_STATUS has no corresponding mask register. It can only
+ * be masked with CAS_INTR_PCS_INT.
+ */
+#define CAS_PCS_INTR_LINK 0x00000004 /* link status change */
+
+#define CAS_PCS_DATAPATH_MII 0x00000001 /* GMII/MII and MAC loopback */
+#define CAS_PCS_DATAPATH_SERDES 0x00000002 /* SERDES via 10-bit */
+
+#define CAS_PCS_SERDES_CTRL_LBK 0x00000001 /* loopback at 10-bit enable */
+#define CAS_PCS_SERDES_CTRL_ESD 0x00000002 /* En. sync char. detection. */
+#define CAS_PCS_SERDES_CTRL_LR 0x00000004 /* Lock to reference clock. */
+
+#define CAS_PCS_SERDES_STATUS_T 0x00000000 /* Undergoing test. */
+#define CAS_PCS_SERDES_STATUS_L 0x00000001 /* Waiting 500us w/ lockrefn. */
+#define CAS_PCS_SERDES_STATUS_C 0x00000002 /* Waiting for comma detect. */
+#define CAS_PCS_SERDES_STATUS_S 0x00000003 /* Receive data is sync. */
+
+#define CAS_PCS_PKT_CNT_TX_MASK 0x000007ff /* TX packets */
+#define CAS_PCS_PKT_CNT_TX_SHFT 0
+#define CAS_PCS_PKT_CNT_RX_MASK 0x07ff0000 /* RX packets */
+#define CAS_PCS_PKT_CNT_RX_SHFT 16
+
+/*
+ * PCI expansion ROM runtime access
+ * Cassinis and Saturn map a 1MB space for the PCI expansion ROM as the
+ * second half of the first register bank, although they only support up
+ * to 64KB ROMs.
+ */
+#define CAS_PCI_ROM_OFFSET 0x100000
+#define CAS_PCI_ROM_SIZE 0x10000
+
+/* secondary local bus device */
+#define CAS_SEC_LBDEV_OFFSET 0x180000
+#define CAS_SEC_LBDE_SIZE 0x7ffff
+
+/* wired PHY addresses */
+#define CAS_PHYAD_INTERNAL 1
+#define CAS_PHYAD_EXTERNAL 0
+
+/* wired RX FIFO size in bytes */
+#define CAS_RX_FIFO_SIZE 16 * 1024
+
+/*
+ * descriptor ring structures
+ */
+struct cas_desc {
+ uint64_t cd_flags;
+ uint64_t cd_buf_ptr;
+};
+
+/*
+ * transmit flags
+ * CAS_TD_CKSUM_START_MASK, CAS_TD_CKSUM_STUFF_MASK, CAS_TD_CKSUM_EN and
+ * CAS_TD_INT_ME only need to be set in 1st descriptor of a frame.
+ */
+#define CAS_TD_BUF_LEN_MASK 0x0000000000003fffULL /* buffer length */
+#define CAS_TD_BUF_LEN_SHFT 0
+#define CAS_TD_CKSUM_START_MASK 0x00000000001f8000ULL /* checksum start... */
+#define CAS_TD_CKSUM_START_SHFT 15 /* ...offset */
+#define CAS_TD_CKSUM_STUFF_MASK 0x000000001fe00000ULL /* checksum stuff... */
+#define CAS_TD_CKSUM_STUFF_SHFT 21 /* ...offset */
+#define CAS_TD_CKSUM_EN 0x0000000020000000ULL /* checksum enable */
+#define CAS_TD_END_OF_FRAME 0x0000000040000000ULL /* last desc. of pkt. */
+#define CAS_TD_START_OF_FRAME 0x0000000080000000ULL /* 1st desc. of pkt. */
+#define CAS_TD_INT_ME 0x0000000100000000ULL /* intr. when in FIFO */
+#define CAS_TD_NO_CRC 0x0000000200000000ULL /* Don't insert CRC. */
+
+/* receive flags */
+#define CAS_RD_BUF_INDEX_MASK 0x0000000000003fffULL /* data buffer index */
+#define CAS_RD_BUF_INDEX_SHFT 0
+
+/*
+ * receive completion ring structure
+ */
+struct cas_rx_comp {
+ uint64_t crc_word1;
+ uint64_t crc_word2;
+ uint64_t crc_word3;
+ uint64_t crc_word4;
+};
+
+#define CAS_RC1_DATA_SIZE_MASK 0x0000000007ffe000ULL /* pkt. data length */
+#define CAS_RC1_DATA_SIZE_SHFT 13
+#define CAS_RC1_DATA_OFF_MASK 0x000001fff8000000ULL /* data buffer offset */
+#define CAS_RC1_DATA_OFF_SHFT 27
+#define CAS_RC1_DATA_INDEX_MASK 0x007ffe0000000000ULL /* data buffer index */
+#define CAS_RC1_DATA_INDEX_SHFT 41
+#define CAS_RC1_SKIP_MASK 0x0180000000000000ULL /* entries to skip */
+#define CAS_RC1_SKIP_SHFT 55
+#define CAS_RC1_RELEASE_NEXT 0x0200000000000000ULL /* last in reas. buf. */
+#define CAS_RC1_SPLIT_PKT 0x0400000000000000ULL /* used 2 reas. buf. */
+#define CAS_RC1_RELEASE_FLOW 0x0800000000000000ULL /* last pkt. of flow */
+#define CAS_RC1_RELEASE_DATA 0x1000000000000000ULL /* reas. buf. full */
+#define CAS_RC1_RELEASE_HDR 0x2000000000000000ULL /* header buf. full */
+#define CAS_RC1_TYPE_HW 0x0000000000000000ULL /* owned by hardware */
+#define CAS_RC1_TYPE_RSFB 0x4000000000000000ULL /* stale flow buf... */
+#define CAS_RC1_TYPE_RNRP 0x8000000000000000ULL /* non-reas. pkt... */
+#define CAS_RC1_TYPE_RFP 0xc000000000000000ULL /* flow packet... */
+#define CAS_RC1_TYPE_MASK CAS_RC1_TYPE_RFP /* ...release */
+#define CAS_RC1_TYPE_SHFT 62
+
+#define CAS_RC2_NEXT_INDEX_MASK 0x00000007ffe00000ULL /* next buf. of pkt. */
+#define CAS_RC2_NEXT_INDEX_SHFT 21
+#define CAS_RC2_HDR_SIZE_MASK 0x00000ff800000000ULL /* header length */
+#define CAS_RC2_HDR_SIZE_SHFT 35
+#define CAS_RC2_HDR_OFF_MASK 0x0003f00000000000ULL /* header buf. offset */
+#define CAS_RC2_HDR_OFF_SHFT 44
+#define CAS_RC2_HDR_INDEX_MASK 0xfffc000000000000ULL /* header buf. index */
+#define CAS_RC2_HDR_INDEX_SHFT 50
+
+#define CAS_RC3_SMALL_PKT 0x0000000000000001ULL /* pkt. <= 256 - SOFF */
+#define CAS_RC3_JUMBO_PKT 0x0000000000000002ULL /* pkt. > 1522 bytes */
+#define CAS_RC3_JMBHS_EN 0x0000000000000004ULL /* jmb. hdr. spl. en. */
+#define CAS_RC3_CSO_MASK 0x000000000007f000ULL /* checksum start... */
+#define CAS_RC3_CSO_SHFT 12 /* ...offset */
+#define CAS_RC3_FLOWID_MASK 0x0000000001f80000ULL /* flow ID of pkt. */
+#define CAS_RC3_FLOWID_SHFT 19
+#define CAS_RC3_OP_MASK 0x000000000e000000ULL /* opcode */
+#define CAS_RC3_OP_SHFT 25
+#define CAS_RC3_FRC_FLAG 0x0000000010000000ULL /* op. 2 batch. lkhd. */
+#define CAS_RC3_NASSIST 0x0000000020000000ULL /* no assist */
+#define CAS_RC3_LB_MASK 0x000001f800000000ULL /* load balancing key */
+#define CAS_RC3_LB_SHFT 35
+#define CAS_RC3_L3HO_MASK 0x0000fe0000000000ULL /* layer 3 hdr. off. */
+#define CAS_RC3_L3HO_SHFT 41
+#define CAS_RC3_PLUS_ENC_PKT 0x0000020000000000ULL /* IPsec AH/ESP pkt. */
+#define CAS_RC3_PLUS_L3HO_MASK 0x0000fc0000000000ULL /* layer 3 hdr. off. */
+#define CAS_RC3_PLUS_L3HO_SHFT 42
+#define CAS_RC3_SAP_MASK 0xffff000000000000ULL /* ethertype */
+#define CAS_RC3_SAP_SHFT 48
+
+#define CAS_RC4_TCP_CSUM_MASK 0x000000000000ffffULL /* TCP checksum */
+#define CAS_RC4_TCP_CSUM_SHFT 0
+#define CAS_RC4_PKT_LEN_MASK 0x000000003fff0000ULL /* entire pkt. length */
+#define CAS_RC4_PKT_LEN_SHFT 16
+#define CAS_RC4_PAM_MASK 0x00000003c0000000ULL /* mcast. addr. match */
+#define CAS_RC4_PAM_SHFT 30
+#define CAS_RC4_ZERO 0x0000080000000000ULL /* owned by software */
+#define CAS_RC4_HASH_VAL_MASK 0x0ffff00000000000ULL /* mcast. addr. hash */
+#define CAS_RC4_HASH_VAL_SHFT 44
+#define CAS_RC4_HASH_PASS 0x1000000000000000ULL /* passed hash filter */
+#define CAS_RC4_BAD 0x4000000000000000ULL /* CRC error */
+#define CAS_RC4_LEN_MMATCH 0x8000000000000000ULL /* length field mism. */
+
+#define CAS_GET(reg, bits) (((reg) & (bits ## _MASK)) >> (bits ## _SHFT))
+#define CAS_SET(val, bits) (((val) << (bits ## _SHFT)) & (bits ## _MASK))
+
+#endif
diff --git a/sys/dev/cas/if_casvar.h b/sys/dev/cas/if_casvar.h
new file mode 100644
index 0000000..0f24cca
--- /dev/null
+++ b/sys/dev/cas/if_casvar.h
@@ -0,0 +1,260 @@
+/*-
+ * Copyright (C) 2001 Eduardo Horvath.
+ * Copyright (c) 2008 Marius Strobl <marius@FreeBSD.org>
+ * 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.
+ *
+ * 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.
+ *
+ * from: NetBSD: gemvar.h,v 1.8 2002/05/15 02:36:12 matt Exp
+ * from: FreeBSD: if_gemvar.h 177560 2008-03-24 17:23:53Z marius
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IF_CASVAR_H
+#define _IF_CASVAR_H
+
+/*
+ * The page size is configurable, but needs to be at least 8k (the
+ * default) in order to also support jumbo buffers.
+ */
+#define CAS_PAGE_SIZE 8192
+
+/*
+ * Transmit descriptor ring size - this is arbitrary, but allocate
+ * enough descriptors for 64 pending transmissions and 16 segments
+ * per packet. This limit is not actually enforced (packets with
+ * more segments can be sent, depending on the busdma backend); it
+ * is however used as an estimate for the TX window size.
+ */
+#define CAS_NTXSEGS 16
+
+#define CAS_TXQUEUELEN 64
+#define CAS_NTXDESC (CAS_TXQUEUELEN * CAS_NTXSEGS)
+#define CAS_MAXTXFREE (CAS_NTXDESC - 1)
+#define CAS_NTXDESC_MASK (CAS_NTXDESC - 1)
+#define CAS_NEXTTX(x) ((x + 1) & CAS_NTXDESC_MASK)
+
+/*
+ * Receive completion ring size - we have one completion per
+ * incoming packet (though the opposite isn't necesarrily true),
+ * so this logic is a little simpler.
+ */
+#define CAS_NRXCOMP 4096
+#define CAS_NRXCOMP_MASK (CAS_NRXCOMP - 1)
+#define CAS_NEXTRXCOMP(x) ((x + 1) & CAS_NRXCOMP_MASK)
+
+/*
+ * Receive descriptor ring sizes - for Cassini+ and Saturn both
+ * rings must be at least initialized.
+ */
+#define CAS_NRXDESC 1024
+#define CAS_NRXDESC_MASK (CAS_NRXDESC - 1)
+#define CAS_NEXTRXDESC(x) ((x + 1) & CAS_NRXDESC_MASK)
+#define CAS_NRXDESC2 32
+#define CAS_NRXDESC2_MASK (CAS_NRXDESC2 - 1)
+#define CAS_NEXTRXDESC2(x) ((x + 1) & CAS_NRXDESC2_MASK)
+
+/*
+ * How many ticks to wait until to retry on a RX descriptor that is
+ * still owned by the hardware.
+ */
+#define CAS_RXOWN_TICKS (hz / 50)
+
+/*
+ * Control structures are DMA'd to the chip. We allocate them
+ * in a single clump that maps to a single DMA segment to make
+ * several things easier.
+ */
+struct cas_control_data {
+ struct cas_desc ccd_txdescs[CAS_NTXDESC]; /* TX descriptors */
+ struct cas_rx_comp ccd_rxcomps[CAS_NRXCOMP]; /* RX completions */
+ struct cas_desc ccd_rxdescs[CAS_NRXDESC]; /* RX descriptors */
+ struct cas_desc ccd_rxdescs2[CAS_NRXDESC2]; /* RX descriptors 2 */
+};
+
+#define CAS_CDOFF(x) offsetof(struct cas_control_data, x)
+#define CAS_CDTXDOFF(x) CAS_CDOFF(ccd_txdescs[(x)])
+#define CAS_CDRXCOFF(x) CAS_CDOFF(ccd_rxcomps[(x)])
+#define CAS_CDRXDOFF(x) CAS_CDOFF(ccd_rxdescs[(x)])
+#define CAS_CDRXD2OFF(x) CAS_CDOFF(ccd_rxdescs2[(x)])
+
+/*
+ * software state for transmit job mbufs (may be elements of mbuf chains)
+ */
+struct cas_txsoft {
+ struct mbuf *txs_mbuf; /* head of our mbuf chain */
+ bus_dmamap_t txs_dmamap; /* our DMA map */
+ u_int txs_firstdesc; /* first descriptor in packet */
+ u_int txs_lastdesc; /* last descriptor in packet */
+ u_int txs_ndescs; /* number of descriptors */
+ STAILQ_ENTRY(cas_txsoft) txs_q;
+};
+
+STAILQ_HEAD(cas_txsq, cas_txsoft);
+
+/*
+ * software state for receive descriptors
+ */
+struct cas_rxdsoft {
+ void *rxds_buf; /* receive buffer */
+ bus_dmamap_t rxds_dmamap; /* our DMA map */
+ bus_addr_t rxds_paddr; /* physical address of the segment */
+#if __FreeBSD_version < 800016
+ struct cas_softc *rxds_sc; /* softc pointer */
+ u_int rxds_idx; /* our index */
+#endif
+ u_int rxds_refcount; /* hardware + mbuf references */
+};
+
+/*
+ * software state per device
+ */
+struct cas_softc {
+ struct ifnet *sc_ifp;
+ struct mtx sc_mtx;
+ device_t sc_miibus;
+ struct mii_data *sc_mii; /* MII media control */
+ device_t sc_dev; /* generic device information */
+ u_char sc_enaddr[ETHER_ADDR_LEN];
+ struct callout sc_tick_ch; /* tick callout */
+ struct callout sc_rx_ch; /* delayed RX callout */
+ u_int sc_wdog_timer; /* watchdog timer */
+
+ void *sc_ih;
+ struct resource *sc_res[2];
+#define CAS_RES_INTR 0
+#define CAS_RES_MEM 1
+
+ bus_dma_tag_t sc_pdmatag; /* parent bus DMA tag */
+ bus_dma_tag_t sc_rdmatag; /* RX bus DMA tag */
+ bus_dma_tag_t sc_tdmatag; /* TX bus DMA tag */
+ bus_dma_tag_t sc_cdmatag; /* control data bus DMA tag */
+ bus_dmamap_t sc_dmamap; /* bus DMA handle */
+
+ u_int sc_phyad; /* PHY to use or -1 for any */
+
+ u_int sc_variant;
+#define CAS_UNKNOWN 0 /* don't know */
+#define CAS_CAS 1 /* Sun Cassini */
+#define CAS_CASPLUS 2 /* Sun Cassini+ */
+#define CAS_SATURN 3 /* National Semiconductor Saturn */
+
+ u_int sc_flags;
+#define CAS_INITED (1 << 0) /* reset persistent regs init'ed */
+#define CAS_NO_CSUM (1 << 1) /* don't use hardware checksumming */
+#define CAS_LINK (1 << 2) /* link is up */
+#define CAS_REG_PLUS (1 << 3) /* has Cassini+ registers */
+#define CAS_SERDES (1 << 4) /* use the SERDES */
+#define CAS_TABORT (1 << 5) /* has target abort issues */
+
+ bus_dmamap_t sc_cddmamap; /* control data DMA map */
+ bus_addr_t sc_cddma;
+
+ /*
+ * software state for transmit and receive descriptors
+ */
+ struct cas_txsoft sc_txsoft[CAS_TXQUEUELEN];
+ struct cas_rxdsoft sc_rxdsoft[CAS_NRXDESC];
+
+ /*
+ * control data structures
+ */
+ struct cas_control_data *sc_control_data;
+#define sc_txdescs sc_control_data->ccd_txdescs
+#define sc_rxcomps sc_control_data->ccd_rxcomps
+#define sc_rxdescs sc_control_data->ccd_rxdescs
+#define sc_rxdescs2 sc_control_data->ccd_rxdescs2
+
+ u_int sc_txfree; /* number of free TX descriptors */
+ u_int sc_txnext; /* next ready TX descriptor */
+ u_int sc_txwin; /* TX desc. since last TX intr. */
+
+ struct cas_txsq sc_txfreeq; /* free software TX descriptors */
+ struct cas_txsq sc_txdirtyq; /* dirty software TX descriptors */
+
+ u_int sc_rxcptr; /* next ready RX completion */
+ u_int sc_rxdptr; /* next ready RX descriptor */
+
+ int sc_ifflags;
+};
+
+#define CAS_BARRIER(sc, offs, len, flags) \
+ bus_barrier((sc)->sc_res[CAS_RES_MEM], (offs), (len), (flags))
+
+#define CAS_READ_N(n, sc, offs) \
+ bus_read_ ## n((sc)->sc_res[CAS_RES_MEM], (offs))
+#define CAS_READ_1(sc, offs) CAS_READ_N(1, (sc), (offs))
+#define CAS_READ_2(sc, offs) CAS_READ_N(2, (sc), (offs))
+#define CAS_READ_4(sc, offs) CAS_READ_N(4, (sc), (offs))
+
+#define CAS_WRITE_N(n, sc, offs, v) \
+ bus_write_ ## n((sc)->sc_res[CAS_RES_MEM], (offs), (v))
+#define CAS_WRITE_1(sc, offs, v) CAS_WRITE_N(1, (sc), (offs), (v))
+#define CAS_WRITE_2(sc, offs, v) CAS_WRITE_N(2, (sc), (offs), (v))
+#define CAS_WRITE_4(sc, offs, v) CAS_WRITE_N(4, (sc), (offs), (v))
+
+#define CAS_CDTXDADDR(sc, x) ((sc)->sc_cddma + CAS_CDTXDOFF((x)))
+#define CAS_CDRXCADDR(sc, x) ((sc)->sc_cddma + CAS_CDRXCOFF((x)))
+#define CAS_CDRXDADDR(sc, x) ((sc)->sc_cddma + CAS_CDRXDOFF((x)))
+#define CAS_CDRXD2ADDR(sc, x) ((sc)->sc_cddma + CAS_CDRXD2OFF((x)))
+
+#define CAS_CDSYNC(sc, ops) \
+ bus_dmamap_sync((sc)->sc_cdmatag, (sc)->sc_cddmamap, (ops));
+
+#define __CAS_UPDATE_RXDESC(rxd, rxds, s) \
+do { \
+ \
+ refcount_init(&(rxds)->rxds_refcount, 1); \
+ (rxd)->cd_buf_ptr = htole64((rxds)->rxds_paddr); \
+ KASSERT((s) < CAS_RD_BUF_INDEX_MASK >> CAS_RD_BUF_INDEX_SHFT, \
+ ("%s: RX buffer index too large!", __func__)); \
+ (rxd)->cd_flags = \
+ htole64((uint64_t)((s) << CAS_RD_BUF_INDEX_SHFT)); \
+} while (0)
+
+#define CAS_UPDATE_RXDESC(sc, d, s) \
+ __CAS_UPDATE_RXDESC(&(sc)->sc_rxdescs[(d)], \
+ &(sc)->sc_rxdsoft[(s)], (s))
+
+#if __FreeBSD_version < 800016
+#define CAS_INIT_RXDESC(sc, d, s) \
+do { \
+ struct cas_rxdsoft *__rxds = &(sc)->sc_rxdsoft[(s)]; \
+ \
+ __rxds->rxds_sc = (sc); \
+ __rxds->rxds_idx = (s); \
+ __CAS_UPDATE_RXDESC(&(sc)->sc_rxdescs[(d)], __rxds, (s)); \
+} while (0)
+#else
+#define CAS_INIT_RXDESC(sc, d, s) CAS_UPDATE_RXDESC(sc, d, s)
+#endif
+
+#define CAS_LOCK_INIT(_sc, _name) \
+ mtx_init(&(_sc)->sc_mtx, _name, MTX_NETWORK_LOCK, MTX_DEF)
+#define CAS_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
+#define CAS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
+#define CAS_LOCK_ASSERT(_sc, _what) mtx_assert(&(_sc)->sc_mtx, (_what))
+#define CAS_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx)
+#define CAS_LOCK_OWNED(_sc) mtx_owned(&(_sc)->sc_mtx)
+
+#endif
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index f789521..4b09df0 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -43,6 +43,7 @@ SUBDIR= ${_3dfx} \
${_canbepm} \
${_canbus} \
${_cardbus} \
+ cas \
${_cbb} \
cd9660 \
cd9660_iconv \
diff --git a/sys/modules/cas/Makefile b/sys/modules/cas/Makefile
new file mode 100644
index 0000000..f4b41ca
--- /dev/null
+++ b/sys/modules/cas/Makefile
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/cas
+
+KMOD= if_cas
+SRCS= bus_if.h device_if.h if_cas.c miibus_if.h pci_if.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/sparc64/conf/GENERIC b/sys/sparc64/conf/GENERIC
index 943dc74..999cc78 100644
--- a/sys/sparc64/conf/GENERIC
+++ b/sys/sparc64/conf/GENERIC
@@ -174,6 +174,7 @@ device txp # 3Com 3cR990 (``Typhoon'')
device miibus # MII bus support
#device bfe # Broadcom BCM440x 10/100 Ethernet
device bge # Broadcom BCM570xx Gigabit Ethernet
+device cas # Sun Cassini/Cassini+ and NS DP83065 Saturn
device dc # DEC/Intel 21143 and various workalikes
device fxp # Intel EtherExpress PRO/100B (82557, 82558)
device gem # Sun GEM/Sun ERI/Apple GMAC
OpenPOWER on IntegriCloud