? ID
? arch/i386/compile/GENERIC
? arch/i386/compile/MSKDEV
? arch/i386/compile/YKDEV
? arch/i386/conf/MSK.local
? arch/i386/conf/MSKDEV
? arch/i386/conf/YK.local
? arch/i386/conf/YKDEV
? dev/pci/if_yk.c
? dev/pci/if_ykreg.h
? dev/pci/if_ykvar.h
Index: dev/pci/files.pci
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/files.pci,v
retrieving revision 1.267
diff -u -r1.267 files.pci
--- dev/pci/files.pci	7 Sep 2006 12:34:42 -0000	1.267
+++ dev/pci/files.pci	9 Sep 2006 03:26:22 -0000
@@ -839,3 +839,10 @@
 device	kse: ether, ifnet, arp
 attach	kse at pci
 file	dev/pci/if_kse.c		kse
+
+# Yukon 2
+device	mskc { }
+attach	mskc at pci
+device	msk: ether, ifnet, arp, mii
+attach	msk at mskc
+file	dev/pci/if_msk.c		mskc | msk
Index: dev/pci/if_msk.c
===================================================================
RCS file: dev/pci/if_msk.c
diff -N dev/pci/if_msk.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ dev/pci/if_msk.c	9 Sep 2006 03:26:23 -0000
@@ -0,0 +1,2289 @@
+/* $NetBSD$ */
+/*	$OpenBSD: if_msk.c,v 1.11 2006/08/17 22:07:40 brad Exp $	*/
+
+/*
+ * Copyright (c) 1997, 1998, 1999, 2000
+ *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * 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.
+ *
+ * $FreeBSD: /c/ncvs/src/sys/pci/if_sk.c,v 1.20 2000/04/22 02:16:37 wpaul Exp $
+ */
+
+/*
+ * Copyright (c) 2003 Nathan L. Binkert <binkertn@umich.edu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "bpfilter.h"
+#include "rnd.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/malloc.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/device.h>
+#include <sys/queue.h>
+#include <sys/sysctl.h>
+#include <sys/endian.h>
+#ifdef __NetBSD__
+ #define letoh16 htole16
+ #define letoh32 htole32
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+
+#include <net/if_media.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+#if NRND > 0
+#include <sys/rnd.h>
+#endif
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+#include <dev/mii/brgphyreg.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/pci/if_skreg.h>
+#include <dev/pci/if_mskvar.h>
+
+int mskc_probe(struct device *, struct cfdata *, void *);
+void mskc_attach(struct device *, struct device *self, void *aux);
+void mskc_shutdown(void *);
+int msk_probe(struct device *, struct cfdata *, void *);
+void msk_attach(struct device *, struct device *self, void *aux);
+int mskcprint(void *, const char *);
+int msk_intr(void *);
+void msk_intr_yukon(struct sk_if_softc *);
+__inline int msk_rxvalid(struct sk_softc *, u_int32_t, u_int32_t);
+void msk_rxeof(struct sk_if_softc *, u_int16_t, u_int32_t);
+void msk_txeof(struct sk_if_softc *);
+int msk_encap(struct sk_if_softc *, struct mbuf *, u_int32_t *);
+void msk_start(struct ifnet *);
+int msk_ioctl(struct ifnet *, u_long, caddr_t);
+int msk_init(struct ifnet *);
+void msk_init_yukon(struct sk_if_softc *);
+void msk_stop(struct ifnet *, int);
+void msk_watchdog(struct ifnet *);
+int msk_ifmedia_upd(struct ifnet *);
+void msk_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+void msk_reset(struct sk_softc *);
+int msk_newbuf(struct sk_if_softc *, int, struct mbuf *, bus_dmamap_t);
+int msk_alloc_jumbo_mem(struct sk_if_softc *);
+void *msk_jalloc(struct sk_if_softc *);
+void msk_jfree(struct mbuf *, caddr_t, size_t, void *);
+int msk_init_rx_ring(struct sk_if_softc *);
+int msk_init_tx_ring(struct sk_if_softc *);
+
+void msk_update_int_mod(struct sk_softc *);
+
+int msk_marv_miibus_readreg(struct device *, int, int);
+void msk_marv_miibus_writereg(struct device *, int, int, int);
+void msk_marv_miibus_statchg(struct device *);
+
+u_int32_t msk_yukon_hash(caddr_t);
+void msk_setfilt(struct sk_if_softc *, caddr_t, int);
+void msk_setmulti(struct sk_if_softc *);
+void msk_setpromisc(struct sk_if_softc *);
+void msk_yukon_tick(void *);
+
+#define MSK_DEBUG 1
+#ifdef MSK_DEBUG
+#define DPRINTF(x)	if (mskdebug) printf x
+#define DPRINTFN(n,x)	if (mskdebug >= (n)) printf x
+int	mskdebug = MSK_DEBUG;
+
+void msk_dump_txdesc(struct msk_tx_desc *, int);
+void msk_dump_mbuf(struct mbuf *);
+void msk_dump_bytes(const char *, int);
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+static int msk_sysctl_handler(SYSCTLFN_PROTO);
+static int msk_root_num;
+
+/* supported device vendors */
+static const struct msk_product {
+        pci_vendor_id_t         msk_vendor;
+        pci_product_id_t        msk_product;
+} msk_products[] = {
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKON_8035 },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKON_8036 },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKON_8038 },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKON_8052 },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKON_8050 },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKON_8053 },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKONII_8021CU },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKONII_8022CU },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKONII_8021X },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKONII_8022X },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKONII_8061CU },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKONII_8062CU },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKONII_8061X },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKONII_8062X },
+	{ PCI_VENDOR_MARVELL,		PCI_PRODUCT_MARVELL_YUKON_3 },
+	{ PCI_VENDOR_SCHNEIDERKOCH,	PCI_PRODUCT_SCHNEIDERKOCH_SK_9SXX },
+	{ PCI_VENDOR_SCHNEIDERKOCH,	PCI_PRODUCT_SCHNEIDERKOCH_SK_9E21 }
+};
+
+static inline u_int32_t
+sk_win_read_4(struct sk_softc *sc, u_int32_t reg)
+{
+	return CSR_READ_4(sc, reg);
+}
+
+static inline u_int16_t
+sk_win_read_2(struct sk_softc *sc, u_int32_t reg)
+{
+	return CSR_READ_2(sc, reg);
+}
+
+static inline u_int8_t
+sk_win_read_1(struct sk_softc *sc, u_int32_t reg)
+{
+	return CSR_READ_1(sc, reg);
+}
+
+static inline void
+sk_win_write_4(struct sk_softc *sc, u_int32_t reg, u_int32_t x)
+{
+	CSR_WRITE_4(sc, reg, x);
+}
+
+static inline void
+sk_win_write_2(struct sk_softc *sc, u_int32_t reg, u_int16_t x)
+{
+	CSR_WRITE_2(sc, reg, x);
+}
+
+static inline void
+sk_win_write_1(struct sk_softc *sc, u_int32_t reg, u_int8_t x)
+{
+	CSR_WRITE_1(sc, reg, x);
+}
+
+int
+msk_marv_miibus_readreg(struct device *dev, int phy, int reg)
+{
+	struct sk_if_softc *sc_if = (struct sk_if_softc *)dev;
+	u_int16_t val;
+	int i;
+
+	if (phy != 0 ||
+	    (sc_if->sk_phytype != SK_PHYTYPE_MARV_COPPER &&
+	     sc_if->sk_phytype != SK_PHYTYPE_MARV_FIBER)) {
+		DPRINTFN(9, ("msk_marv_miibus_readreg (skip) phy=%d, reg=%#x\n",
+			     phy, reg));
+		return (0);
+	}
+
+        SK_YU_WRITE_2(sc_if, YUKON_SMICR, YU_SMICR_PHYAD(phy) |
+		      YU_SMICR_REGAD(reg) | YU_SMICR_OP_READ);
+        
+	for (i = 0; i < SK_TIMEOUT; i++) {
+		DELAY(1);
+		val = SK_YU_READ_2(sc_if, YUKON_SMICR);
+		if (val & YU_SMICR_READ_VALID)
+			break;
+	}
+
+	if (i == SK_TIMEOUT) {
+		aprint_error("%s: phy failed to come ready\n",
+		       sc_if->sk_dev.dv_xname);
+		return (0);
+	}
+        
+ 	DPRINTFN(9, ("msk_marv_miibus_readreg: i=%d, timeout=%d\n", i,
+		     SK_TIMEOUT));
+
+        val = SK_YU_READ_2(sc_if, YUKON_SMIDR);
+
+	DPRINTFN(9, ("msk_marv_miibus_readreg phy=%d, reg=%#x, val=%#x\n",
+		     phy, reg, val));
+
+	return (val);
+}
+
+void
+msk_marv_miibus_writereg(struct device *dev, int phy, int reg, int val)
+{
+	struct sk_if_softc *sc_if = (struct sk_if_softc *)dev;
+	int i;
+
+	DPRINTFN(9, ("msk_marv_miibus_writereg phy=%d reg=%#x val=%#x\n",
+		     phy, reg, val));
+
+	SK_YU_WRITE_2(sc_if, YUKON_SMIDR, val);
+	SK_YU_WRITE_2(sc_if, YUKON_SMICR, YU_SMICR_PHYAD(phy) |
+		      YU_SMICR_REGAD(reg) | YU_SMICR_OP_WRITE);
+
+	for (i = 0; i < SK_TIMEOUT; i++) {
+		DELAY(1);
+		if (SK_YU_READ_2(sc_if, YUKON_SMICR) & YU_SMICR_BUSY)
+			break;
+	}
+
+	if (i == SK_TIMEOUT)
+		aprint_error("%s: phy write timed out\n", sc_if->sk_dev.dv_xname);
+}
+
+void
+msk_marv_miibus_statchg(struct device *dev)
+{
+	DPRINTFN(9, ("msk_marv_miibus_statchg: gpcr=%x\n",
+		     SK_YU_READ_2(((struct sk_if_softc *)dev), YUKON_GPCR)));
+}
+
+#define HASH_BITS	6
+  
+u_int32_t
+msk_yukon_hash(caddr_t addr)
+{
+	u_int32_t crc;
+
+	crc = ether_crc32_be(addr, ETHER_ADDR_LEN);
+	return (crc & ((1 << HASH_BITS) - 1));
+}
+
+void
+msk_setfilt(struct sk_if_softc *sc_if, caddr_t addr, int slot)
+{
+	int base = XM_RXFILT_ENTRY(slot);
+
+	SK_XM_WRITE_2(sc_if, base, *(u_int16_t *)(&addr[0]));
+	SK_XM_WRITE_2(sc_if, base + 2, *(u_int16_t *)(&addr[2]));
+	SK_XM_WRITE_2(sc_if, base + 4, *(u_int16_t *)(&addr[4]));
+}
+
+void
+msk_setmulti(struct sk_if_softc *sc_if)
+{
+	struct ifnet *ifp= &sc_if->sk_ethercom.ec_if;
+	u_int32_t hashes[2] = { 0, 0 };
+	int h;
+	struct ethercom *ec = &sc_if->sk_ethercom;
+	struct ether_multi *enm;
+	struct ether_multistep step;
+
+	/* First, zot all the existing filters. */
+	SK_YU_WRITE_2(sc_if, YUKON_MCAH1, 0);
+	SK_YU_WRITE_2(sc_if, YUKON_MCAH2, 0);
+	SK_YU_WRITE_2(sc_if, YUKON_MCAH3, 0);
+	SK_YU_WRITE_2(sc_if, YUKON_MCAH4, 0);
+
+
+	/* Now program new ones. */
+allmulti:
+	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
+		hashes[0] = 0xFFFFFFFF;
+		hashes[1] = 0xFFFFFFFF;
+	} else {
+		/* First find the tail of the list. */
+		ETHER_FIRST_MULTI(step, ec, enm);
+		while (enm != NULL) {
+			if (bcmp(enm->enm_addrlo, enm->enm_addrhi,
+				 ETHER_ADDR_LEN)) {
+				ifp->if_flags |= IFF_ALLMULTI;
+				goto allmulti;
+			}
+			h = msk_yukon_hash(enm->enm_addrlo);
+			if (h < 32)
+				hashes[0] |= (1 << h);
+			else
+				hashes[1] |= (1 << (h - 32));
+
+			ETHER_NEXT_MULTI(step, enm);
+		}
+	}
+
+	SK_YU_WRITE_2(sc_if, YUKON_MCAH1, hashes[0] & 0xffff);
+	SK_YU_WRITE_2(sc_if, YUKON_MCAH2, (hashes[0] >> 16) & 0xffff);
+	SK_YU_WRITE_2(sc_if, YUKON_MCAH3, hashes[1] & 0xffff);
+	SK_YU_WRITE_2(sc_if, YUKON_MCAH4, (hashes[1] >> 16) & 0xffff);
+}
+
+void
+msk_setpromisc(struct sk_if_softc *sc_if)
+{
+	struct ifnet *ifp = &sc_if->sk_ethercom.ec_if;
+
+	if (ifp->if_flags & IFF_PROMISC)
+		SK_YU_CLRBIT_2(sc_if, YUKON_RCR,
+		    YU_RCR_UFLEN | YU_RCR_MUFLEN);
+	else
+		SK_YU_SETBIT_2(sc_if, YUKON_RCR,
+		    YU_RCR_UFLEN | YU_RCR_MUFLEN);
+}
+
+int
+msk_init_rx_ring(struct sk_if_softc *sc_if)
+{
+	struct msk_chain_data	*cd = &sc_if->sk_cdata;
+	struct msk_ring_data	*rd = sc_if->sk_rdata;
+	int			i, nexti;
+
+	bzero((char *)rd->sk_rx_ring,
+	    sizeof(struct msk_rx_desc) * MSK_RX_RING_CNT);
+
+	for (i = 0; i < MSK_RX_RING_CNT; i++) {
+		cd->sk_rx_chain[i].sk_le = &rd->sk_rx_ring[i];
+		if (i == (MSK_RX_RING_CNT - 1))
+			nexti = 0;
+		else
+			nexti = i + 1;
+		cd->sk_rx_chain[i].sk_next = &cd->sk_rx_chain[nexti];
+	}
+
+	for (i = 0; i < MSK_RX_RING_CNT; i++) {
+		if (msk_newbuf(sc_if, i, NULL,
+		    sc_if->sk_cdata.sk_rx_jumbo_map) == ENOBUFS) {
+			aprint_error("%s: failed alloc of %dth mbuf\n",
+			    sc_if->sk_dev.dv_xname, i);
+			return (ENOBUFS);
+		}
+	}
+
+	sc_if->sk_cdata.sk_rx_prod = MSK_RX_RING_CNT - 1;
+	sc_if->sk_cdata.sk_rx_cons = 0;
+
+	return (0);
+}
+
+int
+msk_init_tx_ring(struct sk_if_softc *sc_if)
+{
+	struct sk_softc		*sc = sc_if->sk_softc;
+	struct msk_chain_data	*cd = &sc_if->sk_cdata;
+	struct msk_ring_data	*rd = sc_if->sk_rdata;
+	bus_dmamap_t		dmamap;
+	struct sk_txmap_entry	*entry;
+	int			i, nexti;
+
+	bzero((char *)sc_if->sk_rdata->sk_tx_ring,
+	    sizeof(struct msk_tx_desc) * MSK_TX_RING_CNT);
+
+	SIMPLEQ_INIT(&sc_if->sk_txmap_head);
+	for (i = 0; i < MSK_TX_RING_CNT; i++) {
+		cd->sk_tx_chain[i].sk_le = &rd->sk_tx_ring[i];
+		if (i == (MSK_TX_RING_CNT - 1))
+			nexti = 0;
+		else
+			nexti = i + 1;
+		cd->sk_tx_chain[i].sk_next = &cd->sk_tx_chain[nexti];
+
+		if (bus_dmamap_create(sc->sc_dmatag, SK_JLEN, SK_NTXSEG,
+		   SK_JLEN, 0, BUS_DMA_NOWAIT, &dmamap))
+			return (ENOBUFS);
+
+		entry = malloc(sizeof(*entry), M_DEVBUF, M_NOWAIT);
+		if (!entry) {
+			bus_dmamap_destroy(sc->sc_dmatag, dmamap);
+			return (ENOBUFS);
+		}
+		entry->dmamap = dmamap;
+		SIMPLEQ_INSERT_HEAD(&sc_if->sk_txmap_head, entry, link);
+	}
+
+	sc_if->sk_cdata.sk_tx_prod = 0;
+	sc_if->sk_cdata.sk_tx_cons = 0;
+	sc_if->sk_cdata.sk_tx_cnt = 0;
+
+	MSK_CDTXSYNC(sc_if, 0, MSK_TX_RING_CNT,
+	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+	return (0);
+}
+
+int
+msk_newbuf(struct sk_if_softc *sc_if, int i, struct mbuf *m,
+	  bus_dmamap_t dmamap)
+{
+	struct mbuf		*m_new = NULL;
+	struct sk_chain		*c;
+	struct msk_rx_desc	*r;
+
+	if (m == NULL) {
+		caddr_t buf = NULL;
+
+		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
+		if (m_new == NULL)
+			return (ENOBUFS);
+		
+		/* Allocate the jumbo buffer */
+		buf = msk_jalloc(sc_if);
+		if (buf == NULL) {
+			m_freem(m_new);
+			DPRINTFN(1, ("%s jumbo allocation failed -- packet "
+			    "dropped!\n", sc_if->sk_ethercom.ec_if.if_xname));
+			return (ENOBUFS);
+		}
+
+		/* Attach the buffer to the mbuf */
+		m_new->m_len = m_new->m_pkthdr.len = SK_JLEN;
+		MEXTADD(m_new, buf, SK_JLEN, 0, msk_jfree, sc_if);
+	} else {
+		/*
+	 	 * We're re-using a previously allocated mbuf;
+		 * be sure to re-init pointers and lengths to
+		 * default values.
+		 */
+		m_new = m;
+		m_new->m_len = m_new->m_pkthdr.len = SK_JLEN;
+		m_new->m_data = m_new->m_ext.ext_buf;
+	}
+	m_adj(m_new, ETHER_ALIGN);
+
+	c = &sc_if->sk_cdata.sk_rx_chain[i];
+	r = c->sk_le;
+	c->sk_mbuf = m_new;
+	r->sk_addr = htole32(dmamap->dm_segs[0].ds_addr +
+	    (((vaddr_t)m_new->m_data
+             - (vaddr_t)sc_if->sk_cdata.sk_jumbo_buf)));
+	r->sk_len = htole16(SK_JLEN);
+	r->sk_ctl = 0;
+	r->sk_opcode = SK_Y2_RXOPC_PACKET | SK_Y2_RXOPC_OWN;
+
+	MSK_CDRXSYNC(sc_if, i, BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
+
+	return (0);
+}
+
+/*
+ * Memory management for jumbo frames.
+ */
+
+int
+msk_alloc_jumbo_mem(struct sk_if_softc *sc_if)
+{
+	struct sk_softc		*sc = sc_if->sk_softc;
+	caddr_t			ptr, kva;
+	bus_dma_segment_t	seg;
+	int		i, rseg, state, error;
+	struct sk_jpool_entry   *entry;
+
+	state = error = 0;
+
+	/* Grab a big chunk o' storage. */
+	if (bus_dmamem_alloc(sc->sc_dmatag, MSK_JMEM, PAGE_SIZE, 0,
+			     &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
+		aprint_error(": can't alloc rx buffers");
+		return (ENOBUFS);
+	}
+
+	state = 1;
+	if (bus_dmamem_map(sc->sc_dmatag, &seg, rseg, MSK_JMEM, &kva,
+			   BUS_DMA_NOWAIT)) {
+		aprint_error(": can't map dma buffers (%d bytes)", MSK_JMEM);
+		error = ENOBUFS;
+		goto out;
+	}
+
+	state = 2;
+	if (bus_dmamap_create(sc->sc_dmatag, MSK_JMEM, 1, MSK_JMEM, 0,
+	    BUS_DMA_NOWAIT, &sc_if->sk_cdata.sk_rx_jumbo_map)) {
+		aprint_error(": can't create dma map");
+		error = ENOBUFS;
+		goto out;
+	}
+
+	state = 3;
+	if (bus_dmamap_load(sc->sc_dmatag, sc_if->sk_cdata.sk_rx_jumbo_map,
+			    kva, MSK_JMEM, NULL, BUS_DMA_NOWAIT)) {
+		aprint_error(": can't load dma map");
+		error = ENOBUFS;
+		goto out;
+	}
+
+	state = 4;
+	sc_if->sk_cdata.sk_jumbo_buf = (caddr_t)kva;
+	DPRINTFN(1,("msk_jumbo_buf = %p\n", (caddr_t)sc_if->sk_cdata.sk_jumbo_buf));
+
+	LIST_INIT(&sc_if->sk_jfree_listhead);
+	LIST_INIT(&sc_if->sk_jinuse_listhead);
+
+	/*
+	 * Now divide it up into 9K pieces and save the addresses
+	 * in an array.
+	 */
+	ptr = sc_if->sk_cdata.sk_jumbo_buf;
+	for (i = 0; i < MSK_JSLOTS; i++) {
+		sc_if->sk_cdata.sk_jslots[i] = ptr;
+		ptr += SK_JLEN;
+		entry = malloc(sizeof(struct sk_jpool_entry),
+		    M_DEVBUF, M_NOWAIT);
+		if (entry == NULL) {
+			aprint_error(": no memory for jumbo buffer queue!");
+			error = ENOBUFS;
+			goto out;
+		}
+		entry->slot = i;
+		if (i)
+			LIST_INSERT_HEAD(&sc_if->sk_jfree_listhead,
+				 entry, jpool_entries);
+		else
+			LIST_INSERT_HEAD(&sc_if->sk_jinuse_listhead,
+				 entry, jpool_entries);
+	}
+out:
+	if (error != 0) {
+		switch (state) {
+		case 4:
+			bus_dmamap_unload(sc->sc_dmatag,
+			    sc_if->sk_cdata.sk_rx_jumbo_map);
+		case 3:
+			bus_dmamap_destroy(sc->sc_dmatag,
+			    sc_if->sk_cdata.sk_rx_jumbo_map);
+		case 2:
+			bus_dmamem_unmap(sc->sc_dmatag, kva, MSK_JMEM);
+		case 1:
+			bus_dmamem_free(sc->sc_dmatag, &seg, rseg);
+			break;
+		default:
+			break;
+		}
+	}
+
+	return (error);
+}
+
+/*
+ * Allocate a jumbo buffer.
+ */
+void *
+msk_jalloc(struct sk_if_softc *sc_if)
+{
+	struct sk_jpool_entry   *entry;
+
+	entry = LIST_FIRST(&sc_if->sk_jfree_listhead);
+
+	if (entry == NULL)
+		return (NULL);
+
+	LIST_REMOVE(entry, jpool_entries);
+	LIST_INSERT_HEAD(&sc_if->sk_jinuse_listhead, entry, jpool_entries);
+	return (sc_if->sk_cdata.sk_jslots[entry->slot]);
+}
+
+/*
+ * Release a jumbo buffer.
+ */
+void
+msk_jfree(struct mbuf *m, caddr_t buf, size_t size, void *arg)
+{
+	struct sk_jpool_entry *entry;
+	struct sk_if_softc *sc;
+	int i, s;
+
+	/* Extract the softc struct pointer. */
+	sc = (struct sk_if_softc *)arg;
+
+	if (sc == NULL)
+		panic("msk_jfree: can't find softc pointer!");
+
+	/* calculate the slot this buffer belongs to */
+
+	i = ((vaddr_t)buf
+	     - (vaddr_t)sc->sk_cdata.sk_jumbo_buf) / SK_JLEN;
+
+	if ((i < 0) || (i >= MSK_JSLOTS))
+		panic("sk_jfree: asked to free buffer that we don't manage!");
+
+	s = splvm();
+	entry = LIST_FIRST(&sc->sk_jinuse_listhead);
+	if (entry == NULL)
+		panic("msk_jfree: buffer not in use!");
+	entry->slot = i;
+	LIST_REMOVE(entry, jpool_entries);
+	LIST_INSERT_HEAD(&sc->sk_jfree_listhead, entry, jpool_entries);
+
+	if (__predict_true(m != NULL))
+		pool_cache_put(&mbpool_cache, m);
+	splx(s);
+}
+
+/*
+ * Set media options.
+ */
+int
+msk_ifmedia_upd(struct ifnet *ifp)
+{
+	struct sk_if_softc *sc_if = ifp->if_softc;
+
+	msk_init(ifp);
+	mii_mediachg(&sc_if->sk_mii);
+	return (0);
+}
+
+/*
+ * Report current media status.
+ */
+void
+msk_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+	struct sk_if_softc *sc_if = ifp->if_softc;
+
+	mii_pollstat(&sc_if->sk_mii);
+	ifmr->ifm_active = sc_if->sk_mii.mii_media_active;
+	ifmr->ifm_status = sc_if->sk_mii.mii_media_status;
+}
+
+int
+msk_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
+{
+	struct sk_if_softc *sc_if = ifp->if_softc;
+	struct ifreq *ifr = (struct ifreq *) data;
+	struct mii_data *mii;
+	int s, error = 0;
+
+	s = splnet();
+
+	switch(command) {
+	case SIOCGIFMEDIA:
+	case SIOCSIFMEDIA:
+		DPRINTFN(2,("msk_ioctl: SIOC[GS]IFMEDIA\n"));
+		mii = &sc_if->sk_mii;
+		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
+		DPRINTFN(2,("msk_ioctl: SIOC[GS]IFMEDIA done\n"));
+		break;
+	default:
+		DPRINTFN(2, ("msk_ioctl ETHER\n"));
+		error = ether_ioctl(ifp, command, data);
+
+		if (error == ENETRESET) {
+			/*
+			 * Multicast list has changed; set the hardware
+			 * filter accordingly.
+			 */
+			if (ifp->if_flags & IFF_RUNNING)
+				msk_setmulti(sc_if);
+			error = 0;
+		}
+		break;
+	}
+
+	splx(s);
+	return (error);
+}
+
+void
+msk_update_int_mod(struct sk_softc *sc)
+{
+	u_int32_t sk_imtimer_ticks;
+
+	/*
+ 	 * Configure interrupt moderation. The moderation timer
+	 * defers interrupts specified in the interrupt moderation
+	 * timer mask based on the timeout specified in the interrupt
+	 * moderation timer init register. Each bit in the timer
+	 * register represents one tick, so to specify a timeout in
+	 * microseconds, we have to multiply by the correct number of
+	 * ticks-per-microsecond.
+	 */
+	switch (sc->sk_type) {
+	case SK_YUKON_EC:
+		sk_imtimer_ticks = SK_IMTIMER_TICKS_YUKON_EC;
+		break;
+	default:
+		sk_imtimer_ticks = SK_IMTIMER_TICKS_YUKON;
+	}
+	aprint_verbose("%s: interrupt moderation is %d us\n",
+	    sc->sk_dev.dv_xname, sc->sk_int_mod);
+        sk_win_write_4(sc, SK_IMTIMERINIT, SK_IM_USECS(sc->sk_int_mod));
+        sk_win_write_4(sc, SK_IMMR, SK_ISR_TX1_S_EOF|SK_ISR_TX2_S_EOF|
+	    SK_ISR_RX1_EOF|SK_ISR_RX2_EOF);
+        sk_win_write_1(sc, SK_IMTIMERCTL, SK_IMCTL_START);
+	sc->sk_int_mod_pending = 0;
+}
+
+static int
+msk_lookup(const struct pci_attach_args *pa)
+{
+	const struct msk_product *pmsk;
+
+	for ( pmsk = &msk_products[0]; pmsk->msk_vendor != 0; pmsk++) {
+		if (PCI_VENDOR(pa->pa_id) == pmsk->msk_vendor &&
+		    PCI_PRODUCT(pa->pa_id) == pmsk->msk_product)
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * Probe for a SysKonnect GEnesis chip. Check the PCI vendor and device
+ * IDs against our list and return a device name if we find a match.
+ */
+int
+mskc_probe(struct device *parent, struct cfdata *match, void *aux)
+{
+	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
+
+	return msk_lookup(pa);
+}
+
+/*
+ * Force the GEnesis into reset, then bring it out of reset.
+ */
+void msk_reset(struct sk_softc *sc)
+{
+	u_int32_t sk_imtimer_ticks;
+	int reg;
+
+	DPRINTFN(2, ("msk_reset\n"));
+
+	CSR_WRITE_1(sc, SK_CSR, SK_CSR_SW_RESET);
+	CSR_WRITE_1(sc, SK_CSR, SK_CSR_MASTER_RESET);
+	CSR_WRITE_2(sc, SK_LINK_CTRL, SK_LINK_RESET_SET);
+
+	DELAY(1000);
+	CSR_WRITE_1(sc, SK_CSR, SK_CSR_SW_UNRESET);
+	DELAY(2);
+	CSR_WRITE_1(sc, SK_CSR, SK_CSR_MASTER_UNRESET);
+	CSR_WRITE_2(sc, SK_LINK_CTRL, SK_LINK_RESET_CLEAR);
+
+	DPRINTFN(2, ("msk_reset: sk_csr=%x\n", CSR_READ_1(sc, SK_CSR)));
+	DPRINTFN(2, ("msk_reset: sk_link_ctrl=%x\n",
+		     CSR_READ_2(sc, SK_LINK_CTRL)));
+
+	/* Disable ASF */
+	CSR_WRITE_1(sc, SK_Y2_ASF_CSR, SK_Y2_ASF_RESET);
+	CSR_WRITE_2(sc, SK_CSR, SK_CSR_ASF_OFF);
+
+	/* Clear I2C IRQ noise */
+	CSR_WRITE_4(sc, SK_I2CHWIRQ, 1);
+
+	/* Disable hardware timer */
+	CSR_WRITE_1(sc, SK_TIMERCTL, SK_IMCTL_STOP);
+	CSR_WRITE_1(sc, SK_TIMERCTL, SK_IMCTL_IRQ_CLEAR);
+
+	/* Disable descriptor polling */
+	CSR_WRITE_4(sc, SK_DPT_TIMER_CTRL, SK_DPT_TCTL_STOP);
+
+	/* Disable time stamps */
+	CSR_WRITE_1(sc, SK_TSTAMP_CTL, SK_TSTAMP_STOP);
+	CSR_WRITE_1(sc, SK_TSTAMP_CTL, SK_TSTAMP_IRQ_CLEAR);
+
+	/* Enable RAM interface */
+	sk_win_write_1(sc, SK_RAMCTL, SK_RAMCTL_UNRESET);
+	for (reg = SK_TO0;reg <= SK_TO11; reg++)
+		sk_win_write_1(sc, reg, 36);
+
+	/*
+	 * Configure interrupt moderation. The moderation timer
+	 * defers interrupts specified in the interrupt moderation
+	 * timer mask based on the timeout specified in the interrupt
+	 * moderation timer init register. Each bit in the timer
+	 * register represents one tick, so to specify a timeout in
+	 * microseconds, we have to multiply by the correct number of
+	 * ticks-per-microsecond.
+	 */
+	switch (sc->sk_type) {
+	case SK_YUKON_EC:
+	case SK_YUKON_XL:
+	case SK_YUKON_FE:
+		sk_imtimer_ticks = SK_IMTIMER_TICKS_YUKON_EC;
+		break;
+	default:
+		sk_imtimer_ticks = SK_IMTIMER_TICKS_YUKON;
+	}
+
+	/* Reset status ring. */
+	bzero((char *)sc->sk_status_ring,
+	    MSK_STATUS_RING_CNT * sizeof(struct msk_status_desc));
+	sc->sk_status_idx = 0;
+
+	sk_win_write_4(sc, SK_STAT_BMU_CSR, SK_STAT_BMU_RESET);
+	sk_win_write_4(sc, SK_STAT_BMU_CSR, SK_STAT_BMU_UNRESET);
+
+	sk_win_write_2(sc, SK_STAT_BMU_LIDX, MSK_STATUS_RING_CNT - 1);
+	sk_win_write_4(sc, SK_STAT_BMU_ADDRLO,
+	    sc->sk_status_map->dm_segs[0].ds_addr);
+	sk_win_write_4(sc, SK_STAT_BMU_ADDRHI,
+	    (u_int64_t)sc->sk_status_map->dm_segs[0].ds_addr >> 32);
+	sk_win_write_2(sc, SK_STAT_BMU_TX_THRESH, 10);
+	sk_win_write_1(sc, SK_STAT_BMU_FIFOWM, 16);
+	sk_win_write_1(sc, SK_STAT_BMU_FIFOIWM, 16);
+
+#if 0
+	sk_win_write_4(sc, SK_Y2_LEV_ITIMERINIT, SK_IM_USECS(100));
+	sk_win_write_4(sc, SK_Y2_TX_ITIMERINIT, SK_IM_USECS(1000));
+
+	sk_win_write_4(sc, SK_Y2_ISR_ITIMERINIT, SK_IM_USECS(20));
+#else
+	sk_win_write_4(sc, SK_Y2_ISR_ITIMERINIT, SK_IM_USECS(4));
+#endif
+
+	sk_win_write_4(sc, SK_STAT_BMU_CSR, SK_STAT_BMU_ON);
+
+	sk_win_write_1(sc, SK_Y2_LEV_ITIMERCTL, SK_IMCTL_START);
+	sk_win_write_1(sc, SK_Y2_TX_ITIMERCTL, SK_IMCTL_START);
+	sk_win_write_1(sc, SK_Y2_ISR_ITIMERCTL, SK_IMCTL_START);
+
+	msk_update_int_mod(sc);
+}
+
+int
+msk_probe(struct device *parent, struct cfdata *match, void *aux)
+{
+	struct skc_attach_args *sa = aux;
+
+	if (sa->skc_port != SK_PORT_A && sa->skc_port != SK_PORT_B)
+		return (0);
+
+	switch (sa->skc_type) {
+	case SK_YUKON_XL:
+	case SK_YUKON_EC_U:
+	case SK_YUKON_EC:
+	case SK_YUKON_FE:
+		return (1);
+	}
+
+	return (0);
+}
+
+/*
+ * Each XMAC chip is attached as a separate logical IP interface.
+ * Single port cards will have only one logical interface of course.
+ */
+void
+msk_attach(struct device *parent, struct device *self, void *aux)
+{
+	struct sk_if_softc *sc_if = (struct sk_if_softc *) self;
+	struct sk_softc *sc = (struct sk_softc *)parent;
+	struct skc_attach_args *sa = aux;
+	struct ifnet *ifp;
+	caddr_t kva;
+	bus_dma_segment_t seg;
+	int i, rseg;
+	u_int32_t chunk, val;
+
+	sc_if->sk_port = sa->skc_port;
+	sc_if->sk_softc = sc;
+	sc->sk_if[sa->skc_port] = sc_if;
+
+	DPRINTFN(2, ("begin msk_attach: port=%d\n", sc_if->sk_port));
+
+	/*
+	 * Get station address for this interface. Note that
+	 * dual port cards actually come with three station
+	 * addresses: one for each port, plus an extra. The
+	 * extra one is used by the SysKonnect driver software
+	 * as a 'virtual' station address for when both ports
+	 * are operating in failover mode. Currently we don't
+	 * use this extra address.
+	 */
+	for (i = 0; i < ETHER_ADDR_LEN; i++)
+		sc_if->sk_enaddr[i] =
+		    sk_win_read_1(sc, SK_MAC0_0 + (sa->skc_port * 8) + i);
+
+	aprint_normal(": Ethernet address %s\n",
+	    ether_sprintf(sc_if->sk_enaddr));
+
+	/*
+	 * Set up RAM buffer addresses. The NIC will have a certain
+	 * amount of SRAM on it, somewhere between 512K and 2MB. We
+	 * need to divide this up a) between the transmitter and
+ 	 * receiver and b) between the two XMACs, if this is a
+	 * dual port NIC. Our algorithm is to divide up the memory
+	 * evenly so that everyone gets a fair share.
+	 *
+	 * Just to be contrary, Yukon2 appears to have separate memory
+	 * for each MAC.
+	 */
+	chunk = sc->sk_ramsize  - (sc->sk_ramsize + 2) / 3;
+	val = sc->sk_rboff / sizeof(u_int64_t);
+	sc_if->sk_rx_ramstart = val;
+	val += (chunk / sizeof(u_int64_t));
+	sc_if->sk_rx_ramend = val - 1;
+	chunk = sc->sk_ramsize - chunk;
+	sc_if->sk_tx_ramstart = val;
+	val += (chunk / sizeof(u_int64_t));
+	sc_if->sk_tx_ramend = val - 1;
+
+	DPRINTFN(2, ("msk_attach: rx_ramstart=%#x rx_ramend=%#x\n"
+		     "           tx_ramstart=%#x tx_ramend=%#x\n",
+		     sc_if->sk_rx_ramstart, sc_if->sk_rx_ramend,
+		     sc_if->sk_tx_ramstart, sc_if->sk_tx_ramend));
+
+	/* Read and save PHY type */
+	sc_if->sk_phytype = sk_win_read_1(sc, SK_EPROM1) & 0xF;
+
+	/* Set PHY address */
+	if ((sc_if->sk_phytype < SK_PHYTYPE_MARV_COPPER &&
+	     sc->sk_pmd != 'L' && sc->sk_pmd != 'S')) {
+		/* not initialized, punt */
+		sc_if->sk_phytype = SK_PHYTYPE_MARV_COPPER;
+
+		sc->sk_coppertype = 1;
+	}
+
+	sc_if->sk_phyaddr = SK_PHYADDR_MARV;
+
+	if (!(sc->sk_coppertype))
+		sc_if->sk_phytype = SK_PHYTYPE_MARV_FIBER;
+
+	/* Allocate the descriptor queues. */
+	if (bus_dmamem_alloc(sc->sc_dmatag, sizeof(struct msk_ring_data),
+	    PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
+		aprint_error(": can't alloc rx buffers\n");
+		goto fail;
+	}
+	if (bus_dmamem_map(sc->sc_dmatag, &seg, rseg,
+	    sizeof(struct msk_ring_data), &kva, BUS_DMA_NOWAIT)) {
+		aprint_error(": can't map dma buffers (%zu bytes)\n",
+		       sizeof(struct msk_ring_data));
+		goto fail_1;
+	}
+	if (bus_dmamap_create(sc->sc_dmatag, sizeof(struct msk_ring_data), 1,
+	    sizeof(struct msk_ring_data), 0, BUS_DMA_NOWAIT,
+            &sc_if->sk_ring_map)) {
+		aprint_error(": can't create dma map\n");
+		goto fail_2;
+	}
+	if (bus_dmamap_load(sc->sc_dmatag, sc_if->sk_ring_map, kva,
+	    sizeof(struct msk_ring_data), NULL, BUS_DMA_NOWAIT)) {
+		aprint_error(": can't load dma map\n");
+		goto fail_3;
+	}
+        sc_if->sk_rdata = (struct msk_ring_data *)kva;
+	bzero(sc_if->sk_rdata, sizeof(struct msk_ring_data));
+
+	ifp = &sc_if->sk_ethercom.ec_if;
+	/* Try to allocate memory for jumbo buffers. */
+	if (msk_alloc_jumbo_mem(sc_if)) {
+		aprint_error(": jumbo buffer allocation failed\n");
+		goto fail_3;
+	}
+	sc_if->sk_ethercom.ec_capabilities = ETHERCAP_VLAN_MTU
+		| ETHERCAP_JUMBO_MTU;
+
+	ifp->if_softc = sc_if;
+	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+	ifp->if_ioctl = msk_ioctl;
+	ifp->if_start = msk_start;
+	ifp->if_stop = msk_stop;
+	ifp->if_init = msk_init;
+	ifp->if_watchdog = msk_watchdog;
+	ifp->if_baudrate = 1000000000;
+	IFQ_SET_MAXLEN(&ifp->if_snd, MSK_TX_RING_CNT - 1);
+	IFQ_SET_READY(&ifp->if_snd);
+	strcpy(ifp->if_xname, sc_if->sk_dev.dv_xname);
+
+	/*
+	 * Do miibus setup.
+	 */
+	msk_init_yukon(sc_if);
+
+ 	DPRINTFN(2, ("msk_attach: 1\n"));
+
+	sc_if->sk_mii.mii_ifp = ifp;
+	sc_if->sk_mii.mii_readreg = msk_marv_miibus_readreg;
+	sc_if->sk_mii.mii_writereg = msk_marv_miibus_writereg;
+	sc_if->sk_mii.mii_statchg = msk_marv_miibus_statchg;
+
+	ifmedia_init(&sc_if->sk_mii.mii_media, 0,
+	    msk_ifmedia_upd, msk_ifmedia_sts);
+	mii_attach(self, &sc_if->sk_mii, 0xffffffff, MII_PHY_ANY,
+	    MII_OFFSET_ANY, 0);
+	if (LIST_FIRST(&sc_if->sk_mii.mii_phys) == NULL) {
+		aprint_error("%s: no PHY found!\n", sc_if->sk_dev.dv_xname);
+		ifmedia_add(&sc_if->sk_mii.mii_media, IFM_ETHER|IFM_MANUAL,
+			    0, NULL);
+		ifmedia_set(&sc_if->sk_mii.mii_media, IFM_ETHER|IFM_MANUAL);
+	} else
+		ifmedia_set(&sc_if->sk_mii.mii_media, IFM_ETHER|IFM_AUTO);
+
+	callout_init(&sc_if->sk_tick_ch);
+	callout_setfunc(&sc_if->sk_tick_ch, msk_yukon_tick, sc_if);
+	callout_schedule(&sc_if->sk_tick_ch, hz);
+
+	/*
+	 * Call MI attach routines.
+	 */
+	if_attach(ifp);
+	ether_ifattach(ifp, sc_if->sk_enaddr);
+
+	shutdownhook_establish(mskc_shutdown, sc);
+
+#if NRND > 0
+	rnd_attach_source(&sc->rnd_source, sc->sk_dev.dv_xname,
+		RND_TYPE_NET, 0);
+#endif
+
+	DPRINTFN(2, ("msk_attach: end\n"));
+	return;
+
+fail_3:
+	bus_dmamap_destroy(sc->sc_dmatag, sc_if->sk_ring_map);
+fail_2:
+	bus_dmamem_unmap(sc->sc_dmatag, kva, sizeof(struct msk_ring_data));
+fail_1:
+	bus_dmamem_free(sc->sc_dmatag, &seg, rseg);
+fail:
+	sc->sk_if[sa->skc_port] = NULL;
+}
+
+int
+mskcprint(void *aux, const char *pnp)
+{
+	struct skc_attach_args *sa = aux;
+
+	if (pnp)
+		aprint_normal("sk port %c at %s",
+		    (sa->skc_port == SK_PORT_A) ? 'A' : 'B', pnp);
+	else
+		aprint_normal(" port %c", (sa->skc_port == SK_PORT_A) ? 'A' : 'B');
+	return (UNCONF);
+}
+
+/*
+ * Attach the interface. Allocate softc structures, do ifmedia
+ * setup and ethernet/BPF attach.
+ */
+void
+mskc_attach(struct device *parent, struct device *self, void *aux)
+{
+	struct sk_softc *sc = (struct sk_softc *)self;
+	struct pci_attach_args *pa = aux;
+	struct skc_attach_args skca;
+	pci_chipset_tag_t pc = pa->pa_pc;
+	pcireg_t command, memtype;
+	pci_intr_handle_t ih;
+	const char *intrstr = NULL;
+	bus_size_t size;
+	int rc, sk_nodenum;
+	u_int8_t hw, skrs;
+	const char *revstr = NULL;
+	const struct sysctlnode *node;
+	caddr_t kva;
+	bus_dma_segment_t seg;
+	int rseg;
+
+	DPRINTFN(2, ("begin mskc_attach\n"));
+
+	/*
+	 * Handle power management nonsense.
+	 */
+	command = pci_conf_read(pc, pa->pa_tag, SK_PCI_CAPID) & 0x000000FF;
+
+	if (command == 0x01) {
+		command = pci_conf_read(pc, pa->pa_tag, SK_PCI_PWRMGMTCTRL);
+		if (command & SK_PSTATE_MASK) {
+			u_int32_t		iobase, membase, irq;
+
+			/* Save important PCI config data. */
+			iobase = pci_conf_read(pc, pa->pa_tag, SK_PCI_LOIO);
+			membase = pci_conf_read(pc, pa->pa_tag, SK_PCI_LOMEM);
+			irq = pci_conf_read(pc, pa->pa_tag, SK_PCI_INTLINE);
+
+			/* Reset the power state. */
+			aprint_normal("%s chip is in D%d power mode "
+			    "-- setting to D0\n", sc->sk_dev.dv_xname,
+			    command & SK_PSTATE_MASK);
+			command &= 0xFFFFFFFC;
+			pci_conf_write(pc, pa->pa_tag,
+			    SK_PCI_PWRMGMTCTRL, command);
+
+			/* Restore PCI config data. */
+			pci_conf_write(pc, pa->pa_tag, SK_PCI_LOIO, iobase);
+			pci_conf_write(pc, pa->pa_tag, SK_PCI_LOMEM, membase);
+			pci_conf_write(pc, pa->pa_tag, SK_PCI_INTLINE, irq);
+		}
+	}
+
+	/*
+	 * Map control/status registers.
+	 */
+
+	memtype = pci_mapreg_type(pc, pa->pa_tag, SK_PCI_LOMEM);
+	switch (memtype) {
+	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
+	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
+		if (pci_mapreg_map(pa, SK_PCI_LOMEM,
+				   memtype, 0, &sc->sk_btag, &sc->sk_bhandle,
+				   NULL, &size) == 0)
+			break;
+	default:
+		aprint_error(": can't map mem space\n");
+		return;
+	}
+
+	sc->sc_dmatag = pa->pa_dmat;
+
+	sc->sk_type = sk_win_read_1(sc, SK_CHIPVER);
+	sc->sk_rev = (sk_win_read_1(sc, SK_CONFIG) >> 4);
+
+	/* bail out here if chip is not recognized */
+	if (!(SK_IS_YUKON(sc))) {
+		aprint_error(": unknown chip type: %d\n", sc->sk_type);
+		goto fail_1;
+	}
+	DPRINTFN(2, ("mskc_attach: allocate interrupt\n"));
+
+	/* Allocate interrupt */
+	if (pci_intr_map(pa, &ih)) {
+		aprint_error(": couldn't map interrupt\n");
+		goto fail_1;
+	}
+
+	intrstr = pci_intr_string(pc, ih);
+	sc->sk_intrhand = pci_intr_establish(pc, ih, IPL_NET, msk_intr, sc);
+	if (sc->sk_intrhand == NULL) {
+		aprint_error(": couldn't establish interrupt");
+		if (intrstr != NULL)
+			aprint_error(" at %s", intrstr);
+		aprint_error("\n");
+		goto fail_1;
+	}
+
+	if (bus_dmamem_alloc(sc->sc_dmatag,
+	    MSK_STATUS_RING_CNT * sizeof(struct msk_status_desc),
+	    PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
+		aprint_error(": can't alloc status buffers\n");
+		goto fail_2;
+	}
+
+	if (bus_dmamem_map(sc->sc_dmatag, &seg, rseg,
+	    MSK_STATUS_RING_CNT * sizeof(struct msk_status_desc),
+	    &kva, BUS_DMA_NOWAIT)) {
+		aprint_error(": can't map dma buffers (%zu bytes)\n",
+		    MSK_STATUS_RING_CNT * sizeof(struct msk_status_desc));
+		goto fail_3;
+	}
+	if (bus_dmamap_create(sc->sc_dmatag,
+	    MSK_STATUS_RING_CNT * sizeof(struct msk_status_desc), 1,
+	    MSK_STATUS_RING_CNT * sizeof(struct msk_status_desc), 0,
+	    BUS_DMA_NOWAIT, &sc->sk_status_map)) {
+		aprint_error(": can't create dma map\n");
+		goto fail_4;
+	}
+	if (bus_dmamap_load(sc->sc_dmatag, sc->sk_status_map, kva,
+	    MSK_STATUS_RING_CNT * sizeof(struct msk_status_desc),
+	    NULL, BUS_DMA_NOWAIT)) {
+		aprint_error(": can't load dma map\n");
+		goto fail_5;
+	}
+	sc->sk_status_ring = (struct msk_status_desc *)kva;
+	bzero(sc->sk_status_ring,
+	    MSK_STATUS_RING_CNT * sizeof(struct msk_status_desc));
+
+	/* Reset the adapter. */
+	msk_reset(sc);
+
+	skrs = sk_win_read_1(sc, SK_EPROM0);
+	if (skrs == 0x00)
+		sc->sk_ramsize = 0x20000;
+	else
+		sc->sk_ramsize = skrs * (1<<12);
+	sc->sk_rboff = SK_RBOFF_0;
+
+	DPRINTFN(2, ("mskc_attach: ramsize=%d (%dk), rboff=%d\n",
+		     sc->sk_ramsize, sc->sk_ramsize / 1024,
+		     sc->sk_rboff));
+
+	/* Read and save physical media type */
+	sc->sk_pmd = sk_win_read_1(sc, SK_PMDTYPE);
+
+	if (sc->sk_pmd == 'T' || sc->sk_pmd == '1' ||
+	    (SK_IS_YUKON2(sc) && !(sc->sk_pmd == 'L' ||
+	    sc->sk_pmd == 'S')))
+		sc->sk_coppertype = 1;
+	else
+		sc->sk_coppertype = 0;
+
+	switch (sc->sk_type) {
+	case SK_YUKON_XL:
+		sc->sk_name = "Marvell Yukon-2 XL";
+		break;
+	case SK_YUKON_EC_U:
+		sc->sk_name = "Marvell Yukon-2 EC Ultra";
+		break;
+	case SK_YUKON_EC:
+		sc->sk_name = "Marvell Yukon-2 EC";
+		break;
+	case SK_YUKON_FE:
+		sc->sk_name = "Marvell Yukon-2 FE";
+		break;
+	default:
+		sc->sk_name = "Marvell Yukon (Unknown)";
+	}
+
+	if (sc->sk_type == SK_YUKON_XL) {
+		switch (sc->sk_rev) {
+		case SK_YUKON_XL_REV_A0:
+			revstr = "A0";
+			break;
+		case SK_YUKON_XL_REV_A1:
+			revstr = "A1";
+			break;
+		case SK_YUKON_XL_REV_A2:
+			revstr = "A2";
+			break;
+		case SK_YUKON_XL_REV_A3:
+			revstr = "A3";
+			break;
+		default:
+			;
+		}
+	}
+
+	if (sc->sk_type == SK_YUKON_EC) {
+		switch (sc->sk_rev) {
+		case SK_YUKON_EC_REV_A1:
+			revstr = "A1";
+			break;
+		case SK_YUKON_EC_REV_A2:
+			revstr = "A2";
+			break;
+		case SK_YUKON_EC_REV_A3:
+			revstr = "A3";
+			break;
+		default:
+			;
+		}
+	}
+
+	if (sc->sk_type == SK_YUKON_EC_U) {
+		switch (sc->sk_rev) {
+		case SK_YUKON_EC_U_REV_A0:
+			revstr = "A0";
+			break;
+		case SK_YUKON_EC_U_REV_A1:
+			revstr = "A1";
+			break;
+		default:
+			;
+		}
+	}
+
+	/* Announce the product name. */
+	aprint_normal(", %s", sc->sk_name);
+	if (revstr != NULL)
+		aprint_normal(" rev. %s", revstr);
+	aprint_normal(" (0x%x): %s\n", sc->sk_rev, intrstr);
+
+
+	sc->sk_macs = 1;
+
+	hw = sk_win_read_1(sc, SK_Y2_HWRES);
+	if ((hw & SK_Y2_HWRES_LINK_MASK) == SK_Y2_HWRES_LINK_DUAL) {
+		if ((sk_win_read_1(sc, SK_Y2_CLKGATE) &
+		    SK_Y2_CLKGATE_LINK2_INACTIVE) == 0)
+			sc->sk_macs++;
+	}
+
+	skca.skc_port = SK_PORT_A;
+	skca.skc_type = sc->sk_type;
+	skca.skc_rev = sc->sk_rev;
+	(void)config_found(&sc->sk_dev, &skca, mskcprint);
+
+	if (sc->sk_macs > 1) {
+		skca.skc_port = SK_PORT_B;
+		skca.skc_type = sc->sk_type;
+		skca.skc_rev = sc->sk_rev;
+		(void)config_found(&sc->sk_dev, &skca, mskcprint);
+	}
+
+	/* Turn on the 'driver is loaded' LED. */
+	CSR_WRITE_2(sc, SK_LED, SK_LED_GREEN_ON);
+
+	/* skc sysctl setup */
+
+	sc->sk_int_mod = SK_IM_DEFAULT;
+	sc->sk_int_mod_pending = 0;
+
+	if ((rc = sysctl_createv(&sc->sk_clog, 0, NULL, &node,
+	    0, CTLTYPE_NODE, sc->sk_dev.dv_xname,
+	    SYSCTL_DESCR("mskc per-controller controls"),
+	    NULL, 0, NULL, 0, CTL_HW, msk_root_num, CTL_CREATE,
+	    CTL_EOL)) != 0) {
+		aprint_normal("%s: couldn't create sysctl node\n",
+		    sc->sk_dev.dv_xname);
+		goto fail_6;
+	}
+
+	sk_nodenum = node->sysctl_num;
+
+	/* interrupt moderation time in usecs */
+	if ((rc = sysctl_createv(&sc->sk_clog, 0, NULL, &node,
+	    CTLFLAG_READWRITE,
+	    CTLTYPE_INT, "int_mod",
+	    SYSCTL_DESCR("msk interrupt moderation timer"),
+	    msk_sysctl_handler, 0, sc,
+	    0, CTL_HW, msk_root_num, sk_nodenum, CTL_CREATE,
+	    CTL_EOL)) != 0) {
+		aprint_normal("%s: couldn't create int_mod sysctl node\n",
+		    sc->sk_dev.dv_xname);
+		goto fail_6;
+	}
+
+	return;
+
+ fail_6:
+	bus_dmamap_unload(sc->sc_dmatag, sc->sk_status_map);
+fail_5:
+	bus_dmamap_destroy(sc->sc_dmatag, sc->sk_status_map);
+fail_4:
+	bus_dmamem_unmap(sc->sc_dmatag, kva, 
+	    MSK_STATUS_RING_CNT * sizeof(struct msk_status_desc));
+fail_3:
+	bus_dmamem_free(sc->sc_dmatag, &seg, rseg);
+fail_2:
+	pci_intr_disestablish(pc, sc->sk_intrhand);
+fail_1:
+	bus_space_unmap(sc->sk_btag, sc->sk_bhandle, size);
+}
+
+int
+msk_encap(struct sk_if_softc *sc_if, struct mbuf *m_head, u_int32_t *txidx)
+{
+	struct sk_softc		*sc = sc_if->sk_softc;
+	struct msk_tx_desc		*f = NULL;
+	u_int32_t		frag, cur, cnt = 0;
+	int			i;
+	struct sk_txmap_entry	*entry;
+	bus_dmamap_t		txmap;
+
+	DPRINTFN(2, ("msk_encap\n"));
+
+	entry = SIMPLEQ_FIRST(&sc_if->sk_txmap_head);
+	if (entry == NULL) {
+		DPRINTFN(2, ("msk_encap: no txmap available\n"));
+		return (ENOBUFS);
+	}
+	txmap = entry->dmamap;
+
+	cur = frag = *txidx;
+
+#ifdef MSK_DEBUG
+	if (mskdebug >= 2)
+		msk_dump_mbuf(m_head);
+#endif
+
+	/*
+	 * Start packing the mbufs in this chain into
+	 * the fragment pointers. Stop when we run out
+	 * of fragments or hit the end of the mbuf chain.
+	 */
+	if (bus_dmamap_load_mbuf(sc->sc_dmatag, txmap, m_head,
+	    BUS_DMA_NOWAIT)) {
+		DPRINTFN(2, ("msk_encap: dmamap failed\n"));
+		return (ENOBUFS);
+	}
+
+	DPRINTFN(2, ("msk_encap: dm_nsegs=%d\n", txmap->dm_nsegs));
+
+	/* Sync the DMA map. */
+	bus_dmamap_sync(sc->sc_dmatag, txmap, 0, txmap->dm_mapsize,
+	    BUS_DMASYNC_PREWRITE);
+
+	for (i = 0; i < txmap->dm_nsegs; i++) {
+		if ((MSK_TX_RING_CNT - (sc_if->sk_cdata.sk_tx_cnt + cnt)) < 2) {
+			DPRINTFN(2, ("msk_encap: too few descriptors free\n"));
+			return (ENOBUFS);
+		}
+		f = &sc_if->sk_rdata->sk_tx_ring[frag];
+		f->sk_addr = htole32(txmap->dm_segs[i].ds_addr);
+		f->sk_len = htole16(txmap->dm_segs[i].ds_len);
+		f->sk_ctl = 0;
+		if (cnt == 0)
+			f->sk_opcode = SK_Y2_TXOPC_PACKET;
+		else
+			f->sk_opcode = SK_Y2_TXOPC_BUFFER | SK_Y2_TXOPC_OWN;
+		cur = frag;
+		SK_INC(frag, MSK_TX_RING_CNT);
+		cnt++;
+	}
+
+	sc_if->sk_cdata.sk_tx_chain[cur].sk_mbuf = m_head;
+	SIMPLEQ_REMOVE_HEAD(&sc_if->sk_txmap_head, link);
+
+	sc_if->sk_cdata.sk_tx_map[cur] = entry;
+	sc_if->sk_rdata->sk_tx_ring[cur].sk_ctl |= SK_Y2_TXCTL_LASTFRAG;
+
+	/* Sync descriptors before handing to chip */
+	MSK_CDTXSYNC(sc_if, *txidx, txmap->dm_nsegs,
+            BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+	sc_if->sk_rdata->sk_tx_ring[*txidx].sk_opcode |= SK_Y2_TXOPC_OWN;
+
+	/* Sync first descriptor to hand it off */
+	MSK_CDTXSYNC(sc_if, *txidx, 1,
+	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+	sc_if->sk_cdata.sk_tx_cnt += cnt;
+
+#ifdef MSK_DEBUG
+	if (mskdebug >= 2) {
+		struct msk_tx_desc *le;
+		u_int32_t idx;
+		for (idx = *txidx; idx != frag; SK_INC(idx, MSK_TX_RING_CNT)) {
+			le = &sc_if->sk_rdata->sk_tx_ring[idx];
+			msk_dump_txdesc(le, idx);
+		}
+	}
+#endif
+
+	*txidx = frag;
+
+	DPRINTFN(2, ("msk_encap: completed successfully\n"));
+
+	return (0);
+}
+
+void
+msk_start(struct ifnet *ifp)
+{
+        struct sk_if_softc	*sc_if = ifp->if_softc;
+        struct mbuf		*m_head = NULL;
+        u_int32_t		idx = sc_if->sk_cdata.sk_tx_prod;
+	int			pkts = 0;
+
+	DPRINTFN(2, ("msk_start\n"));
+
+	while (sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf == NULL) {
+		IFQ_POLL(&ifp->if_snd, m_head);
+		if (m_head == NULL)
+			break;
+
+		/*
+		 * Pack the data into the transmit ring. If we
+		 * don't have room, set the OACTIVE flag and wait
+		 * for the NIC to drain the ring.
+		 */
+		if (msk_encap(sc_if, m_head, &idx)) {
+			ifp->if_flags |= IFF_OACTIVE;
+			break;
+		}
+
+		/* now we are committed to transmit the packet */
+		IFQ_DEQUEUE(&ifp->if_snd, m_head);
+		pkts++;
+
+		/*
+		 * If there's a BPF listener, bounce a copy of this frame
+		 * to him.
+		 */
+#if NBPFILTER > 0
+		if (ifp->if_bpf)
+			bpf_mtap(ifp->if_bpf, m_head);
+#endif
+	}
+	if (pkts == 0)
+		return;
+
+	/* Transmit */
+	if (idx != sc_if->sk_cdata.sk_tx_prod) {
+		sc_if->sk_cdata.sk_tx_prod = idx;
+		SK_IF_WRITE_2(sc_if, 1, SK_TXQA1_Y2_PREF_PUTIDX, idx);
+
+		/* Set a timeout in case the chip goes out to lunch. */
+		ifp->if_timer = 5;
+	}
+}
+
+void
+msk_watchdog(struct ifnet *ifp)
+{
+	struct sk_if_softc *sc_if = ifp->if_softc;
+
+	/*
+	 * Reclaim first as there is a possibility of losing Tx completion
+	 * interrupts.
+	 */
+	msk_txeof(sc_if);
+	if (sc_if->sk_cdata.sk_tx_cnt != 0) {
+		aprint_error("%s: watchdog timeout\n", sc_if->sk_dev.dv_xname);
+
+		ifp->if_oerrors++;
+
+		/* XXX Resets both ports; we shouldn't do that. */
+		msk_reset(sc_if->sk_softc);
+		msk_init(ifp);
+	}
+}
+
+void
+mskc_shutdown(void *v)
+{
+	struct sk_softc		*sc = v;
+
+	DPRINTFN(2, ("msk_shutdown\n"));
+
+	/* Turn off the 'driver is loaded' LED. */
+	CSR_WRITE_2(sc, SK_LED, SK_LED_GREEN_OFF);
+
+	msk_reset(sc);
+}
+
+__inline int
+msk_rxvalid(struct sk_softc *sc, u_int32_t stat, u_int32_t len)
+{
+	if ((stat & (YU_RXSTAT_CRCERR | YU_RXSTAT_LONGERR |
+	    YU_RXSTAT_MIIERR | YU_RXSTAT_BADFC | YU_RXSTAT_GOODFC |
+	    YU_RXSTAT_JABBER)) != 0 ||
+	    (stat & YU_RXSTAT_RXOK) != YU_RXSTAT_RXOK ||
+	    YU_RXSTAT_BYTES(stat) != len)
+		return (0);
+
+	return (1);
+}
+
+void
+msk_rxeof(struct sk_if_softc *sc_if, u_int16_t len, u_int32_t rxstat)
+{
+	struct sk_softc		*sc = sc_if->sk_softc;
+	struct ifnet		*ifp = &sc_if->sk_ethercom.ec_if;
+	struct mbuf		*m;
+	struct sk_chain		*cur_rx;
+	int			cur, total_len = len;
+	bus_dmamap_t		dmamap;
+
+	DPRINTFN(2, ("msk_rxeof\n"));
+
+	cur = sc_if->sk_cdata.sk_rx_cons;
+	SK_INC(sc_if->sk_cdata.sk_rx_cons, MSK_RX_RING_CNT);
+	SK_INC(sc_if->sk_cdata.sk_rx_prod, MSK_RX_RING_CNT);
+
+	/* Sync the descriptor */
+	MSK_CDRXSYNC(sc_if, cur, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+
+	cur_rx = &sc_if->sk_cdata.sk_rx_chain[cur];
+	dmamap = sc_if->sk_cdata.sk_rx_jumbo_map;
+
+	bus_dmamap_sync(sc_if->sk_softc->sc_dmatag, dmamap, 0,
+	    dmamap->dm_mapsize, BUS_DMASYNC_POSTREAD);
+
+	m = cur_rx->sk_mbuf;
+	cur_rx->sk_mbuf = NULL;
+
+	if (total_len < SK_MIN_FRAMELEN ||
+	    total_len > SK_JUMBO_FRAMELEN ||
+	    msk_rxvalid(sc, rxstat, total_len) == 0) {
+		ifp->if_ierrors++;
+		msk_newbuf(sc_if, cur, m, dmamap);
+		return;
+	}
+
+	/*
+	 * Try to allocate a new jumbo buffer. If that fails, copy the
+	 * packet to mbufs and put the jumbo buffer back in the ring
+	 * so it can be re-used. If allocating mbufs fails, then we
+	 * have to drop the packet.
+	 */
+	if (msk_newbuf(sc_if, cur, NULL, dmamap) == ENOBUFS) {
+		struct mbuf		*m0;
+		m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
+		    total_len + ETHER_ALIGN, 0, ifp, NULL);
+		msk_newbuf(sc_if, cur, m, dmamap);
+		if (m0 == NULL) {
+			ifp->if_ierrors++;
+			return;
+		}
+		m_adj(m0, ETHER_ALIGN);
+		m = m0;
+	} else {
+		m->m_pkthdr.rcvif = ifp;
+		m->m_pkthdr.len = m->m_len = total_len;
+	}
+
+	ifp->if_ipackets++;
+
+#if NBPFILTER > 0
+	if (ifp->if_bpf)
+		bpf_mtap(ifp->if_bpf, m);
+#endif
+
+	/* pass it on. */
+	(*ifp->if_input)(ifp, m);
+}
+
+void
+msk_txeof(struct sk_if_softc *sc_if)
+{
+	struct sk_softc		*sc = sc_if->sk_softc;
+	struct msk_tx_desc	*cur_tx;
+	struct ifnet		*ifp = &sc_if->sk_ethercom.ec_if;
+	u_int32_t		idx, sk_ctl;
+	struct sk_txmap_entry	*entry;
+
+	DPRINTFN(2, ("msk_txeof\n"));
+
+	/*
+	 * Go through our tx ring and free mbufs for those
+	 * frames that have been sent.
+	 */
+	idx = sc_if->sk_cdata.sk_tx_cons;
+	while (idx != sk_win_read_2(sc, SK_STAT_BMU_TXA1_RIDX)) {
+		MSK_CDTXSYNC(sc_if, idx, 1,
+		    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+
+		cur_tx = &sc_if->sk_rdata->sk_tx_ring[idx];
+		sk_ctl = letoh32(cur_tx->sk_ctl);
+#ifdef MSK_DEBUG
+		if (mskdebug >= 2)
+			msk_dump_txdesc(cur_tx, idx);
+#endif
+		if (sk_ctl & SK_TXCTL_LASTFRAG)
+			ifp->if_opackets++;
+		if (sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf != NULL) {
+			entry = sc_if->sk_cdata.sk_tx_map[idx];
+
+			m_freem(sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf);
+			sc_if->sk_cdata.sk_tx_chain[idx].sk_mbuf = NULL;
+
+			bus_dmamap_sync(sc->sc_dmatag, entry->dmamap, 0,
+			    entry->dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE);
+
+			bus_dmamap_unload(sc->sc_dmatag, entry->dmamap);
+			SIMPLEQ_INSERT_TAIL(&sc_if->sk_txmap_head, entry,
+					  link);
+			sc_if->sk_cdata.sk_tx_map[idx] = NULL;
+		}
+		sc_if->sk_cdata.sk_tx_cnt--;
+		SK_INC(idx, MSK_TX_RING_CNT);
+	}
+	ifp->if_timer = sc_if->sk_cdata.sk_tx_cnt > 0 ? 5 : 0;
+
+	if (sc_if->sk_cdata.sk_tx_cnt < MSK_TX_RING_CNT - 2)
+		ifp->if_flags &= ~IFF_OACTIVE;
+
+	sc_if->sk_cdata.sk_tx_cons = idx;
+}
+
+void
+msk_yukon_tick(void *xsc_if)
+{
+	struct sk_if_softc *sc_if = xsc_if;  
+	struct mii_data *mii = &sc_if->sk_mii;
+
+	mii_tick(mii);
+	callout_schedule(&sc_if->sk_tick_ch, hz);
+}
+
+void
+msk_intr_yukon(struct sk_if_softc *sc_if)
+{
+	u_int8_t status;
+
+	status = SK_IF_READ_1(sc_if, 0, SK_GMAC_ISR);
+	/* RX overrun */
+	if ((status & SK_GMAC_INT_RX_OVER) != 0) {
+		SK_IF_WRITE_1(sc_if, 0, SK_RXMF1_CTRL_TEST,
+		    SK_RFCTL_RX_FIFO_OVER);
+	}
+	/* TX underrun */
+	if ((status & SK_GMAC_INT_TX_UNDER) != 0) {
+		SK_IF_WRITE_1(sc_if, 0, SK_RXMF1_CTRL_TEST,
+		    SK_TFCTL_TX_FIFO_UNDER);
+	}
+
+	DPRINTFN(2, ("msk_intr_yukon status=%#x\n", status));
+}
+
+int
+msk_intr(void *xsc)
+{
+	struct sk_softc		*sc = xsc;
+	struct sk_if_softc	*sc_if0 = sc->sk_if[SK_PORT_A];
+	struct sk_if_softc	*sc_if1 = sc->sk_if[SK_PORT_B];
+	struct ifnet		*ifp0 = NULL, *ifp1 = NULL;
+	int			claimed = 0;
+	u_int32_t		status;
+	u_int16_t		idx;
+	struct msk_status_desc	*cur_st;
+
+	status = CSR_READ_4(sc, SK_Y2_ISSR2);
+	if (status == 0) {
+		CSR_WRITE_4(sc, SK_Y2_ICR, 2);
+		return (0);
+	}
+
+	status = CSR_READ_4(sc, SK_ISR);
+
+	if (sc_if0 != NULL)
+		ifp0 = &sc_if0->sk_ethercom.ec_if;
+	if (sc_if1 != NULL)
+		ifp1 = &sc_if1->sk_ethercom.ec_if;
+
+	if (sc_if0 && (status & SK_Y2_IMR_MAC1) &&
+	    (ifp0->if_flags & IFF_RUNNING)) {
+		msk_intr_yukon(sc_if0);
+	}
+
+	if (sc_if1 && (status & SK_Y2_IMR_MAC2) &&
+	    (ifp1->if_flags & IFF_RUNNING)) {
+		msk_intr_yukon(sc_if1);
+	}
+
+	idx = CSR_READ_2(sc, SK_STAT_BMU_PUTIDX);
+	while (sc->sk_status_idx != idx) {
+		MSK_CDSTSYNC(sc, sc->sk_status_idx,
+		    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+
+		cur_st = &sc->sk_status_ring[sc->sk_status_idx];
+		switch (cur_st->sk_opcode & ~SK_Y2_STOPC_OWN) {
+		case SK_Y2_STOPC_RXSTAT:
+			msk_rxeof(sc->sk_if[cur_st->sk_link],
+			    letoh16(cur_st->sk_len),
+			    letoh32(cur_st->sk_status));
+			SK_IF_WRITE_2(sc->sk_if[cur_st->sk_link], 0,
+			    SK_RXQ1_Y2_PREF_PUTIDX,
+			    sc->sk_if[cur_st->sk_link]->sk_cdata.sk_rx_prod);
+			break;
+		case SK_Y2_STOPC_TXSTAT:
+			msk_txeof(sc->sk_if[cur_st->sk_link]);
+			break;
+		default:
+			aprint_error("opcode=0x%x\n", cur_st->sk_opcode);
+			break;
+		}
+		SK_INC(sc->sk_status_idx, MSK_STATUS_RING_CNT);
+		idx = CSR_READ_2(sc, SK_STAT_BMU_PUTIDX);
+	}
+
+	if (status & SK_Y2_IMR_BMU) {
+		CSR_WRITE_4(sc, SK_STAT_BMU_CSR, SK_STAT_BMU_IRQ_CLEAR);
+		claimed = 1;
+	}
+
+	CSR_WRITE_4(sc, SK_Y2_ICR, 2);
+
+	if (ifp0 != NULL && !IFQ_IS_EMPTY(&ifp0->if_snd))
+		msk_start(ifp0);
+	if (ifp1 != NULL && !IFQ_IS_EMPTY(&ifp1->if_snd))
+		msk_start(ifp1);
+
+#if NRND > 0
+	if (RND_ENABLED(&sc->rnd_source))
+		rnd_add_uint32(&sc->rnd_source, status);
+#endif
+
+	if (sc->sk_int_mod_pending)
+		msk_update_int_mod(sc);
+
+	return claimed;
+}
+
+void
+msk_init_yukon(struct sk_if_softc *sc_if)
+{
+	u_int32_t		phy, v;
+	u_int16_t		reg;
+	struct sk_softc		*sc;
+	int			i;
+
+	sc = sc_if->sk_softc;
+
+	DPRINTFN(2, ("msk_init_yukon: start: sk_csr=%#x\n",
+		     CSR_READ_4(sc_if->sk_softc, SK_CSR)));
+
+	DPRINTFN(6, ("msk_init_yukon: 1\n"));
+
+	/* GMAC and GPHY Reset */
+	SK_IF_WRITE_4(sc_if, 0, SK_GPHY_CTRL, SK_GPHY_RESET_SET);
+	SK_IF_WRITE_4(sc_if, 0, SK_GMAC_CTRL, SK_GMAC_RESET_SET);
+	DELAY(1000);
+
+	DPRINTFN(6, ("msk_init_yukon: 2\n"));
+
+#if 0
+	phy = SK_GPHY_INT_POL_HI | SK_GPHY_DIS_FC | SK_GPHY_DIS_SLEEP |
+		SK_GPHY_ENA_XC | SK_GPHY_ANEG_ALL | SK_GPHY_ENA_PAUSE;
+#else
+	phy = SK_GPHY_ENA_PAUSE;
+#endif
+
+	if (sc->sk_coppertype)
+		phy |= SK_GPHY_COPPER;
+	else
+		phy |= SK_GPHY_FIBER;
+
+	DPRINTFN(3, ("msk_init_yukon: phy=%#x\n", phy));
+
+	SK_IF_WRITE_4(sc_if, 0, SK_GPHY_CTRL, phy | SK_GPHY_RESET_SET);
+	DELAY(1000);
+	SK_IF_WRITE_4(sc_if, 0, SK_GPHY_CTRL, phy | SK_GPHY_RESET_CLEAR);
+	SK_IF_WRITE_4(sc_if, 0, SK_GMAC_CTRL, SK_GMAC_LOOP_OFF |
+		      SK_GMAC_PAUSE_ON | SK_GMAC_RESET_CLEAR);
+
+	DPRINTFN(3, ("msk_init_yukon: gmac_ctrl=%#x\n",
+		     SK_IF_READ_4(sc_if, 0, SK_GMAC_CTRL)));
+
+	DPRINTFN(6, ("msk_init_yukon: 3\n"));
+
+	/* unused read of the interrupt source register */
+	DPRINTFN(6, ("msk_init_yukon: 4\n"));
+	SK_IF_READ_2(sc_if, 0, SK_GMAC_ISR);
+
+	DPRINTFN(6, ("msk_init_yukon: 4a\n"));
+	reg = SK_YU_READ_2(sc_if, YUKON_PAR);
+	DPRINTFN(6, ("msk_init_yukon: YUKON_PAR=%#x\n", reg));
+
+	/* MIB Counter Clear Mode set */
+        reg |= YU_PAR_MIB_CLR;
+	DPRINTFN(6, ("msk_init_yukon: YUKON_PAR=%#x\n", reg));
+	DPRINTFN(6, ("msk_init_yukon: 4b\n"));
+	SK_YU_WRITE_2(sc_if, YUKON_PAR, reg);
+
+	/* MIB Counter Clear Mode clear */
+	DPRINTFN(6, ("msk_init_yukon: 5\n"));
+        reg &= ~YU_PAR_MIB_CLR;
+	SK_YU_WRITE_2(sc_if, YUKON_PAR, reg);
+
+	/* receive control reg */
+	DPRINTFN(6, ("msk_init_yukon: 7\n"));
+	SK_YU_WRITE_2(sc_if, YUKON_RCR, YU_RCR_CRCR);
+
+	/* transmit parameter register */
+	DPRINTFN(6, ("msk_init_yukon: 8\n"));
+	SK_YU_WRITE_2(sc_if, YUKON_TPR, YU_TPR_JAM_LEN(0x3) |
+		      YU_TPR_JAM_IPG(0xb) | YU_TPR_JAM2DATA_IPG(0x1a) );
+
+	/* serial mode register */
+	DPRINTFN(6, ("msk_init_yukon: 9\n"));
+	SK_YU_WRITE_2(sc_if, YUKON_SMR, YU_SMR_DATA_BLIND(0x1c) |
+		      YU_SMR_MFL_VLAN | YU_SMR_MFL_JUMBO |
+		      YU_SMR_IPG_DATA(0x1e));
+
+	DPRINTFN(6, ("msk_init_yukon: 10\n"));
+	/* Setup Yukon's address */
+	for (i = 0; i < 3; i++) {
+		/* Write Source Address 1 (unicast filter) */
+		SK_YU_WRITE_2(sc_if, YUKON_SAL1 + i * 4, 
+			      sc_if->sk_enaddr[i * 2] |
+			      sc_if->sk_enaddr[i * 2 + 1] << 8);
+	}
+
+	for (i = 0; i < 3; i++) {
+		reg = sk_win_read_2(sc_if->sk_softc,
+				    SK_MAC1_0 + i * 2 + sc_if->sk_port * 8);
+		SK_YU_WRITE_2(sc_if, YUKON_SAL2 + i * 4, reg);
+	}
+
+	/* Set promiscuous mode */
+	msk_setpromisc(sc_if);
+
+	/* Set multicast filter */
+	DPRINTFN(6, ("msk_init_yukon: 11\n"));
+	msk_setmulti(sc_if);
+
+	/* enable interrupt mask for counter overflows */
+	DPRINTFN(6, ("msk_init_yukon: 12\n"));
+	SK_YU_WRITE_2(sc_if, YUKON_TIMR, 0);
+	SK_YU_WRITE_2(sc_if, YUKON_RIMR, 0);
+	SK_YU_WRITE_2(sc_if, YUKON_TRIMR, 0);
+
+	/* Configure RX MAC FIFO Flush Mask */
+	v = YU_RXSTAT_FOFL | YU_RXSTAT_CRCERR | YU_RXSTAT_MIIERR |
+	    YU_RXSTAT_BADFC | YU_RXSTAT_GOODFC | YU_RXSTAT_RUNT |
+	    YU_RXSTAT_JABBER;
+	SK_IF_WRITE_2(sc_if, 0, SK_RXMF1_FLUSH_MASK, v);
+
+	/* Disable RX MAC FIFO Flush for YUKON-Lite Rev. A0 only */
+	if (sc->sk_type == SK_YUKON_LITE && sc->sk_rev == SK_YUKON_LITE_REV_A0)
+		v = SK_TFCTL_OPERATION_ON;
+	else
+		v = SK_TFCTL_OPERATION_ON | SK_RFCTL_FIFO_FLUSH_ON;
+	/* Configure RX MAC FIFO */
+	SK_IF_WRITE_1(sc_if, 0, SK_RXMF1_CTRL_TEST, SK_RFCTL_RESET_CLEAR);
+	SK_IF_WRITE_2(sc_if, 0, SK_RXMF1_CTRL_TEST, v);
+
+	/* Increase flush threshould to 64 bytes */
+	SK_IF_WRITE_2(sc_if, 0, SK_RXMF1_FLUSH_THRESHOLD,
+	    SK_RFCTL_FIFO_THRESHOLD + 1);
+
+	/* Configure TX MAC FIFO */
+	SK_IF_WRITE_1(sc_if, 0, SK_TXMF1_CTRL_TEST, SK_TFCTL_RESET_CLEAR);
+	SK_IF_WRITE_2(sc_if, 0, SK_TXMF1_CTRL_TEST, SK_TFCTL_OPERATION_ON);
+
+#if 1
+	SK_YU_WRITE_2(sc_if, YUKON_GPCR, YU_GPCR_TXEN | YU_GPCR_RXEN);
+#endif
+	DPRINTFN(6, ("msk_init_yukon: end\n"));
+}
+
+/*
+ * Note that to properly initialize any part of the GEnesis chip,
+ * you first have to take it out of reset mode.
+ */
+int
+msk_init(struct ifnet *ifp)
+{
+	struct sk_if_softc	*sc_if = ifp->if_softc;
+	struct sk_softc		*sc = sc_if->sk_softc;
+	struct mii_data		*mii = &sc_if->sk_mii;
+	int			s;
+	uint32_t		imr, sk_imtimer_ticks;
+
+
+	DPRINTFN(2, ("msk_init\n"));
+
+	s = splnet();
+
+	/* Cancel pending I/O and free all RX/TX buffers. */
+	msk_stop(ifp,0);
+
+	/* Configure I2C registers */
+
+	/* Configure XMAC(s) */
+	msk_init_yukon(sc_if);
+	mii_mediachg(mii);
+
+	/* Configure transmit arbiter(s) */
+	SK_IF_WRITE_1(sc_if, 0, SK_TXAR1_COUNTERCTL, SK_TXARCTL_ON);
+#if 0
+	    SK_TXARCTL_ON|SK_TXARCTL_FSYNC_ON);
+#endif
+
+	/* Configure RAMbuffers */
+	SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_CTLTST, SK_RBCTL_UNRESET);
+	SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_START, sc_if->sk_rx_ramstart);
+	SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_WR_PTR, sc_if->sk_rx_ramstart);
+	SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_RD_PTR, sc_if->sk_rx_ramstart);
+	SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_END, sc_if->sk_rx_ramend);
+	SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_CTLTST, SK_RBCTL_ON);
+
+	SK_IF_WRITE_4(sc_if, 1, SK_TXRBA1_CTLTST, SK_RBCTL_UNRESET);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXRBA1_CTLTST, SK_RBCTL_STORENFWD_ON);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXRBA1_START, sc_if->sk_tx_ramstart);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXRBA1_WR_PTR, sc_if->sk_tx_ramstart);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXRBA1_RD_PTR, sc_if->sk_tx_ramstart);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXRBA1_END, sc_if->sk_tx_ramend);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXRBA1_CTLTST, SK_RBCTL_ON);
+
+	/* Configure BMUs */
+	SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, 0x00000016);
+	SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, 0x00000d28);
+	SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, 0x00000080);
+	SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_WATERMARK, 0x00000600);
+
+	SK_IF_WRITE_4(sc_if, 1, SK_TXQA1_BMU_CSR, 0x00000016);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXQA1_BMU_CSR, 0x00000d28);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXQA1_BMU_CSR, 0x00000080);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXQA1_WATERMARK, 0x00000600);
+
+	/* Make sure the sync transmit queue is disabled. */
+	SK_IF_WRITE_4(sc_if, 1, SK_TXRBS1_CTLTST, SK_RBCTL_RESET);
+
+	/* Init descriptors */
+	if (msk_init_rx_ring(sc_if) == ENOBUFS) {
+		aprint_error("%s: initialization failed: no "
+		    "memory for rx buffers\n", sc_if->sk_dev.dv_xname);
+		msk_stop(ifp,0);
+		splx(s);
+		return ENOBUFS;
+	}
+
+	if (msk_init_tx_ring(sc_if) == ENOBUFS) {
+		aprint_error("%s: initialization failed: no "
+		    "memory for tx buffers\n", sc_if->sk_dev.dv_xname);
+		msk_stop(ifp,0);
+		splx(s);
+		return ENOBUFS;
+	}
+
+	/* Set interrupt moderation if changed via sysctl. */
+	switch (sc->sk_type) {
+	case SK_YUKON_EC:
+		sk_imtimer_ticks = SK_IMTIMER_TICKS_YUKON_EC;
+		break;
+	default:
+		sk_imtimer_ticks = SK_IMTIMER_TICKS_YUKON;
+	}
+	imr = sk_win_read_4(sc, SK_IMTIMERINIT);
+	if (imr != SK_IM_USECS(sc->sk_int_mod)) {
+		sk_win_write_4(sc, SK_IMTIMERINIT,
+		    SK_IM_USECS(sc->sk_int_mod));
+		aprint_verbose("%s: interrupt moderation is %d us\n",
+		    sc->sk_dev.dv_xname, sc->sk_int_mod);
+	}
+
+	/* Initialize prefetch engine. */
+	SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_Y2_PREF_CSR, 0x00000001);
+	SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_Y2_PREF_CSR, 0x00000002);
+	SK_IF_WRITE_2(sc_if, 0, SK_RXQ1_Y2_PREF_LIDX, MSK_RX_RING_CNT - 1);
+	SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_Y2_PREF_ADDRLO,
+	    MSK_RX_RING_ADDR(sc_if, 0));
+	SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_Y2_PREF_ADDRHI,
+	    (u_int64_t)MSK_RX_RING_ADDR(sc_if, 0) >> 32);
+	SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_Y2_PREF_CSR, 0x00000008);
+	SK_IF_READ_4(sc_if, 0, SK_RXQ1_Y2_PREF_CSR);
+
+	SK_IF_WRITE_4(sc_if, 1, SK_TXQA1_Y2_PREF_CSR, 0x00000001);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXQA1_Y2_PREF_CSR, 0x00000002);
+	SK_IF_WRITE_2(sc_if, 1, SK_TXQA1_Y2_PREF_LIDX, MSK_TX_RING_CNT - 1);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXQA1_Y2_PREF_ADDRLO,
+	    MSK_TX_RING_ADDR(sc_if, 0));
+	SK_IF_WRITE_4(sc_if, 1, SK_TXQA1_Y2_PREF_ADDRHI,
+	    (u_int64_t)MSK_TX_RING_ADDR(sc_if, 0) >> 32);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXQA1_Y2_PREF_CSR, 0x00000008);
+	SK_IF_READ_4(sc_if, 1, SK_TXQA1_Y2_PREF_CSR);
+
+	SK_IF_WRITE_2(sc_if, 0, SK_RXQ1_Y2_PREF_PUTIDX,
+	    sc_if->sk_cdata.sk_rx_prod);
+
+	/* Configure interrupt handling */
+	if (sc_if->sk_port == SK_PORT_A)
+		sc->sk_intrmask |= SK_Y2_INTRS1;
+	else
+		sc->sk_intrmask |= SK_Y2_INTRS2;
+	sc->sk_intrmask |= SK_Y2_IMR_BMU;
+	CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask);
+
+	ifp->if_flags |= IFF_RUNNING;
+	ifp->if_flags &= ~IFF_OACTIVE;
+
+	callout_schedule(&sc_if->sk_tick_ch, hz);
+
+	splx(s);
+	return 0;
+}
+
+void
+msk_stop(struct ifnet *ifp, int disable)
+{
+	struct sk_if_softc	*sc_if = ifp->if_softc;
+	struct sk_softc		*sc = sc_if->sk_softc;
+	struct sk_txmap_entry	*dma;
+	int			i;
+
+	DPRINTFN(2, ("msk_stop\n"));
+
+	callout_stop(&sc_if->sk_tick_ch);
+
+	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
+
+	/* Stop transfer of Tx descriptors */
+
+	/* Stop transfer of Rx descriptors */
+
+	/* Turn off various components of this interface. */
+	SK_XM_SETBIT_2(sc_if, XM_GPIO, XM_GPIO_RESETMAC);
+	SK_IF_WRITE_1(sc_if,0, SK_RXMF1_CTRL_TEST, SK_RFCTL_RESET_SET);
+	SK_IF_WRITE_1(sc_if,0, SK_TXMF1_CTRL_TEST, SK_TFCTL_RESET_SET);
+	SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_BMU_CSR, SK_RXBMU_OFFLINE);
+	SK_IF_WRITE_4(sc_if, 0, SK_RXRB1_CTLTST, SK_RBCTL_RESET|SK_RBCTL_OFF);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXQA1_BMU_CSR, SK_TXBMU_OFFLINE);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXRBA1_CTLTST, SK_RBCTL_RESET|SK_RBCTL_OFF);
+	SK_IF_WRITE_1(sc_if, 0, SK_TXAR1_COUNTERCTL, SK_TXARCTL_OFF);
+	SK_IF_WRITE_1(sc_if, 0, SK_RXLED1_CTL, SK_RXLEDCTL_COUNTER_STOP);
+	SK_IF_WRITE_1(sc_if, 0, SK_TXLED1_CTL, SK_RXLEDCTL_COUNTER_STOP);
+	SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_OFF);
+	SK_IF_WRITE_1(sc_if, 0, SK_LINKLED1_CTL, SK_LINKLED_LINKSYNC_OFF);
+
+	SK_IF_WRITE_4(sc_if, 0, SK_RXQ1_Y2_PREF_CSR, 0x00000001);
+	SK_IF_WRITE_4(sc_if, 1, SK_TXQA1_Y2_PREF_CSR, 0x00000001);
+
+	/* Disable interrupts */
+	if (sc_if->sk_port == SK_PORT_A)
+		sc->sk_intrmask &= ~SK_Y2_INTRS1;
+	else
+		sc->sk_intrmask &= ~SK_Y2_INTRS2;
+	CSR_WRITE_4(sc, SK_IMR, sc->sk_intrmask);
+
+	SK_XM_READ_2(sc_if, XM_ISR);
+	SK_XM_WRITE_2(sc_if, XM_IMR, 0xFFFF);
+
+	/* Free RX and TX mbufs still in the queues. */
+	for (i = 0; i < MSK_RX_RING_CNT; i++) {
+		if (sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf != NULL) {
+			m_freem(sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf);
+			sc_if->sk_cdata.sk_rx_chain[i].sk_mbuf = NULL;
+		}
+	}
+
+	for (i = 0; i < MSK_TX_RING_CNT; i++) {
+		if (sc_if->sk_cdata.sk_tx_chain[i].sk_mbuf != NULL) {
+			m_freem(sc_if->sk_cdata.sk_tx_chain[i].sk_mbuf);
+			sc_if->sk_cdata.sk_tx_chain[i].sk_mbuf = NULL;
+#if 1
+			SIMPLEQ_INSERT_HEAD(&sc_if->sk_txmap_head,
+			    sc_if->sk_cdata.sk_tx_map[i], link);
+			sc_if->sk_cdata.sk_tx_map[i] = 0;
+#endif
+		}
+	}
+
+#if 1
+	while ((dma = SIMPLEQ_FIRST(&sc_if->sk_txmap_head))) {
+		SIMPLEQ_REMOVE_HEAD(&sc_if->sk_txmap_head, link);
+		bus_dmamap_destroy(sc->sc_dmatag, dma->dmamap);
+		free(dma, M_DEVBUF);
+	}
+#endif
+}
+
+CFATTACH_DECL(mskc, sizeof(struct sk_softc), mskc_probe, mskc_attach,
+	NULL, NULL);
+
+CFATTACH_DECL(msk, sizeof(struct sk_if_softc), msk_probe, msk_attach,
+	NULL, NULL);
+
+#ifdef MSK_DEBUG
+void
+msk_dump_txdesc(struct msk_tx_desc *le, int idx)
+{
+#define DESC_PRINT(X)					\
+	if (X)					\
+		printf("txdesc[%d]." #X "=%#x\n",	\
+		       idx, X);
+
+	DESC_PRINT(letoh32(le->sk_addr));
+	DESC_PRINT(letoh16(le->sk_len));
+	DESC_PRINT(le->sk_ctl);
+	DESC_PRINT(le->sk_opcode);
+#undef DESC_PRINT
+}
+
+void
+msk_dump_bytes(const char *data, int len)
+{
+	int c, i, j;
+
+	for (i = 0; i < len; i += 16) {
+		printf("%08x  ", i);
+		c = len - i;
+		if (c > 16) c = 16;
+
+		for (j = 0; j < c; j++) {
+			printf("%02x ", data[i + j] & 0xff);
+			if ((j & 0xf) == 7 && j > 0)
+				printf(" ");
+		}
+		
+		for (; j < 16; j++)
+			printf("   ");
+		printf("  ");
+
+		for (j = 0; j < c; j++) {
+			int ch = data[i + j] & 0xff;
+			printf("%c", ' ' <= ch && ch <= '~' ? ch : ' ');
+		}
+		
+		printf("\n");
+		
+		if (c < 16)
+			break;
+	}
+}
+
+void
+msk_dump_mbuf(struct mbuf *m)
+{
+	int count = m->m_pkthdr.len;
+
+	printf("m=%p, m->m_pkthdr.len=%d\n", m, m->m_pkthdr.len);
+
+	while (count > 0 && m) {
+		printf("m=%p, m->m_data=%p, m->m_len=%d\n",
+		       m, m->m_data, m->m_len);
+		msk_dump_bytes(mtod(m, char *), m->m_len);
+
+		count -= m->m_len;
+		m = m->m_next;
+	}
+}
+#endif
+
+static int
+msk_sysctl_handler(SYSCTLFN_ARGS)
+{
+	int error, t;
+	struct sysctlnode node;
+	struct sk_softc *sc;
+
+	node = *rnode;
+	sc = node.sysctl_data;
+	t = sc->sk_int_mod;
+	node.sysctl_data = &t;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	if (t < SK_IM_MIN || t > SK_IM_MAX)
+		return EINVAL;
+
+	/* update the softc with sysctl-changed value, and mark
+	   for hardware update */
+	sc->sk_int_mod = t;
+	sc->sk_int_mod_pending = 1;
+	return 0;
+}
+
+/*
+ * Set up sysctl(3) MIB, hw.sk.* - Individual controllers will be
+ * set up in skc_attach()
+ */
+SYSCTL_SETUP(sysctl_msk, "sysctl msk subtree setup")
+{
+	int rc;
+	const struct sysctlnode *node;
+
+	if ((rc = sysctl_createv(clog, 0, NULL, NULL,
+	    0, CTLTYPE_NODE, "hw", NULL,
+	    NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) {
+		goto err;
+	}
+
+	if ((rc = sysctl_createv(clog, 0, NULL, &node,
+	    0, CTLTYPE_NODE, "msk",
+	    SYSCTL_DESCR("msk interface controls"),
+	    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) {
+		goto err;
+	}
+
+	msk_root_num = node->sysctl_num;
+	return;
+
+err:
+	aprint_error("%s: syctl_createv failed (rc = %d)\n", __func__, rc);
+}
Index: dev/pci/if_mskvar.h
===================================================================
RCS file: dev/pci/if_mskvar.h
diff -N dev/pci/if_mskvar.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ dev/pci/if_mskvar.h	9 Sep 2006 03:26:23 -0000
@@ -0,0 +1,257 @@
+/*	$OpenBSD: if_mskvar.h,v 1.1 2006/08/16 21:06:23 kettenis Exp $	*/
+/*	$NetBSD: if_skvar.h,v 1.6 2005/05/30 04:35:22 christos Exp $	*/
+
+/*-
+ * Copyright (c) 2003 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*	$OpenBSD: if_mskvar.h,v 1.1 2006/08/16 21:06:23 kettenis Exp $	*/
+
+/*
+ * Copyright (c) 1997, 1998, 1999, 2000
+ *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Bill Paul.
+ * 4. Neither the name of the author nor the names of any co-contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
+ * 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.
+ *
+ * $FreeBSD: /c/ncvs/src/sys/pci/if_skreg.h,v 1.9 2000/04/22 02:16:37 wpaul Exp $
+ */
+
+/*
+ * Copyright (c) 2003 Nathan L. Binkert <binkertn@umich.edu>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _DEV_PCI_IF_MSKVAR_H_
+#define _DEV_PCI_IF_MSKVAR_H_
+
+#include "rnd.h"
+
+#if NRND > 0
+#include <sys/rnd.h>
+#endif
+
+struct sk_jpool_entry {
+	int                             slot;
+	LIST_ENTRY(sk_jpool_entry)	jpool_entries;
+};
+
+struct sk_chain {
+	void			*sk_le;
+	struct mbuf		*sk_mbuf;
+	struct sk_chain		*sk_next;
+};
+
+/*
+ * Number of DMA segments in a TxCB. Note that this is carefully
+ * chosen to make the total struct size an even power of two. It's
+ * critical that no TxCB be split across a page boundary since
+ * no attempt is made to allocate physically contiguous memory.
+ *
+ */
+#define SK_NTXSEG      30
+
+struct sk_txmap_entry {
+	bus_dmamap_t			dmamap;
+	SIMPLEQ_ENTRY(sk_txmap_entry)	link;
+};
+
+struct msk_chain_data {
+	struct sk_chain		sk_tx_chain[MSK_TX_RING_CNT];
+	struct sk_chain		sk_rx_chain[MSK_RX_RING_CNT];
+	struct sk_txmap_entry	*sk_tx_map[MSK_TX_RING_CNT];
+	bus_dmamap_t		sk_rx_map[MSK_RX_RING_CNT];
+	bus_dmamap_t		sk_rx_jumbo_map;
+	int			sk_tx_prod;
+	int			sk_tx_cons;
+	int			sk_tx_cnt;
+	int			sk_rx_prod;
+	int			sk_rx_cons;
+	int			sk_rx_cnt;
+	/* Stick the jumbo mem management stuff here too. */
+	caddr_t			sk_jslots[MSK_JSLOTS];
+	void			*sk_jumbo_buf;
+};
+
+struct msk_ring_data {
+	struct msk_tx_desc	sk_tx_ring[MSK_TX_RING_CNT];
+	struct msk_rx_desc	sk_rx_ring[MSK_RX_RING_CNT];
+};
+
+#define MSK_TX_RING_ADDR(sc, i) \
+    ((sc)->sk_ring_map->dm_segs[0].ds_addr + \
+     offsetof(struct msk_ring_data, sk_tx_ring[(i)]))
+
+#define MSK_RX_RING_ADDR(sc, i) \
+    ((sc)->sk_ring_map->dm_segs[0].ds_addr + \
+     offsetof(struct msk_ring_data, sk_rx_ring[(i)]))
+
+#define MSK_CDOFF(x)	offsetof(struct msk_ring_data, x)
+#define MSK_CDTXOFF(x)	MSK_CDOFF(sk_tx_ring[(x)])
+#define MSK_CDRXOFF(x)	MSK_CDOFF(sk_rx_ring[(x)])
+#define MSK_CDSTOFF(x)	((x) * sizeof(struct msk_status_desc))
+
+#define MSK_CDTXSYNC(sc, x, n, ops)					\
+do {									\
+	int __x, __n;							\
+									\
+	__x = (x);							\
+	__n = (n);							\
+									\
+	/* If it will wrap around, sync to the end of the ring. */	\
+	if ((__x + __n) > MSK_TX_RING_CNT) {				\
+		bus_dmamap_sync((sc)->sk_softc->sc_dmatag,		\
+		    (sc)->sk_ring_map, MSK_CDTXOFF(__x),		\
+		    sizeof(struct msk_tx_desc) * (MSK_TX_RING_CNT - __x), \
+		    (ops));						\
+		__n -= (MSK_TX_RING_CNT - __x);				\
+		__x = 0;						\
+	}								\
+									\
+	/* Now sync whatever is left. */				\
+	bus_dmamap_sync((sc)->sk_softc->sc_dmatag, (sc)->sk_ring_map,	\
+	    MSK_CDTXOFF((__x)), sizeof(struct msk_tx_desc) * __n, (ops)); \
+} while (/*CONSTCOND*/0)
+
+#define MSK_CDRXSYNC(sc, x, ops)					\
+do {									\
+	bus_dmamap_sync((sc)->sk_softc->sc_dmatag, (sc)->sk_ring_map,	\
+	    MSK_CDRXOFF((x)), sizeof(struct msk_rx_desc), (ops));	\
+} while (/*CONSTCOND*/0)
+
+#define MSK_CDSTSYNC(sc, x, ops)					\
+do {									\
+	bus_dmamap_sync((sc)->sc_dmatag, (sc)->sk_status_map,		\
+	    MSK_CDSTOFF((x)), sizeof(struct msk_status_desc), (ops));	\
+} while (/*CONSTCOND*/0)
+
+#define SK_INC(x, y)	(x) = (x + 1) % y
+
+/* Forward decl. */
+struct sk_if_softc;
+
+/* Softc for the Yukon-II controller. */
+struct sk_softc {
+	struct device		sk_dev;		/* generic device */
+	bus_space_handle_t	sk_bhandle;	/* bus space handle */
+	bus_space_tag_t		sk_btag;	/* bus space tag */
+	void			*sk_intrhand;	/* irq handler handle */
+	u_int8_t		sk_coppertype;
+	u_int8_t		sk_pmd;		/* physical media type */
+	u_int8_t		sk_type;
+	u_int8_t		sk_rev;
+	u_int8_t		sk_macs;	/* # of MACs */
+	const char		*sk_name;
+	u_int32_t		sk_rboff;	/* RAMbuffer offset */
+	u_int32_t		sk_ramsize;	/* amount of RAM on NIC */
+	u_int32_t		sk_intrmask;
+	struct sysctllog	*sk_clog;
+	int			sk_int_mod;
+	int			sk_int_mod_pending;
+	bus_dma_tag_t		sc_dmatag;
+	struct sk_if_softc	*sk_if[2];
+	struct msk_status_desc	*sk_status_ring;
+	bus_dmamap_t		sk_status_map;
+	int			sk_status_idx;
+#if NRND > 0
+	rndsource_element_t     rnd_source;
+#endif
+};
+
+/* Softc for each logical interface */
+struct sk_if_softc {
+	struct device		sk_dev;		/* generic device */
+	struct ethercom		sk_ethercom;	/* interface info */
+	struct mii_data		sk_mii;
+	u_int8_t		sk_enaddr[ETHER_ADDR_LEN]; /* station addr */
+	u_int8_t		sk_port;	/* port # on controller */
+	u_int32_t		sk_rx_ramstart;
+	u_int32_t		sk_rx_ramend;
+	u_int32_t		sk_tx_ramstart;
+	u_int32_t		sk_tx_ramend;
+	u_int8_t		sk_phytype;
+	int			sk_phyaddr;
+	int			sk_cnt;
+	int			sk_link;
+	struct callout		sk_tick_ch;
+	struct msk_chain_data	sk_cdata;
+	struct msk_ring_data	*sk_rdata;
+	bus_dmamap_t		sk_ring_map;
+	int			sk_status_idx;
+	struct sk_softc		*sk_softc;	/* parent controller */
+	int			sk_if_flags;
+	LIST_HEAD(__sk_jfreehead, sk_jpool_entry)	sk_jfree_listhead;
+	LIST_HEAD(__sk_jinusehead, sk_jpool_entry)	sk_jinuse_listhead;
+	SIMPLEQ_HEAD(__sk_txmaphead, sk_txmap_entry)	sk_txmap_head;
+};
+
+struct skc_attach_args {
+	u_int16_t	skc_port;
+	u_int8_t	skc_type;
+	u_int8_t	skc_rev;
+};
+
+#endif /* _DEV_PCI_IF_MSKVAR_H_ */
Index: dev/pci/if_skreg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_skreg.h,v
retrieving revision 1.7
diff -u -r1.7 if_skreg.h
--- dev/pci/if_skreg.h	31 May 2006 21:46:32 -0000	1.7
+++ dev/pci/if_skreg.h	9 Sep 2006 03:26:24 -0000
@@ -34,7 +34,7 @@
  */
 /*	$OpenBSD: if_skreg.h,v 1.10 2003/08/12 05:23:06 nate Exp $	*/
 /*	$OpenBSD: yukonreg.h,v 1.2 2003/08/12 05:23:06 nate Exp $	*/
-/*	$OpenBSD: xmaciireg.h,v 1.2.4.1 2001/05/14 22:26:01 niklas Exp $ */
+/*	$OpenBSD: if_skreg.h,v 1.37 2006/08/16 21:06:23 kettenis Exp $	*/
 
 /*
  * Copyright (c) 1997, 1998, 1999, 2000
@@ -177,6 +177,11 @@
 #define SK_IESR		0x0010	/* interrupt hardware error source */
 #define SK_IEMR		0x0014  /* interrupt hardware error mask */
 #define SK_ISSR		0x0018	/* special interrupt source */
+#define SK_Y2_ISSR2	0x001C
+#define SK_Y2_ISSR3	0x0020
+#define SK_Y2_EISR	0x0024
+#define SK_Y2_LISR	0x0028
+#define SK_Y2_ICR	0x002C
 #define SK_XM_IMR0	0x0020
 #define SK_XM_ISR0	0x0028
 #define SK_XM_PHYADDR0	0x0030
@@ -203,6 +208,8 @@
 #define SK_CSR_SW_IRQ_SET		0x0080
 #define SK_CSR_SLOTSIZE			0x0100 /* 1 == 64 bits, 0 == 32 */
 #define SK_CSR_BUSCLOCK			0x0200 /* 1 == 33/66 MHz, = 33 */
+#define SK_CSR_ASF_OFF			0x1000
+#define SK_CSR_ASF_ON			0x2000
 
 /* SK_LED register */
 #define SK_LED_GREEN_OFF		0x01
@@ -282,6 +289,30 @@
 #define SK_INTRS2	\
 	(SK_IMR_RX2_EOF|SK_IMR_TX2_S_EOF|SK_IMR_MAC2)
 
+#define SK_Y2_IMR_TX1_AS_CHECK		0x00000001
+#define SK_Y2_IMR_TX1_S_CHECK		0x00000002
+#define SK_Y2_IMR_RX1_CHECK		0x00000004
+#define SK_Y2_IMR_MAC1			0x00000008
+#define SK_Y2_IMR_PHY1			0x00000010
+#define SK_Y2_IMR_TX2_AS_CHECK		0x00000100
+#define SK_Y2_IMR_TX2_S_CHECK		0x00000200
+#define SK_Y2_IMR_RX2_CHECK		0x00000400
+#define SK_Y2_IMR_MAC2			0x00000800
+#define SK_Y2_IMR_PHY2			0x00001000
+#define SK_Y2_IMR_TIMER			0x01000000
+#define SK_Y2_IMR_SW			0x02000000
+#define SK_Y2_IMR_ASF			0x20000000
+#define SK_Y2_IMR_BMU			0x40000000
+#define SK_Y2_IMR_HWERR			0x80000000
+
+#define SK_Y2_INTRS1	\
+	(SK_Y2_IMR_RX1_CHECK|SK_Y2_IMR_TX1_AS_CHECK \
+	|SK_Y2_IMR_MAC1|SK_Y2_IMR_PHY1)
+
+#define SK_Y2_INTRS2	\
+	(SK_Y2_IMR_RX2_CHECK|SK_Y2_IMR_TX2_AS_CHECK \
+	|SK_Y2_IMR_MAC2|SK_Y2_IMR_PHY2)
+
 /* SK_IESR register */
 #define SK_IESR_PAR_RX2			0x00000001
 #define SK_IESR_PAR_RX1			0x00000002
@@ -323,7 +354,9 @@
 #define SK_CHIPVER	0x011B
 #define SK_EPROM0	0x011C
 #define SK_EPROM1	0x011D
+#define SK_Y2_CLKGATE	0x011D		/* yukon 2 */
 #define SK_EPROM2	0x011E
+#define SK_Y2_HWRES	0x011E		/* yukon 2 */
 #define SK_EPROM3	0x011F
 #define SK_EP_ADDR	0x0120
 #define SK_EP_DATA	0x0124
@@ -362,17 +395,34 @@
 #define SK_YUKON_EC		0xB6
 #define SK_YUKON_FE		0xB7
 #define SK_YUKON_FAMILY(x) ((x) & 0xB0)
+
+#define SK_IS_GENESIS(sc) \
+    ((sc)->sk_type == SK_GENESIS)
+#define SK_IS_YUKON(sc) \
+    ((sc)->sk_type >= SK_YUKON && (sc)->sk_type <= SK_YUKON_FE)
+#define SK_IS_YUKON2(sc) \
+    ((sc)->sk_type >= SK_YUKON_XL && (sc)->sk_type <= SK_YUKON_FE)
+
 /* known revisions in SK_CONFIG */
 #define SK_YUKON_LITE_REV_A0	0x0 /* invented, see test in skc_attach */
 #define SK_YUKON_LITE_REV_A1	0x3
 #define SK_YUKON_LITE_REV_A3	0x7
 
+#define SK_YUKON_XL_REV_A0	0x0
+#define SK_YUKON_XL_REV_A1	0x1
+#define SK_YUKON_XL_REV_A2	0x2
+#define SK_YUKON_XL_REV_A3	0x3
+
 #define SK_YUKON_EC_REV_A1	0x0
 #define SK_YUKON_EC_REV_A2	0x1
 #define SK_YUKON_EC_REV_A3	0x2
 
-#define SK_IMCTL_STOP	0x02
-#define SK_IMCTL_START	0x04
+#define SK_YUKON_EC_U_REV_A0	0x1
+#define SK_YUKON_EC_U_REV_A1	0x2
+
+#define SK_IMCTL_IRQ_CLEAR	0x01
+#define SK_IMCTL_STOP		0x02
+#define SK_IMCTL_START		0x04
 
 /* Number of ticks per usec for interrupt moderation */
 #define SK_IMTIMER_TICKS_GENESIS	54
@@ -449,6 +499,20 @@
 #define SK_GPIO_DIR8		0x01000000
 #define SK_GPIO_DIR9           0x02000000
 
+#define SK_Y2_CLKGATE_LINK2_INACTIVE    0x80    /* port 2 inactive */
+#define SK_Y2_CLKGATE_LINK2_GATE_DIS    0x40    /* disable clock gate, 2 */
+#define SK_Y2_CLKGATE_LINK2_CORE_DIS    0x20    /* disable core clock, 2 */
+#define SK_Y2_CLKGATE_LINK2_PCI_DIS     0x10    /* disable pci clock, 2 */
+#define SK_Y2_CLKGATE_LINK1_INACTIVE    0x08    /* port 1 inactive */
+#define SK_Y2_CLKGATE_LINK1_GATE_DIS    0x04    /* disable clock gate, 1 */
+#define SK_Y2_CLKGATE_LINK1_CORE_DIS    0x02    /* disable core clock, 1 */
+#define SK_Y2_CLKGATE_LINK1_PCI_DIS     0x01    /* disable pci clock, 1 */
+
+#define SK_Y2_HWRES_LINK_1      0x01
+#define SK_Y2_HWRES_LINK_2      0x02
+#define SK_Y2_HWRES_LINK_MASK   (SK_Y2_HWRES_LINK_1 | SK_Y2_HWRES_LINK_2)
+#define SK_Y2_HWRES_LINK_DUAL   (SK_Y2_HWRES_LINK_1 | SK_Y2_HWRES_LINK_2)
+
 /* Block 3 Ram interface and MAC arbiter registers */
 #define SK_RAMADDR	0x0180
 #define SK_RAMDATA0	0x0184
@@ -614,6 +678,28 @@
 #define SK_RXQ1_TEST1		0x043C
 #define SK_RXQ1_TEST2		0x0440
 #define SK_RXQ1_TEST3		0x0444
+/* yukon-2 only */
+#define SK_RXQ1_Y2_WM           0x0440
+#define SK_RXQ1_Y2_AL           0x0442
+#define SK_RXQ1_Y2_RSP          0x0444
+#define SK_RXQ1_Y2_RSL          0x0446
+#define SK_RXQ1_Y2_RP           0x0448
+#define SK_RXQ1_Y2_RL           0x044A
+#define SK_RXQ1_Y2_WP           0x044C
+#define SK_RXQ1_Y2_WSP          0x044D
+#define SK_RXQ1_Y2_WL           0x044E
+#define SK_RXQ1_Y2_WSL          0x044F
+/* yukon-2 only (prefetch unit) */
+#define SK_RXQ1_Y2_PREF_CSR     0x0450
+#define SK_RXQ1_Y2_PREF_LIDX    0x0454
+#define SK_RXQ1_Y2_PREF_ADDRLO  0x0458
+#define SK_RXQ1_Y2_PREF_ADDRHI  0x045C
+#define SK_RXQ1_Y2_PREF_GETIDX  0x0460
+#define SK_RXQ1_Y2_PREF_PUTIDX  0x0464
+#define SK_RXQ1_Y2_PREF_FIFOWP  0x0470
+#define SK_RXQ1_Y2_PREF_FIFORP  0x0474
+#define SK_RXQ1_Y2_PREF_FIFOWM  0x0478
+#define SK_RXQ1_Y2_PREF_FIFOLV  0x047C
 
 /* Block 9 -- RX queue 2 */
 #define SK_RXQ2_BUFCNT		0x0480
@@ -638,6 +724,28 @@
 #define SK_RXQ2_TEST1		0x04BC
 #define SK_RXQ2_TEST2		0x04C0
 #define SK_RXQ2_TEST3		0x04C4
+/* yukon-2 only */
+#define SK_RXQ2_Y2_WM           0x04C0
+#define SK_RXQ2_Y2_AL           0x04C2
+#define SK_RXQ2_Y2_RSP          0x04C4
+#define SK_RXQ2_Y2_RSL          0x04C6
+#define SK_RXQ2_Y2_RP           0x04C8
+#define SK_RXQ2_Y2_RL           0x04CA
+#define SK_RXQ2_Y2_WP           0x04CC
+#define SK_RXQ2_Y2_WSP          0x04CD
+#define SK_RXQ2_Y2_WL           0x04CE
+#define SK_RXQ2_Y2_WSL          0x04CF
+/* yukon-2 only (prefetch unit) */
+#define SK_RXQ2_Y2_PREF_CSR     0x04D0
+#define SK_RXQ2_Y2_PREF_LIDX    0x04D4
+#define SK_RXQ2_Y2_PREF_ADDRLO  0x04D8
+#define SK_RXQ2_Y2_PREF_ADDRHI  0x04DC
+#define SK_RXQ2_Y2_PREF_GETIDX  0x04E0
+#define SK_RXQ2_Y2_PREF_PUTIDX  0x04E4
+#define SK_RXQ2_Y2_PREF_FIFOWP  0x04F0
+#define SK_RXQ2_Y2_PREF_FIFORP  0x04F4
+#define SK_RXQ2_Y2_PREF_FIFOWM  0x04F8
+#define SK_RXQ2_Y2_PREF_FIFOLV  0x04FC
 
 #define SK_RXBMU_CLR_IRQ_ERR		0x00000001
 #define SK_RXBMU_CLR_IRQ_EOF		0x00000002
@@ -696,6 +804,17 @@
 #define SK_TXQS1_TEST1		0x063C
 #define SK_TXQS1_TEST2		0x0640
 #define SK_TXQS1_TEST3		0x0644
+/* yukon-2 only (prefetch unit) */
+#define SK_TXQS1_Y2_PREF_CSR    0x0650
+#define SK_TXQS1_Y2_PREF_LIDX   0x0654
+#define SK_TXQS1_Y2_PREF_ADDRLO 0x0658
+#define SK_TXQS1_Y2_PREF_ADDRHI 0x065C
+#define SK_TXQS1_Y2_PREF_GETIDX 0x0660 
+#define SK_TXQS1_Y2_PREF_PUTIDX 0x0664
+#define SK_TXQS1_Y2_PREF_FIFOWP 0x0670
+#define SK_TXQS1_Y2_PREF_FIFORP 0x0674
+#define SK_TXQS1_Y2_PREF_FIFOWM 0x0678
+#define SK_TXQS1_Y2_PREF_FIFOLV 0x067C
 
 /* Block 13 -- TX async queue 1 */
 #define SK_TXQA1_BUFCNT		0x0680
@@ -718,6 +837,30 @@
 #define SK_TXQA1_TEST1		0x06BC
 #define SK_TXQA1_TEST2		0x06C0
 #define SK_TXQA1_TEST3		0x06C4
+/* yukon-2 only */
+#define SK_TXQA1_Y2_WM          0x06C0
+#define SK_TXQA1_Y2_AL          0x06C2
+#define SK_TXQA1_Y2_RSP         0x06C4
+#define SK_TXQA1_Y2_RSL         0x06C6
+#define SK_TXQA1_Y2_RP          0x06C8
+#define SK_TXQA1_Y2_RL          0x06CA
+#define SK_TXQA1_Y2_WP          0x06CC
+#define SK_TXQA1_Y2_WSP         0x06CD
+#define SK_TXQA1_Y2_WL          0x06CE
+#define SK_TXQA1_Y2_WSL         0x06CF
+/* yukon-2 only (prefetch unit) */
+#define SK_TXQA1_Y2_PREF_CSR    0x06D0
+#define SK_TXQA1_Y2_PREF_LIDX   0x06D4
+#define SK_TXQA1_Y2_PREF_ADDRLO 0x06D8
+#define SK_TXQA1_Y2_PREF_ADDRHI 0x06DC
+#define SK_TXQA1_Y2_PREF_GETIDX 0x06E0
+#define SK_TXQA1_Y2_PREF_PUTIDX 0x06E4
+#define SK_TXQA1_Y2_PREF_FIFOWP 0x06F0
+#define SK_TXQA1_Y2_PREF_PUTIDX 0x06E4
+#define SK_TXQA1_Y2_PREF_FIFOWP 0x06F0
+#define SK_TXQA1_Y2_PREF_FIFORP 0x06F4
+#define SK_TXQA1_Y2_PREF_FIFOWM 0x06F8
+#define SK_TXQA1_Y2_PREF_FIFOLV 0x06FC
 
 /* Block 14 -- TX sync queue 2 */
 #define SK_TXQS2_BUFCNT		0x0700
@@ -740,6 +883,28 @@
 #define SK_TXQS2_TEST1		0x073C
 #define SK_TXQS2_TEST2		0x0740
 #define SK_TXQS2_TEST3		0x0744
+/* yukon-2 only */
+#define SK_TXQS2_Y2_WM          0x0740
+#define SK_TXQS2_Y2_AL          0x0742
+#define SK_TXQS2_Y2_RSP         0x0744
+#define SK_TXQS2_Y2_RSL         0x0746
+#define SK_TXQS2_Y2_RP          0x0748
+#define SK_TXQS2_Y2_RL          0x074A
+#define SK_TXQS2_Y2_WP          0x074C
+#define SK_TXQS2_Y2_WSP         0x074D
+#define SK_TXQS2_Y2_WL          0x074E
+#define SK_TXQS2_Y2_WSL         0x074F
+/* yukon-2 only (prefetch unit) */
+#define SK_TXQS2_Y2_PREF_CSR    0x0750
+#define SK_TXQS2_Y2_PREF_LIDX   0x0754
+#define SK_TXQS2_Y2_PREF_ADDRLO 0x0758
+#define SK_TXQS2_Y2_PREF_ADDRHI 0x075C
+#define SK_TXQS2_Y2_PREF_GETIDX 0x0760
+#define SK_TXQS2_Y2_PREF_PUTIDX 0x0764
+#define SK_TXQS2_Y2_PREF_FIFOWP 0x0770
+#define SK_TXQS2_Y2_PREF_FIFORP 0x0774
+#define SK_TXQS2_Y2_PREF_FIFOWM 0x0778
+#define SK_TXQS2_Y2_PREF_FIFOLV 0x077C
 
 /* Block 15 -- TX async queue 2 */
 #define SK_TXQA2_BUFCNT		0x0780
@@ -762,6 +927,28 @@
 #define SK_TXQA2_TEST1		0x07BC
 #define SK_TXQA2_TEST2		0x07C0
 #define SK_TXQA2_TEST3		0x07C4
+/* yukon-2 only */
+#define SK_TXQA2_Y2_WM          0x07C0
+#define SK_TXQA2_Y2_AL          0x07C2
+#define SK_TXQA2_Y2_RSP         0x07C4
+#define SK_TXQA2_Y2_RSL         0x07C6
+#define SK_TXQA2_Y2_RP          0x07C8
+#define SK_TXQA2_Y2_RL          0x07CA
+#define SK_TXQA2_Y2_WP          0x07CC
+#define SK_TXQA2_Y2_WSP         0x07CD
+#define SK_TXQA2_Y2_WL          0x07CE
+#define SK_TXQA2_Y2_WSL         0x07CF
+/* yukon-2 only (prefetch unit) */
+#define SK_TXQA2_Y2_PREF_CSR    0x07D0
+#define SK_TXQA2_Y2_PREF_LIDX   0x07D4
+#define SK_TXQA2_Y2_PREF_ADDRLO 0x07D8
+#define SK_TXQA2_Y2_PREF_ADDRHI 0x07DC
+#define SK_TXQA2_Y2_PREF_GETIDX 0x07E0
+#define SK_TXQA2_Y2_PREF_PUTIDX 0x07E4
+#define SK_TXQA2_Y2_PREF_FIFOWP 0x07F0
+#define SK_TXQA2_Y2_PREF_FIFORP 0x07F4
+#define SK_TXQA2_Y2_PREF_FIFOWM 0x07F8
+#define SK_TXQA2_Y2_PREF_FIFOLV 0x07FC
 
 #define SK_TXBMU_CLR_IRQ_ERR		0x00000001
 #define SK_TXBMU_CLR_IRQ_EOF		0x00000002
@@ -891,6 +1078,8 @@
 #define SK_RXMF1_END		0x0C40
 #define SK_RXMF1_THRESHOLD	0x0C44
 #define SK_RXMF1_CTRL_TEST	0x0C48
+#define SK_RXMF1_FLUSH_MASK     0x0C4C
+#define SK_RXMF1_FLUSH_THRESHOLD        0x0C50
 #define SK_RXMF1_WRITE_PTR	0x0C60
 #define SK_RXMF1_WRITE_LEVEL	0x0C68
 #define SK_RXMF1_READ_PTR	0x0C70
@@ -902,6 +1091,8 @@
 #define SK_RFCTL_RD_PTR_TST_ON	0x00000400	/* Read pointer test on */
 #define SK_RFCTL_RD_PTR_TST_OFF	0x00000200	/* Read pointer test off */
 #define SK_RFCTL_RD_PTR_STEP	0x00000100	/* Read pointer increment */
+#define SK_RFCTL_FIFO_FLUSH_OFF 0x00000080      /* RX FIFO Flsuh mode off */
+#define SK_RFCTL_FIFO_FLUSH_ON  0x00000040      /* RX FIFO Flush mode on */
 #define SK_RFCTL_RX_FIFO_OVER	0x00000040	/* Clear IRQ RX FIFO Overrun */
 #define SK_RFCTL_FRAME_RX_DONE	0x00000010	/* Clear IRQ Frame RX Done */
 #define SK_RFCTL_OPERATION_ON	0x00000008	/* Operational mode on */
@@ -909,6 +1100,7 @@
 #define SK_RFCTL_RESET_CLEAR	0x00000002	/* MAC FIFO Reset Clear */
 #define SK_RFCTL_RESET_SET	0x00000001	/* MAC FIFO Reset Set */
 
+#define SK_RFCTL_FIFO_THRESHOLD 0x0a    /* flush threshold (default) */
 
 /* Block 25 -- RX MAC FIFO 2 regisrers and LINK_SYNC counter */
 #define SK_RXF2_END		0x0C80
@@ -1046,7 +1238,48 @@
 #define SK_DPT_TTEST_OFF	0x0002	/* Test Mode Off */
 #define SK_DPT_TTEST_ON		0x0004	/* Test Mode On */
 
-/* Block 29 -- reserved */
+#define SK_TSTAMP_COUNT		0x0e14
+#define SK_TSTAMP_CTL		0x0e18
+
+#define SK_TSTAMP_IRQ_CLEAR	0x01
+#define SK_TSTAMP_STOP		0x02
+#define SK_TSTAMP_START		0x04
+
+#define SK_Y2_ASF_CSR		0x0e68
+
+#define SK_Y2_ASF_RESET		0x08
+
+#define SK_Y2_LEV_ITIMERINIT	0x0eb0
+#define SK_Y2_LEV_ITIMERCTL	0x0eb8
+#define SK_Y2_TX_ITIMERINIT	0x0ec0
+#define SK_Y2_TX_ITIMERCTL	0x0ec8
+#define SK_Y2_ISR_ITIMERINIT	0x0ed0
+#define SK_Y2_ISR_ITIMERCTL	0x0ed8
+
+/* Block 29 -- Status BMU (Yukon-2 only) */
+#define SK_STAT_BMU_CSR		0x0e80
+#define SK_STAT_BMU_LIDX	0x0e84
+#define SK_STAT_BMU_ADDRLO	0x0e88
+#define SK_STAT_BMU_ADDRHI	0x0e8c
+#define SK_STAT_BMU_TXA1_RIDX	0x0e90
+#define SK_STAT_BMU_TXS1_RIDX	0x0e92
+#define SK_STAT_BMU_TXA2_RIDX	0x0e94
+#define SK_STAT_BMU_TXS2_RIDX	0x0e96
+#define SK_STAT_BMU_TX_THRESH	0x0e98
+#define SK_STAT_BMU_PUTIDX	0x0e9c
+#define SK_STAT_BMU_FIFOWP	0x0ea0
+#define SK_STAT_BMU_FIFORP	0x0ea4
+#define SK_STAT_BMU_FIFORSP	0x0ea6
+#define SK_STAT_BMU_FIFOLV	0x0ea8
+#define SK_STAT_BMU_FIFOSLV	0x0eaa
+#define SK_STAT_BMU_FIFOWM	0x0eac
+#define SK_STAT_BMU_FIFOIWM	0x0ead
+
+#define SK_STAT_BMU_RESET	0x00000001
+#define SK_STAT_BMU_UNRESET	0x00000002
+#define SK_STAT_BMU_OFF		0x00000004
+#define SK_STAT_BMU_ON		0x00000008
+#define SK_STAT_BMU_IRQ_CLEAR	0x00000010
 
 /* Block 30 -- GMAC/GPHY Control Registers (Yukon Only)*/
 #define SK_GMAC_CTRL		0x0f00	/* GMAC Control Register */
@@ -1373,6 +1606,45 @@
 #define SK_TX_RING_CNT		512
 #define SK_RX_RING_CNT		256
 
+struct msk_rx_desc {
+	u_int32_t		sk_addr;
+	u_int16_t		sk_len;
+	u_int8_t		sk_ctl;
+	u_int8_t		sk_opcode;
+} __packed;
+
+#define SK_Y2_RXOPC_BUFFER	0x40
+#define SK_Y2_RXOPC_PACKET	0x41
+#define SK_Y2_RXOPC_OWN		0x80
+
+struct msk_tx_desc {
+	u_int32_t		sk_addr;
+	u_int16_t		sk_len;
+	u_int8_t		sk_ctl;
+	u_int8_t		sk_opcode;
+} __packed;
+
+#define SK_Y2_TXCTL_LASTFRAG	0x80
+
+#define SK_Y2_TXOPC_BUFFER	0x40
+#define SK_Y2_TXOPC_PACKET	0x41
+#define SK_Y2_TXOPC_OWN		0x80
+
+struct msk_status_desc {
+	u_int32_t		sk_status;
+	u_int16_t		sk_len;
+	u_int8_t		sk_link;
+	u_int8_t		sk_opcode;
+} __packed;
+
+#define SK_Y2_STOPC_RXSTAT	0x60
+#define SK_Y2_STOPC_TXSTAT	0x68
+#define SK_Y2_STOPC_OWN		0x80
+
+#define MSK_TX_RING_CNT		512
+#define MSK_RX_RING_CNT		512
+#define MSK_STATUS_RING_CNT	2048
+
 /*
  * Jumbo buffer stuff. Note that we must allocate more jumbo
  * buffers than there are descriptors in the receive ring. This
@@ -1383,6 +1655,7 @@
  */
 #define SK_JUMBO_FRAMELEN	9018
 #define SK_JUMBO_MTU		(SK_JUMBO_FRAMELEN-ETHER_HDR_LEN-ETHER_CRC_LEN)
+#define SK_MIN_FRAMELEN		(ETHER_MIN_LEN - ETHER_CRC_LEN)
 #define SK_JSLOTS		384
 
 #define SK_JRAWLEN	(SK_JUMBO_FRAMELEN + ETHER_ALIGN)
@@ -1392,6 +1665,11 @@
 #define SK_RESID	(SK_JPAGESZ - (SK_JLEN * SK_JSLOTS) % SK_JPAGESZ)
 #define SK_JMEM		((SK_JLEN * SK_JSLOTS) + SK_RESID)
 
+#define MSK_JSLOTS		((MSK_RX_RING_CNT / 2) * 3)
+
+#define MSK_RESID	(SK_JPAGESZ - (SK_JLEN * MSK_JSLOTS) % SK_JPAGESZ)
+#define MSK_JMEM	((SK_JLEN * MSK_JSLOTS) + MSK_RESID)
+
 #define SK_MAXUNIT	256
 #define SK_TIMEOUT	1000
 #define ETHER_ALIGN	2
@@ -1551,6 +1829,24 @@
 #define YU_PAR_MIB_CLR		0x0020	/* MIB Counters Clear Mode */
 #define YU_PAR_LOAD_TSTCNT	0x0010	/* Load count 0xfffffff0 into cntr */
 
+/* Receive status */
+#define YU_RXSTAT_FOFL          0x00000001      /* Rx FIFO overflow */
+#define YU_RXSTAT_CRCERR        0x00000002      /* CRC error */
+#define YU_RXSTAT_FRAGMENT      0x00000008      /* fragment */
+#define YU_RXSTAT_LONGERR       0x00000010      /* too long packet */
+#define YU_RXSTAT_MIIERR        0x00000020      /* MII error */
+#define YU_RXSTAT_BADFC         0x00000040      /* bad flow-control packet */
+#define YU_RXSTAT_GOODFC        0x00000080      /* good flow-control packet */
+#define YU_RXSTAT_RXOK          0x00000100      /* receice OK (Good packet) */
+#define YU_RXSTAT_BROADCAST     0x00000200      /* broadcast packet */
+#define YU_RXSTAT_MULTICAST     0x00000400      /* multicast packet */
+#define YU_RXSTAT_RUNT          0x00000800      /* undersize packet */
+#define YU_RXSTAT_JABBER        0x00001000      /* jabber packet */
+#define YU_RXSTAT_VLAN          0x00002000      /* VLAN packet */
+#define YU_RXSTAT_LENSHIFT      16
+
+#define YU_RXSTAT_BYTES(x)      ((x) >> YU_RXSTAT_LENSHIFT)
+
 /*
  * Registers and data structures for the XaQti Corporation XMAC II
  * Gigabit Ethernet MAC. Datasheet is available from http://www.xaqti.com.
