changeset 13228:0a25729da430

9 Provide an open source implementation of spwr(7D) Reviewed by: garrett@nexenta.com, richlowe@richlowe.net Approved by: garrett@nexenta.com
author Steven Stallion <stallion@opensolaris.org>
date Wed, 27 Oct 2010 08:57:45 -0400
parents 6f4345d35518
children 178433b2c76a
files usr/src/pkg/manifests/driver-network-efe.mf usr/src/uts/common/Makefile.files usr/src/uts/common/Makefile.rules usr/src/uts/common/io/efe/THIRDPARTYLICENSE usr/src/uts/common/io/efe/THIRDPARTYLICENSE.descrip usr/src/uts/common/io/efe/efe.c usr/src/uts/common/io/efe/efe.h usr/src/uts/intel/Makefile.intel.shared usr/src/uts/intel/efe/Makefile usr/src/uts/intel/os/master usr/src/uts/sparc/Makefile.sparc.shared usr/src/uts/sparc/efe/Makefile
diffstat 12 files changed, 2334 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkg/manifests/driver-network-efe.mf	Wed Oct 27 08:57:45 2010 -0400
@@ -0,0 +1,32 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# The default for payload-bearing actions in this package is to appear in the
+# global zone only.  See the include file for greater detail, as well as
+# information about overriding the defaults.
+#
+<include global_zone_only_component>
+set name=pkg.fmri value=pkg:/driver/network/efe@$(PKGVERS)
+set name=pkg.description value="EPIC/100 Fast Ethernet Network Adapter Driver"
+set name=pkg.summary value="EPIC/100 Fast Ethernet Driver"
+set name=info.classification \
+    value=org.opensolaris.category.2008:Drivers/Networking
+set name=variant.arch value=$(ARCH)
+dir path=kernel group=sys
+dir path=kernel/drv group=sys
+dir path=kernel/drv/$(ARCH64) group=sys
+driver name=efe alias=pci10b8,5 clone_perms="efe 0666 root sys" \
+    perms="* 0666 root sys"
+file path=kernel/drv/$(ARCH64)/efe group=sys
+$(i386_ONLY)file path=kernel/drv/efe group=sys
+license usr/src/uts/common/io/efe/THIRDPARTYLICENSE \
+    license=usr/src/uts/common/io/efe/THIRDPARTYLICENSE
--- a/usr/src/uts/common/Makefile.files	Mon Oct 25 11:04:06 2010 -0700
+++ b/usr/src/uts/common/Makefile.files	Wed Oct 27 08:57:45 2010 -0400
@@ -1763,6 +1763,8 @@
 
 DMFE_OBJS += dmfe_log.o dmfe_main.o dmfe_mii.o
 
+EFE_OBJS += efe.o
+
 ELXL_OBJS += elxl.o
 
 HME_OBJS += hme.o
--- a/usr/src/uts/common/Makefile.rules	Mon Oct 25 11:04:06 2010 -0700
+++ b/usr/src/uts/common/Makefile.rules	Wed Oct 27 08:57:45 2010 -0400
@@ -712,6 +712,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
+$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/efe/%.c
+	$(COMPILE.c) -o $@ $<
+	$(CTFCONVERT_O)
+
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/elxl/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -2034,6 +2038,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/drm/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
+$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/efe/%.c
+	@($(LHEAD) $(LINT.c) $< $(LTAIL))
+
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/elxl/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/efe/THIRDPARTYLICENSE	Wed Oct 27 08:57:45 2010 -0400
@@ -0,0 +1,27 @@
+Copyright (c) 2010 Steven Stallion.  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. Neither the name of the copyright owner nor the names of any
+       contributors may be used to endorse or promote products derived
+       from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 COPYRIGHT OWNER 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.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/efe/THIRDPARTYLICENSE.descrip	Wed Oct 27 08:57:45 2010 -0400
@@ -0,0 +1,1 @@
+EPIC/100 FAST ETHERNET DRIVER
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/efe/efe.c	Wed Oct 27 08:57:45 2010 -0400
@@ -0,0 +1,1671 @@
+/*
+ * Copyright (c) 2010 Steven Stallion.  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. Neither the name of the copyright owner nor the names of any
+ *        contributors may be used to endorse or promote products derived
+ *        from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 COPYRIGHT OWNER 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.
+ */
+
+#include <sys/byteorder.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/varargs.h>
+#include <sys/cmn_err.h>
+#include <sys/note.h>
+#include <sys/kmem.h>
+#include <sys/conf.h>
+#include <sys/devops.h>
+#include <sys/modctl.h>
+#include <sys/sysmacros.h>
+#include <sys/ddi.h>
+#include <sys/ddi_intr.h>
+#include <sys/sunddi.h>
+#include <sys/stream.h>
+#include <sys/strsun.h>
+#include <sys/pci.h>
+#include <sys/ethernet.h>
+#include <sys/vlan.h>
+#include <sys/crc32.h>
+#include <sys/mii.h>
+#include <sys/mac.h>
+#include <sys/mac_ether.h>
+#include <sys/mac_provider.h>
+
+#include "efe.h"
+
+/* Autoconfiguration entry points */
+static int	efe_attach(dev_info_t *, ddi_attach_cmd_t);
+static int	efe_detach(dev_info_t *, ddi_detach_cmd_t);
+static int	efe_quiesce(dev_info_t *);
+
+/* MII entry points */
+static uint16_t	efe_mii_read(void *, uint8_t, uint8_t);
+static void	efe_mii_write(void *, uint8_t, uint8_t, uint16_t);
+static void	efe_mii_notify(void *, link_state_t);
+
+/* MAC entry points */
+static int	efe_m_getstat(void *, uint_t, uint64_t *);
+static int	efe_m_start(void *);
+static void	efe_m_stop(void *);
+static int	efe_m_setpromisc(void *, boolean_t);
+static int	efe_m_multicst(void *, boolean_t, const uint8_t *);
+static int	efe_m_unicst(void *, const uint8_t *);
+static mblk_t	*efe_m_tx(void *, mblk_t *);
+static int	efe_m_setprop(void *, const char *, mac_prop_id_t, uint_t,
+    const void *);
+static int	efe_m_getprop(void *, const char *, mac_prop_id_t, uint_t,
+    void *);
+static void	efe_m_propinfo(void *, const char *, mac_prop_id_t,
+    mac_prop_info_handle_t);
+
+/* ISR/periodic callbacks */
+static uint_t	efe_intr(caddr_t, caddr_t);
+
+/* Support functions */
+static void		efe_init(efe_t *);
+static void		efe_init_rx_ring(efe_t *);
+static void		efe_init_tx_ring(efe_t *);
+static void		efe_reset(efe_t *);
+static void		efe_start(efe_t *);
+static void		efe_stop(efe_t *);
+static void		efe_stop_dma(efe_t *);
+static inline void	efe_restart(efe_t *);
+static int		efe_suspend(efe_t *);
+static int		efe_resume(efe_t *);
+
+static efe_ring_t	*efe_ring_alloc(dev_info_t *, size_t);
+static void		efe_ring_free(efe_ring_t **);
+static efe_buf_t	*efe_buf_alloc(dev_info_t *, size_t);
+static void		efe_buf_free(efe_buf_t **);
+
+static void		efe_intr_enable(efe_t *);
+static void		efe_intr_disable(efe_t *);
+
+static mblk_t		*efe_recv(efe_t *);
+static mblk_t		*efe_recv_pkt(efe_t *, efe_desc_t *);
+
+static int		efe_send(efe_t *, mblk_t *);
+static void		efe_send_done(efe_t *);
+
+static void		efe_getaddr(efe_t *, uint8_t *);
+static void		efe_setaddr(efe_t *, uint8_t *);
+static void		efe_setmchash(efe_t *, uint16_t *);
+
+static void		efe_eeprom_read(efe_t *, uint8_t *, size_t, uint8_t);
+static uint16_t		efe_eeprom_readw(efe_t *, int, uint8_t);
+static inline int	efe_eeprom_readbit(efe_t *);
+static inline void	efe_eeprom_writebit(efe_t *, int);
+
+static void		efe_dprintf(dev_info_t *, int, const char *, ...);
+
+#ifdef DEBUG
+#define	efe_debug(dip, ...) \
+	efe_dprintf((dip), CE_CONT, __VA_ARGS__)
+#else
+#define	efe_debug(dip, ...)	/*EMPTY*/
+#endif
+
+#define	efe_error(dip, ...) \
+	efe_dprintf((dip), CE_WARN, __VA_ARGS__)
+
+extern struct mod_ops mod_driverops;
+
+DDI_DEFINE_STREAM_OPS(efe_dev_ops, nulldev, nulldev, efe_attach, efe_detach,
+    nodev, NULL, D_MP, NULL, efe_quiesce);
+
+static struct modldrv modldrv = {
+	&mod_driverops,			/* drv_modops */
+	"EPIC/100 Fast Ethernet",	/* drv_linkinfo */
+	&efe_dev_ops			/* drv_dev_ops */
+};
+
+static struct modlinkage modlinkage = {
+	MODREV_1,		/* ml_rev */
+	{ &modldrv, NULL }	/* ml_linkage */
+};
+
+static ddi_device_acc_attr_t efe_regs_acc_attr = {
+	DDI_DEVICE_ATTR_V0,	/* devacc_attr_version */
+	DDI_STRUCTURE_LE_ACC,	/* devacc_attr_endian_flags */
+	DDI_STRICTORDER_ACC	/* devacc_attr_dataorder */
+};
+
+static ddi_device_acc_attr_t efe_buf_acc_attr = {
+	DDI_DEVICE_ATTR_V0,	/* devacc_attr_version */
+	DDI_NEVERSWAP_ACC,	/* devacc_attr_endian_flags */
+	DDI_STRICTORDER_ACC	/* devacc_attr_dataorder */
+};
+
+static ddi_dma_attr_t efe_dma_attr = {
+	DMA_ATTR_V0,		/* dma_attr_version */
+	0,			/* dma_attr_addr_lo */
+	0xFFFFFFFFUL,		/* dma_attr_addr_hi */
+	0x7FFFFFFFUL,		/* dma_attr_count_max */
+	4,			/* dma_attr_align */
+	0x7F,			/* dma_attr_burstsizes */
+	1,			/* dma_attr_minxfer */
+	0xFFFFFFFFUL,		/* dma_attr_maxxfer */
+	0xFFFFFFFFUL,		/* dma_attr_seg */
+	1,			/* dma_attr_sgllen */
+	1,			/* dma_attr_granular */
+	0			/* dma_attr_flags */
+};
+
+static mii_ops_t efe_mii_ops = {
+	MII_OPS_VERSION,	/* mii_version */
+	efe_mii_read,		/* mii_read */
+	efe_mii_write,		/* mii_write */
+	efe_mii_notify		/* mii_notify */
+};
+
+static mac_callbacks_t efe_m_callbacks = {
+	MC_SETPROP | MC_GETPROP,	/* mc_callbacks */
+	efe_m_getstat,			/* mc_getstat */
+	efe_m_start,			/* mc_start */
+	efe_m_stop,			/* mc_stop */
+	efe_m_setpromisc,		/* mc_setpromisc */
+	efe_m_multicst,			/* mc_multicst */
+	efe_m_unicst,			/* mc_unicst */
+	efe_m_tx,			/* mc_tx */
+	NULL,				/* mc_reserved */
+	NULL,				/* mc_ioctl */
+	NULL,				/* mc_getcapab */
+	NULL,				/* mc_open */
+	NULL,				/* mc_close */
+	efe_m_setprop,			/* mc_setprop */
+	efe_m_getprop,			/* mc_getprop */
+	efe_m_propinfo			/* mc_propinfo */
+};
+
+static uint8_t efe_broadcast[] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+static uint16_t efe_mchash_promisc[] = {
+	0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF
+};
+
+/*
+ * Loadable module entry points.
+ */
+int
+_init(void)
+{
+	int error;
+
+	mac_init_ops(&efe_dev_ops, "efe");
+	if ((error = mod_install(&modlinkage)) != DDI_SUCCESS) {
+		mac_fini_ops(&efe_dev_ops);
+	}
+
+	return (error);
+}
+
+int
+_fini(void)
+{
+	int error;
+
+	if ((error = mod_remove(&modlinkage)) == DDI_SUCCESS) {
+		mac_fini_ops(&efe_dev_ops);
+	}
+
+	return (error);
+}
+
+int
+_info(struct modinfo *modinfop)
+{
+	return (mod_info(&modlinkage, modinfop));
+}
+
+/*
+ * Autoconfiguration entry points.
+ */
+int
+efe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
+{
+	ddi_acc_handle_t pci;
+	int types;
+	int count;
+	int actual;
+	uint_t pri;
+	efe_t *efep;
+	mac_register_t *macp;
+
+	switch (cmd) {
+	case DDI_ATTACH:
+		break;
+
+	case DDI_RESUME:
+		efep = ddi_get_driver_private(dip);
+		return (efe_resume(efep));
+
+	default:
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * PCI configuration.
+	 */
+	if (pci_config_setup(dip, &pci) != DDI_SUCCESS) {
+		efe_error(dip, "unable to setup PCI configuration!");
+		return (DDI_FAILURE);
+	}
+
+	pci_config_put16(pci, PCI_CONF_COMM,
+	    pci_config_get16(pci, PCI_CONF_COMM) | PCI_COMM_MAE | PCI_COMM_ME);
+
+	pci_config_teardown(&pci);
+
+	if (ddi_intr_get_supported_types(dip, &types)
+	    != DDI_SUCCESS || !(types & DDI_INTR_TYPE_FIXED)) {
+		efe_error(dip, "fixed interrupts not supported!");
+		return (DDI_FAILURE);
+	}
+
+	if (ddi_intr_get_nintrs(dip, DDI_INTR_TYPE_FIXED, &count)
+	    != DDI_SUCCESS || count != 1) {
+		efe_error(dip, "no fixed interrupts available!");
+		return (DDI_FAILURE);
+	}
+
+	/*
+	 * Initialize soft state.
+	 */
+	efep = kmem_zalloc(sizeof (efe_t), KM_SLEEP);
+	ddi_set_driver_private(dip, efep);
+
+	efep->efe_dip = dip;
+
+	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&efep->efe_regs, 0, 0,
+	    &efe_regs_acc_attr, &efep->efe_regs_acch) != DDI_SUCCESS) {
+		efe_error(dip, "unable to setup register mapping!");
+		goto failure;
+	}
+
+	efep->efe_rx_ring = efe_ring_alloc(efep->efe_dip, RXDESCL);
+	if (efep->efe_rx_ring == NULL) {
+		efe_error(efep->efe_dip, "unable to allocate rx ring!");
+		goto failure;
+	}
+
+	efep->efe_tx_ring = efe_ring_alloc(efep->efe_dip, TXDESCL);
+	if (efep->efe_tx_ring == NULL) {
+		efe_error(efep->efe_dip, "unable to allocate tx ring!");
+		goto failure;
+	}
+
+	if (ddi_intr_alloc(dip, &efep->efe_intrh, DDI_INTR_TYPE_FIXED, 0,
+	    count, &actual, DDI_INTR_ALLOC_STRICT) != DDI_SUCCESS ||
+	    actual != count) {
+		efe_error(dip, "unable to allocate fixed interrupt!");
+		goto failure;
+	}
+
+	if (ddi_intr_get_pri(efep->efe_intrh, &pri) != DDI_SUCCESS ||
+	    pri >= ddi_intr_get_hilevel_pri()) {
+		efe_error(dip, "unable to get valid interrupt priority!");
+		goto failure;
+	}
+
+	mutex_init(&efep->efe_intrlock, NULL, MUTEX_DRIVER,
+	    DDI_INTR_PRI(pri));
+
+	mutex_init(&efep->efe_txlock, NULL, MUTEX_DRIVER,
+	    DDI_INTR_PRI(pri));
+
+	/*
+	 * Initialize device.
+	 */
+	mutex_enter(&efep->efe_intrlock);
+	mutex_enter(&efep->efe_txlock);
+
+	efe_reset(efep);
+
+	mutex_exit(&efep->efe_txlock);
+	mutex_exit(&efep->efe_intrlock);
+
+	/* Use factory address as default */
+	efe_getaddr(efep, efep->efe_macaddr);
+
+	/*
+	 * Enable the ISR.
+	 */
+	if (ddi_intr_add_handler(efep->efe_intrh, efe_intr, efep, NULL)
+	    != DDI_SUCCESS) {
+		efe_error(dip, "unable to add interrupt handler!");
+		goto failure;
+	}
+
+	if (ddi_intr_enable(efep->efe_intrh) != DDI_SUCCESS) {
+		efe_error(dip, "unable to enable interrupt!");
+		goto failure;
+	}
+
+	/*
+	 * Allocate MII resources.
+	 */
+	if ((efep->efe_miih = mii_alloc(efep, dip, &efe_mii_ops)) == NULL) {
+		efe_error(dip, "unable to allocate mii resources!");
+		goto failure;
+	}
+
+	/*
+	 * Allocate MAC resources.
+	 */
+	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
+		efe_error(dip, "unable to allocate mac resources!");
+		goto failure;
+	}
+
+	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
+	macp->m_driver = efep;
+	macp->m_dip = dip;
+	macp->m_src_addr = efep->efe_macaddr;
+	macp->m_callbacks = &efe_m_callbacks;
+	macp->m_min_sdu = 0;
+	macp->m_max_sdu = ETHERMTU;
+	macp->m_margin = VLAN_TAGSZ;
+
+	if (mac_register(macp, &efep->efe_mh) != 0) {
+		efe_error(dip, "unable to register with mac!");
+		goto failure;
+	}
+	mac_free(macp);
+
+	ddi_report_dev(dip);
+
+	return (DDI_SUCCESS);
+
+failure:
+	if (macp != NULL) {
+		mac_free(macp);
+	}
+
+	if (efep->efe_miih != NULL) {
+		mii_free(efep->efe_miih);
+	}
+
+	if (efep->efe_intrh != NULL) {
+		(void) ddi_intr_disable(efep->efe_intrh);
+		(void) ddi_intr_remove_handler(efep->efe_intrh);
+		(void) ddi_intr_free(efep->efe_intrh);
+	}
+
+	mutex_destroy(&efep->efe_txlock);
+	mutex_destroy(&efep->efe_intrlock);
+
+	if (efep->efe_tx_ring != NULL) {
+		efe_ring_free(&efep->efe_tx_ring);
+	}
+	if (efep->efe_rx_ring != NULL) {
+		efe_ring_free(&efep->efe_rx_ring);
+	}
+
+	if (efep->efe_regs_acch != NULL) {
+		ddi_regs_map_free(&efep->efe_regs_acch);
+	}
+
+	kmem_free(efep, sizeof (efe_t));
+
+	return (DDI_FAILURE);
+}
+
+int
+efe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
+{
+	efe_t *efep = ddi_get_driver_private(dip);
+
+	switch (cmd) {
+	case DDI_DETACH:
+		break;
+
+	case DDI_SUSPEND:
+		return (efe_suspend(efep));
+
+	default:
+		return (DDI_FAILURE);
+	}
+
+	if (mac_unregister(efep->efe_mh) != 0) {
+		efe_error(dip, "unable to unregister from mac!");
+		return (DDI_FAILURE);
+	}
+
+	mii_free(efep->efe_miih);
+
+	(void) ddi_intr_disable(efep->efe_intrh);
+	(void) ddi_intr_remove_handler(efep->efe_intrh);
+	(void) ddi_intr_free(efep->efe_intrh);
+
+	mutex_destroy(&efep->efe_txlock);
+	mutex_destroy(&efep->efe_intrlock);
+
+	if (efep->efe_tx_ring != NULL) {
+		efe_ring_free(&efep->efe_tx_ring);
+	}
+	if (efep->efe_rx_ring != NULL) {
+		efe_ring_free(&efep->efe_rx_ring);
+	}
+
+	ddi_regs_map_free(&efep->efe_regs_acch);
+
+	kmem_free(efep, sizeof (efe_t));
+
+	return (DDI_SUCCESS);
+}
+
+int
+efe_quiesce(dev_info_t *dip)
+{
+	efe_t *efep = ddi_get_driver_private(dip);
+
+	PUTCSR(efep, CSR_GENCTL, GENCTL_RESET);
+	drv_usecwait(RESET_DELAY);
+
+	PUTCSR(efep, CSR_GENCTL, GENCTL_PWRDWN);
+
+	return (DDI_SUCCESS);
+}
+
+/*
+ * MII entry points.
+ */
+uint16_t
+efe_mii_read(void *arg, uint8_t phy, uint8_t reg)
+{
+	efe_t *efep = arg;
+
+	PUTCSR(efep, CSR_MMCTL, MMCTL_READ |
+	    reg << MMCTL_PHYREG | phy << MMCTL_PHYADDR);
+
+	for (int i = 0; i < MII_DELAY_CYCLES; ++i) {
+		if (!(GETCSR(efep, CSR_MMCTL) & MMCTL_READ)) {
+			return ((uint16_t)GETCSR(efep, CSR_MMDATA));
+		}
+		drv_usecwait(MII_DELAY);
+	}
+	efe_error(efep->efe_dip, "timed out reading from MII!");
+
+	return (0);
+}
+
+void
+efe_mii_write(void *arg, uint8_t phy, uint8_t reg, uint16_t data)
+{
+	efe_t *efep = arg;
+
+	PUTCSR(efep, CSR_MMDATA, data);
+
+	PUTCSR(efep, CSR_MMCTL, MMCTL_WRITE |
+	    reg << MMCTL_PHYREG | phy << MMCTL_PHYADDR);
+
+	for (int i = 0; i < MII_DELAY_CYCLES; ++i) {
+		if (!(GETCSR(efep, CSR_MMCTL) & MMCTL_WRITE)) {
+			return;
+		}
+		drv_usecwait(MII_DELAY);
+	}
+	efe_error(efep->efe_dip, "timed out writing to MII!");
+}
+
+void
+efe_mii_notify(void *arg, link_state_t link)
+{
+	efe_t *efep = arg;
+
+	mac_link_update(efep->efe_mh, link);
+}
+
+/*
+ * MAC entry points.
+ */
+int
+efe_m_getstat(void *arg, uint_t stat, uint64_t *val)
+{
+	efe_t *efep = arg;
+
+	if (mii_m_getstat(efep->efe_miih, stat, val) == 0) {
+		return (0);
+	}
+
+	switch (stat) {
+	case MAC_STAT_MULTIRCV:
+		*val = efep->efe_multircv;
+		break;
+
+	case MAC_STAT_BRDCSTRCV:
+		*val = efep->efe_brdcstrcv;
+		break;
+
+	case MAC_STAT_MULTIXMT:
+		*val = efep->efe_multixmt;
+		break;
+
+	case MAC_STAT_BRDCSTXMT:
+		*val = efep->efe_brdcstxmt;
+		break;
+
+	case MAC_STAT_NORCVBUF:
+		*val = efep->efe_norcvbuf;
+		break;
+
+	case MAC_STAT_IERRORS:
+		*val = efep->efe_ierrors;
+		break;
+
+	case MAC_STAT_NOXMTBUF:
+		*val = efep->efe_noxmtbuf;
+		break;
+
+	case MAC_STAT_OERRORS:
+		*val = efep->efe_oerrors;
+		break;
+
+	case MAC_STAT_COLLISIONS:
+		*val = efep->efe_collisions;
+		break;
+
+	case MAC_STAT_RBYTES:
+		*val = efep->efe_rbytes;
+		break;
+
+	case MAC_STAT_IPACKETS:
+		*val = efep->efe_ipackets;
+		break;
+
+	case MAC_STAT_OBYTES:
+		*val = efep->efe_obytes;
+		break;
+
+	case MAC_STAT_OPACKETS:
+		*val = efep->efe_opackets;
+		break;
+
+	case MAC_STAT_UNDERFLOWS:
+		*val = efep->efe_uflo;
+		break;
+
+	case MAC_STAT_OVERFLOWS:
+		*val = efep->efe_oflo;
+		break;
+
+	case ETHER_STAT_ALIGN_ERRORS:
+		*val = efep->efe_align_errors;
+		break;
+
+	case ETHER_STAT_FCS_ERRORS:
+		*val = efep->efe_fcs_errors;
+		break;
+
+	case ETHER_STAT_FIRST_COLLISIONS:
+		*val = efep->efe_first_collisions;
+		break;
+
+	case ETHER_STAT_TX_LATE_COLLISIONS:
+		*val = efep->efe_tx_late_collisions;
+		break;
+
+	case ETHER_STAT_DEFER_XMTS:
+		*val = efep->efe_defer_xmts;
+		break;
+
+	case ETHER_STAT_EX_COLLISIONS:
+		*val = efep->efe_ex_collisions;
+		break;
+
+	case ETHER_STAT_MACXMT_ERRORS:
+		*val = efep->efe_macxmt_errors;
+		break;
+
+	case ETHER_STAT_CARRIER_ERRORS:
+		*val = efep->efe_carrier_errors;
+		break;
+
+	case ETHER_STAT_TOOLONG_ERRORS:
+		*val = efep->efe_toolong_errors;
+		break;
+
+	case ETHER_STAT_MACRCV_ERRORS:
+		*val = efep->efe_macrcv_errors;
+		break;
+
+	case ETHER_STAT_TOOSHORT_ERRORS:
+		*val = efep->efe_runt_errors;
+		break;
+
+	case ETHER_STAT_JABBER_ERRORS:
+		*val = efep->efe_jabber_errors;
+		break;
+
+	default:
+		return (ENOTSUP);
+	}
+
+	return (0);
+}
+
+int
+efe_m_start(void *arg)
+{
+	efe_t *efep = arg;
+
+	mutex_enter(&efep->efe_intrlock);
+	mutex_enter(&efep->efe_txlock);
+
+	efe_start(efep);
+	efep->efe_flags |= FLAG_RUNNING;
+
+	mutex_exit(&efep->efe_txlock);
+	mutex_exit(&efep->efe_intrlock);
+
+	mii_start(efep->efe_miih);
+
+	return (0);
+}
+
+void
+efe_m_stop(void *arg)
+{
+	efe_t *efep = arg;
+
+	mutex_enter(&efep->efe_intrlock);
+	mutex_enter(&efep->efe_txlock);
+
+	efe_stop(efep);
+	efep->efe_flags &= ~FLAG_RUNNING;
+
+	mutex_exit(&efep->efe_txlock);
+	mutex_exit(&efep->efe_intrlock);
+
+	mii_stop(efep->efe_miih);
+}
+
+int
+efe_m_setpromisc(void *arg, boolean_t on)
+{
+	efe_t *efep = arg;
+
+	mutex_enter(&efep->efe_intrlock);
+	mutex_enter(&efep->efe_txlock);
+
+	if (efep->efe_flags & FLAG_SUSPENDED) {
+		mutex_exit(&efep->efe_txlock);
+		mutex_exit(&efep->efe_intrlock);
+		return (0);
+	}
+
+	efep->efe_promisc = on;
+
+	if (efep->efe_flags & FLAG_RUNNING) {
+		efe_restart(efep);
+	}
+
+	mutex_exit(&efep->efe_txlock);
+	mutex_exit(&efep->efe_intrlock);
+
+	return (0);
+}
+
+int
+efe_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
+{
+	efe_t *efep = arg;
+	uint32_t val;
+	int index;
+	int bit;
+	boolean_t restart = B_FALSE;
+
+	mutex_enter(&efep->efe_intrlock);
+	mutex_enter(&efep->efe_txlock);
+
+	if (efep->efe_flags & FLAG_SUSPENDED) {
+		mutex_exit(&efep->efe_txlock);
+		mutex_exit(&efep->efe_intrlock);
+		return (0);
+	}
+
+	CRC32(val, macaddr, ETHERADDRL, -1U, crc32_table);
+	val %= MCHASHL;
+
+	index = val / MCHASHSZ;
+	bit = 1U << (val % MCHASHSZ);
+
+	if (add) {
+		efep->efe_mccount[val]++;
+		if (efep->efe_mccount[val] == 1) {
+			efep->efe_mchash[index] |= bit;
+			restart = B_TRUE;
+		}
+
+	} else {
+		efep->efe_mccount[val]--;
+		if (efep->efe_mccount[val] == 0) {
+			efep->efe_mchash[index] &= ~bit;
+			restart = B_TRUE;
+		}
+	}
+
+	if (restart && efep->efe_flags & FLAG_RUNNING) {
+		efe_restart(efep);
+	}
+
+	mutex_exit(&efep->efe_txlock);
+	mutex_exit(&efep->efe_intrlock);
+
+	return (0);
+}
+
+int
+efe_m_unicst(void *arg, const uint8_t *macaddr)
+{
+	efe_t *efep = arg;
+
+	mutex_enter(&efep->efe_intrlock);
+	mutex_enter(&efep->efe_txlock);
+
+	if (efep->efe_flags & FLAG_SUSPENDED) {
+		mutex_exit(&efep->efe_txlock);
+		mutex_exit(&efep->efe_intrlock);
+		return (0);
+	}
+
+	bcopy(macaddr, efep->efe_macaddr, ETHERADDRL);
+
+	if (efep->efe_flags & FLAG_RUNNING) {
+		efe_restart(efep);
+	}
+
+	mutex_exit(&efep->efe_txlock);
+	mutex_exit(&efep->efe_intrlock);
+
+	return (0);
+}
+
+mblk_t *
+efe_m_tx(void *arg, mblk_t *mp)
+{
+	efe_t *efep = arg;
+
+	mutex_enter(&efep->efe_txlock);
+
+	if (efep->efe_flags & FLAG_SUSPENDED) {
+		mutex_exit(&efep->efe_txlock);
+		return (mp);
+	}
+
+	while (mp != NULL) {
+		mblk_t *tmp = mp->b_next;
+		mp->b_next = NULL;
+
+		if (efe_send(efep, mp) != DDI_SUCCESS) {
+			mp->b_next = tmp;
+			break;
+		}
+		mp = tmp;
+	}
+
+	/* Kick the transmitter */
+	PUTCSR(efep, CSR_COMMAND, COMMAND_TXQUEUED);
+
+	mutex_exit(&efep->efe_txlock);
+
+	return (mp);
+}
+
+int
+efe_m_setprop(void *arg, const char *name, mac_prop_id_t id,
+    uint_t valsize, const void *val)
+{
+	efe_t *efep = arg;
+
+	return (mii_m_setprop(efep->efe_miih, name, id, valsize, val));
+}
+
+int
+efe_m_getprop(void *arg, const char *name, mac_prop_id_t id,
+    uint_t valsize, void *val)
+{
+	efe_t *efep = arg;
+
+	return (mii_m_getprop(efep->efe_miih, name, id, valsize, val));
+}
+
+void
+efe_m_propinfo(void *arg, const char *name, mac_prop_id_t id,
+    mac_prop_info_handle_t state)
+{
+	efe_t *efep = arg;
+
+	mii_m_propinfo(efep->efe_miih, name, id, state);
+}
+
+/*
+ * ISR/periodic callbacks.
+ */
+uint_t
+efe_intr(caddr_t arg1, caddr_t arg2)
+{
+	efe_t *efep = (void *)arg1;
+	uint32_t status;
+	mblk_t *mp = NULL;
+
+	_NOTE(ARGUNUSED(arg2));
+
+	mutex_enter(&efep->efe_intrlock);
+
+	if (efep->efe_flags & FLAG_SUSPENDED) {
+		mutex_exit(&efep->efe_intrlock);
+		return (DDI_INTR_UNCLAIMED);
+	}
+
+	status = GETCSR(efep, CSR_INTSTAT);
+	if (!(status & INTSTAT_ACTV)) {
+		mutex_exit(&efep->efe_intrlock);
+		return (DDI_INTR_UNCLAIMED);
+	}
+	PUTCSR(efep, CSR_INTSTAT, status);
+
+	if (status & INTSTAT_RCC) {
+		mp = efe_recv(efep);
+	}
+
+	if (status & INTSTAT_RQE) {
+		efep->efe_ierrors++;
+		efep->efe_macrcv_errors++;
+
+		/* Kick the receiver */
+		PUTCSR(efep, CSR_COMMAND, COMMAND_RXQUEUED);
+	}
+
+	if (status & INTSTAT_TXC) {
+		mutex_enter(&efep->efe_txlock);
+
+		efe_send_done(efep);
+
+		mutex_exit(&efep->efe_txlock);
+	}
+
+	if (status & INTSTAT_FATAL) {
+		mutex_enter(&efep->efe_txlock);
+
+		efe_error(efep->efe_dip, "bus error; resetting!");
+		efe_restart(efep);
+
+		mutex_exit(&efep->efe_txlock);
+	}
+
+	mutex_exit(&efep->efe_intrlock);
+
+	if (mp != NULL) {
+		mac_rx(efep->efe_mh, NULL, mp);
+	}
+
+	if (status & INTSTAT_TXC) {
+		mac_tx_update(efep->efe_mh);
+	}
+
+	if (status & INTSTAT_FATAL) {
+		mii_reset(efep->efe_miih);
+	}
+
+	return (DDI_INTR_CLAIMED);
+}
+
+/*
+ * Support functions.
+ */
+void
+efe_init(efe_t *efep)
+{
+	uint32_t val;
+
+	ASSERT(mutex_owned(&efep->efe_intrlock));
+	ASSERT(mutex_owned(&efep->efe_txlock));
+
+	efe_reset(efep);
+
+	val = GENCTL_ONECOPY | GENCTL_RFT_128 | GENCTL_MRM;
+#ifdef _BIG_ENDIAN
+	val |= GENCTL_BE;
+#endif	/* _BIG_ENDIAN */
+
+	PUTCSR(efep, CSR_GENCTL, val);
+	PUTCSR(efep, CSR_PBLCNT, BURSTLEN);
+
+	efe_init_rx_ring(efep);
+	efe_init_tx_ring(efep);
+
+	efe_setaddr(efep, efep->efe_macaddr);
+
+	if (efep->efe_promisc) {
+		efe_setmchash(efep, efe_mchash_promisc);
+	} else {
+		efe_setmchash(efep, efep->efe_mchash);
+	}
+}
+
+void
+efe_init_rx_ring(efe_t *efep)
+{
+	efe_ring_t *rp;
+
+	ASSERT(mutex_owned(&efep->efe_intrlock));
+
+	rp = efep->efe_rx_ring;
+
+	for (int i = 0; i < DESCLEN(rp); ++i) {
+		efe_desc_t *dp = GETDESC(rp, i);
+		efe_buf_t *bp = GETBUF(rp, i);
+
+		PUTDESC16(rp, &dp->d_status, RXSTAT_OWNER);
+		PUTDESC16(rp, &dp->d_len, 0);
+		PUTDESC32(rp, &dp->d_bufaddr, BUFADDR(bp));
+		PUTDESC16(rp, &dp->d_buflen, BUFLEN(bp));
+		PUTDESC16(rp, &dp->d_control, 0);
+		PUTDESC32(rp, &dp->d_next, NEXTDESCADDR(rp, i));
+
+		SYNCDESC(rp, i, DDI_DMA_SYNC_FORDEV);
+	}
+
+	efep->efe_rx_desc = 0;
+
+	PUTCSR(efep, CSR_PRCDAR, DESCADDR(rp, 0));
+}
+
+void
+efe_init_tx_ring(efe_t *efep)
+{
+	efe_ring_t *rp;
+
+	ASSERT(mutex_owned(&efep->efe_txlock));
+
+	rp = efep->efe_tx_ring;
+
+	for (int i = 0; i < DESCLEN(rp); ++i) {
+		efe_desc_t *dp = GETDESC(rp, i);
+		efe_buf_t *bp = GETBUF(rp, i);
+
+		PUTDESC16(rp, &dp->d_status, 0);
+		PUTDESC16(rp, &dp->d_len, 0);
+		PUTDESC32(rp, &dp->d_bufaddr, BUFADDR(bp));
+		PUTDESC16(rp, &dp->d_buflen, BUFLEN(bp));
+		PUTDESC16(rp, &dp->d_control, 0);
+		PUTDESC32(rp, &dp->d_next, NEXTDESCADDR(rp, i));
+
+		SYNCDESC(rp, i, DDI_DMA_SYNC_FORDEV);
+	}
+
+	efep->efe_tx_desc = 0;
+	efep->efe_tx_sent = 0;
+
+	PUTCSR(efep, CSR_PTCDAR, DESCADDR(rp, 0));
+}
+
+void
+efe_reset(efe_t *efep)
+{
+	ASSERT(mutex_owned(&efep->efe_intrlock));
+	ASSERT(mutex_owned(&efep->efe_txlock));
+
+	PUTCSR(efep, CSR_GENCTL, GENCTL_RESET);
+	drv_usecwait(RESET_DELAY);
+
+	/* Assert internal clock source (AN 7.15) */
+	for (int i = 0; i < RESET_TEST_CYCLES; ++i) {
+		PUTCSR(efep, CSR_TEST, TEST_CLOCK);
+	}
+}
+
+void
+efe_start(efe_t *efep)
+{
+	ASSERT(mutex_owned(&efep->efe_intrlock));
+	ASSERT(mutex_owned(&efep->efe_txlock));
+
+	efe_init(efep);
+
+	PUTCSR(efep, CSR_RXCON,
+	    RXCON_SEP | RXCON_RRF | RXCON_RBF | RXCON_RMF |
+	    (efep->efe_promisc ? RXCON_PROMISC : 0));
+
+	PUTCSR(efep, CSR_TXCON, TXCON_LB_3);
+
+	efe_intr_enable(efep);
+
+	SETBIT(efep, CSR_COMMAND,
+	    COMMAND_START_RX | COMMAND_RXQUEUED);
+}
+
+void
+efe_stop(efe_t *efep)
+{
+	ASSERT(mutex_owned(&efep->efe_intrlock));
+	ASSERT(mutex_owned(&efep->efe_txlock));
+
+	efe_intr_disable(efep);
+
+	PUTCSR(efep, CSR_COMMAND, COMMAND_STOP_RX);
+
+	efe_stop_dma(efep);
+
+	PUTCSR(efep, CSR_GENCTL, GENCTL_RESET);
+	drv_usecwait(RESET_DELAY);
+
+	PUTCSR(efep, CSR_GENCTL, GENCTL_PWRDWN);
+}
+
+void
+efe_stop_dma(efe_t *efep)
+{
+	ASSERT(mutex_owned(&efep->efe_intrlock));
+	ASSERT(mutex_owned(&efep->efe_txlock));
+
+	PUTCSR(efep, CSR_COMMAND,
+	    COMMAND_STOP_RDMA | COMMAND_STOP_TDMA);
+
+	for (int i = 0; i < STOP_DELAY_CYCLES; ++i) {
+		uint32_t status = GETCSR(efep, CSR_INTSTAT);
+		if (status & INTSTAT_RXIDLE &&
+		    status & INTSTAT_TXIDLE) {
+			return;
+		}
+		drv_usecwait(STOP_DELAY);
+	}
+	efe_error(efep->efe_dip, "timed out stopping DMA engine!");
+}
+
+inline void
+efe_restart(efe_t *efep)
+{
+	efe_stop(efep);
+	efe_start(efep);
+}
+
+int
+efe_suspend(efe_t *efep)
+{
+	mutex_enter(&efep->efe_intrlock);
+	mutex_enter(&efep->efe_txlock);
+
+	if (efep->efe_flags & FLAG_RUNNING) {
+		efe_stop(efep);
+	}
+	efep->efe_flags |= FLAG_SUSPENDED;
+
+	mutex_exit(&efep->efe_txlock);
+	mutex_exit(&efep->efe_intrlock);
+
+	mii_suspend(efep->efe_miih);
+
+	return (DDI_SUCCESS);
+}
+
+int
+efe_resume(efe_t *efep)
+{
+	mutex_enter(&efep->efe_intrlock);
+	mutex_enter(&efep->efe_txlock);
+
+	if (efep->efe_flags & FLAG_RUNNING) {
+		efe_start(efep);
+	}
+	efep->efe_flags &= ~FLAG_SUSPENDED;
+
+	mutex_exit(&efep->efe_txlock);
+	mutex_exit(&efep->efe_intrlock);
+
+	mii_resume(efep->efe_miih);
+
+	return (DDI_SUCCESS);
+}
+
+efe_ring_t *
+efe_ring_alloc(dev_info_t *dip, size_t len)
+{
+	efe_ring_t *rp;
+	size_t rlen;
+	uint_t ccount;
+
+	ASSERT(len > 1);
+
+	rp = kmem_zalloc(sizeof (efe_ring_t), KM_SLEEP);
+	rp->r_len = len;
+
+	if (ddi_dma_alloc_handle(dip, &efe_dma_attr, DDI_DMA_SLEEP, NULL,
+	    &rp->r_dmah) != DDI_SUCCESS) {
+		efe_error(dip, "unable to allocate DMA handle!");
+		goto failure;
+	}
+
+	if (ddi_dma_mem_alloc(rp->r_dmah, DESCSZ(len), &efe_buf_acc_attr,
+	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, (caddr_t *)&rp->r_descp,
+	    &rlen, &rp->r_acch) != DDI_SUCCESS) {
+		efe_error(dip, "unable to allocate descriptors!");
+		goto failure;
+	}
+
+	if (ddi_dma_addr_bind_handle(rp->r_dmah, NULL, (caddr_t)rp->r_descp,
+	    DESCSZ(len), DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP,
+	    NULL, &rp->r_dmac, &ccount) != DDI_DMA_MAPPED) {
+		efe_error(dip, "unable to bind DMA handle to descriptors!");
+		goto failure;
+	}
+
+	rp->r_bufpp = kmem_zalloc(BUFPSZ(len), KM_SLEEP);
+
+	for (int i = 0; i < len; ++i) {
+		efe_buf_t *bp = efe_buf_alloc(dip, BUFSZ);
+		if (bp == NULL) {
+			goto failure;
+		}
+		rp->r_bufpp[i] = bp;
+	}
+
+	return (rp);
+
+failure:
+	efe_ring_free(&rp);
+
+	return (NULL);
+}
+
+void
+efe_ring_free(efe_ring_t **rpp)
+{
+	efe_ring_t *rp = *rpp;
+
+	ASSERT(rp != NULL);
+
+	for (int i = 0; i < DESCLEN(rp); ++i) {
+		efe_buf_t *bp = GETBUF(rp, i);
+		if (bp != NULL) {
+			efe_buf_free(&bp);
+		}
+	}
+	kmem_free(rp->r_bufpp, BUFPSZ(DESCLEN(rp)));
+
+	if (rp->r_descp != NULL) {
+		(void) ddi_dma_unbind_handle(rp->r_dmah);
+	}
+	if (rp->r_acch != NULL) {
+		ddi_dma_mem_free(&rp->r_acch);
+	}
+	if (rp->r_dmah != NULL) {
+		ddi_dma_free_handle(&rp->r_dmah);
+	}
+	kmem_free(rp, sizeof (efe_ring_t));
+
+	*rpp = NULL;
+}
+
+efe_buf_t *
+efe_buf_alloc(dev_info_t *dip, size_t len)
+{
+	efe_buf_t *bp;
+	size_t rlen;
+	uint_t ccount;
+
+	bp = kmem_zalloc(sizeof (efe_buf_t), KM_SLEEP);
+	bp->b_len = len;
+
+	if (ddi_dma_alloc_handle(dip, &efe_dma_attr, DDI_DMA_SLEEP, NULL,
+	    &bp->b_dmah) != DDI_SUCCESS) {
+		efe_error(dip, "unable to allocate DMA handle!");
+		goto failure;
+	}
+
+	if (ddi_dma_mem_alloc(bp->b_dmah, len, &efe_buf_acc_attr,
+	    DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL, &bp->b_kaddr, &rlen,
+	    &bp->b_acch) != DDI_SUCCESS) {
+		efe_error(dip, "unable to allocate buffer!");
+		goto failure;
+	}
+
+	if (ddi_dma_addr_bind_handle(bp->b_dmah, NULL, bp->b_kaddr,
+	    len, DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP, NULL,
+	    &bp->b_dmac, &ccount) != DDI_DMA_MAPPED) {
+		efe_error(dip, "unable to bind DMA handle to buffer!");
+		goto failure;
+	}
+
+	return (bp);
+
+failure:
+	efe_buf_free(&bp);
+
+	return (NULL);
+}
+
+void
+efe_buf_free(efe_buf_t **bpp)
+{
+	efe_buf_t *bp = *bpp;
+
+	ASSERT(bp != NULL);
+
+	if (bp->b_kaddr != NULL) {
+		(void) ddi_dma_unbind_handle(bp->b_dmah);
+	}
+	if (bp->b_acch != NULL) {
+		ddi_dma_mem_free(&bp->b_acch);
+	}
+	if (bp->b_dmah != NULL) {
+		ddi_dma_free_handle(&bp->b_dmah);
+	}
+	kmem_free(bp, sizeof (efe_buf_t));
+
+	*bpp = NULL;
+}
+
+void
+efe_intr_enable(efe_t *efep)
+{
+	PUTCSR(efep, CSR_INTMASK,
+	    INTMASK_RCC | INTMASK_RQE | INTMASK_TXC | INTMASK_FATAL);
+
+	SETBIT(efep, CSR_GENCTL, GENCTL_INT);
+}
+
+void
+efe_intr_disable(efe_t *efep)
+{
+	PUTCSR(efep, CSR_INTMASK, 0);
+
+	CLRBIT(efep, CSR_GENCTL, GENCTL_INT);
+}
+
+mblk_t *
+efe_recv(efe_t *efep)
+{
+	efe_ring_t *rp;
+	mblk_t *mp = NULL;
+	mblk_t **mpp = &mp;
+
+	ASSERT(mutex_owned(&efep->efe_intrlock));
+
+	rp = efep->efe_rx_ring;
+
+	for (;;) {
+		efe_desc_t *dp;
+		uint16_t status;
+
+		dp = GETDESC(rp, efep->efe_rx_desc);
+		SYNCDESC(rp, efep->efe_rx_desc, DDI_DMA_SYNC_FORKERNEL);
+
+		status = GETDESC16(rp, &dp->d_status);
+
+		/* Stop if device owns descriptor */
+		if (status & RXSTAT_OWNER) {
+			break;
+		}
+
+		if (status & RXSTAT_PRI) {
+			mblk_t *tmp = efe_recv_pkt(efep, dp);
+			if (tmp != NULL) {
+				*mpp = tmp;
+				mpp = &tmp->b_next;
+			}
+
+		} else {
+			efep->efe_ierrors++;
+
+			if (status & RXSTAT_FAE) {
+				efep->efe_align_errors++;
+			}
+			if (status & RXSTAT_CRC) {
+				efep->efe_fcs_errors++;
+			}
+			if (status & RXSTAT_MP) {
+				efep->efe_oflo++;
+			}
+		}
+
+		/* Release ownership to device */
+		PUTDESC16(rp, &dp->d_status, RXSTAT_OWNER);
+
+		SYNCDESC(rp, efep->efe_rx_desc, DDI_DMA_SYNC_FORDEV);
+
+		efep->efe_rx_desc = NEXTDESC(rp, efep->efe_rx_desc);
+	}
+
+	return (mp);
+}
+
+mblk_t *
+efe_recv_pkt(efe_t *efep, efe_desc_t *dp)
+{
+	efe_ring_t *rp;
+	efe_buf_t *bp;
+	uint16_t len;
+	mblk_t *mp;
+	uint16_t status;
+
+	ASSERT(mutex_owned(&efep->efe_intrlock));
+
+	rp = efep->efe_rx_ring;
+
+	len = GETDESC16(rp, &dp->d_len) - ETHERFCSL;
+
+	if (len < ETHERMIN) {
+		efep->efe_ierrors++;
+		efep->efe_runt_errors++;
+		return (NULL);
+	}
+
+	if (len > ETHERMAX + VLAN_TAGSZ) {
+		efep->efe_ierrors++;
+		efep->efe_toolong_errors++;
+		return (NULL);
+	}
+
+	mp = allocb(len, 0);
+	if (mp == NULL) {
+		efep->efe_ierrors++;
+		efep->efe_norcvbuf++;
+		return (NULL);
+	}
+	mp->b_wptr = mp->b_rptr + len;
+
+	bp = GETBUF(rp, efep->efe_rx_desc);
+	SYNCBUF(bp, DDI_DMA_SYNC_FORKERNEL);
+
+	bcopy(bp->b_kaddr, mp->b_rptr, len);
+
+	efep->efe_ipackets++;
+	efep->efe_rbytes += len;
+
+	status = GETDESC16(rp, &dp->d_status);
+
+	if (status & RXSTAT_BAR) {
+		efep->efe_brdcstrcv++;
+
+	} else if (status & RXSTAT_MAR) {
+		efep->efe_multircv++;
+	}
+
+	return (mp);
+}
+
+int
+efe_send(efe_t *efep, mblk_t *mp)
+{
+	efe_ring_t *rp;
+	uint16_t len;
+	efe_desc_t *dp;
+	uint16_t status;
+	efe_buf_t *bp;
+
+	ASSERT(mutex_owned(&efep->efe_txlock));
+
+	rp = efep->efe_tx_ring;
+
+	len = msgsize(mp);
+
+	if (len > ETHERMAX + VLAN_TAGSZ) {
+		efep->efe_oerrors++;
+		efep->efe_macxmt_errors++;
+		freemsg(mp);
+		return (DDI_SUCCESS);
+	}
+
+	dp = GETDESC(rp, efep->efe_tx_desc);
+	SYNCDESC(rp, efep->efe_tx_desc, DDI_DMA_SYNC_FORKERNEL);
+
+	status = GETDESC16(efep->efe_tx_ring, &dp->d_status);
+
+	/* Stop if device owns descriptor */
+	if (status & TXSTAT_OWNER) {
+		return (DDI_FAILURE);
+	}
+
+	bp = GETBUF(rp, efep->efe_tx_desc);
+
+	mcopymsg(mp, bp->b_kaddr);
+
+	/*
+	 * Packets must contain at least ETHERMIN octets.
+	 * Padded octets are zeroed out prior to sending.
+	 */
+	if (len < ETHERMIN) {
+		bzero(bp->b_kaddr + len, ETHERMIN - len);
+		len = ETHERMIN;
+	}
+
+	SYNCBUF(bp, DDI_DMA_SYNC_FORDEV);
+
+	PUTDESC16(rp, &dp->d_status, TXSTAT_OWNER);
+	PUTDESC16(rp, &dp->d_len, len);
+	PUTDESC16(rp, &dp->d_control, TXCTL_LASTDESCR);
+
+	SYNCDESC(rp, efep->efe_tx_desc, DDI_DMA_SYNC_FORDEV);
+
+	efep->efe_opackets++;
+	efep->efe_obytes += len;
+
+	if (*bp->b_kaddr & 0x01) {
+		if (bcmp(bp->b_kaddr, efe_broadcast, ETHERADDRL) == 0) {
+			efep->efe_brdcstxmt++;
+		} else {
+			efep->efe_multixmt++;
+		}
+	}
+
+	efep->efe_tx_desc = NEXTDESC(rp, efep->efe_tx_desc);
+
+	return (DDI_SUCCESS);
+}
+
+void
+efe_send_done(efe_t *efep)
+{
+	efe_ring_t *rp;
+
+	ASSERT(mutex_owned(&efep->efe_txlock));
+
+	rp = efep->efe_tx_ring;
+
+	for (;;) {
+		efe_desc_t *dp;
+		uint16_t status;
+
+		dp = GETDESC(rp, efep->efe_tx_sent);
+		SYNCDESC(rp, efep->efe_tx_sent, DDI_DMA_SYNC_FORKERNEL);
+
+		status = GETDESC16(rp, &dp->d_status);
+
+		/* Stop if device owns descriptor */
+		if (status & TXSTAT_OWNER) {
+			break;
+		}
+
+		if (status & TXSTAT_PTX) {
+			if (!(status & TXSTAT_ND)) {
+				efep->efe_defer_xmts++;
+			}
+			if (status & TXSTAT_COLL) {
+				efep->efe_first_collisions++;
+			}
+
+		} else {
+			efep->efe_oerrors++;
+
+			if (status & TXSTAT_CSL) {
+				efep->efe_carrier_errors++;
+			}
+			if (status & TXSTAT_UFLO) {
+				efep->efe_uflo++;
+			}
+			if (status & TXSTAT_OWC) {
+				efep->efe_tx_late_collisions++;
+			}
+			if (status & TXSTAT_DEFER) {
+				efep->efe_jabber_errors++;
+			}
+			if (status & TXSTAT_EXCOLL) {
+				efep->efe_ex_collisions++;
+			}
+		}
+
+		efep->efe_collisions +=
+		    (status >> TXSTAT_CCNT) & TXSTAT_CCNTMASK;
+
+		efep->efe_tx_sent = NEXTDESC(rp, efep->efe_tx_sent);
+	}
+}
+
+void
+efe_getaddr(efe_t *efep, uint8_t *macaddr)
+{
+	efe_eeprom_read(efep, macaddr, ETHERADDRL, 0x0);
+
+	efe_debug(efep->efe_dip,
+	    "factory address is %02x:%02x:%02x:%02x:%02x:%02x\n",
+	    macaddr[0], macaddr[1], macaddr[2], macaddr[3],
+	    macaddr[4], macaddr[5]);
+}
+
+void
+efe_setaddr(efe_t *efep, uint8_t *macaddr)
+{
+	uint16_t val;
+
+	bcopy(macaddr, &val, sizeof (uint16_t));
+	PUTCSR(efep, CSR_LAN0, val);
+	macaddr += sizeof (uint16_t);
+
+	bcopy(macaddr, &val, sizeof (uint16_t));
+	PUTCSR(efep, CSR_LAN1, val);
+	macaddr += sizeof (uint16_t);
+
+	bcopy(macaddr, &val, sizeof (uint16_t));
+	PUTCSR(efep, CSR_LAN2, val);
+}
+
+void
+efe_setmchash(efe_t *efep, uint16_t *mchash)
+{
+	PUTCSR(efep, CSR_MC0, mchash[0]);
+	PUTCSR(efep, CSR_MC1, mchash[1]);
+	PUTCSR(efep, CSR_MC2, mchash[2]);
+	PUTCSR(efep, CSR_MC3, mchash[3]);
+}
+
+void
+efe_eeprom_read(efe_t *efep, uint8_t *buf, size_t len, uint8_t addr)
+{
+	int addrlen;
+
+	ASSERT(len & ~0x1);	/* non-zero; word-aligned */
+
+	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS);
+	drv_usecwait(EEPROM_DELAY);
+
+	addrlen = (GETCSR(efep, CSR_EECTL) & EECTL_SIZE ?
+	    AT93C46_ADDRLEN : AT93C56_ADDRLEN);
+
+	for (int i = 0; i < len / sizeof (uint16_t); ++i) {
+		uint16_t val = efe_eeprom_readw(efep, addrlen, addr + i);
+		bcopy(&val, buf, sizeof (uint16_t));
+		buf += sizeof (uint16_t);
+	}
+}
+
+uint16_t
+efe_eeprom_readw(efe_t *efep, int addrlen, uint8_t addr)
+{
+	uint16_t val = 0;
+
+	ASSERT(addrlen > 0);
+
+	/* Write Start Bit (SB) */
+	efe_eeprom_writebit(efep, 1);
+
+	/* Write READ instruction */
+	efe_eeprom_writebit(efep, 1);
+	efe_eeprom_writebit(efep, 0);
+
+	/* Write EEPROM address */
+	for (int i = addrlen - 1; i >= 0; --i) {
+		efe_eeprom_writebit(efep, addr & 1U << i);
+	}
+
+	/* Read EEPROM word */
+	for (int i = EEPROM_WORDSZ - 1; i >= 0; --i) {
+		val |= efe_eeprom_readbit(efep) << i;
+	}
+
+	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE);
+	drv_usecwait(EEPROM_DELAY);
+
+	return (val);
+}
+
+inline int
+efe_eeprom_readbit(efe_t *efep)
+{
+	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS);
+	drv_usecwait(EEPROM_DELAY);
+
+	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS |
+	    EECTL_EESK);
+	drv_usecwait(EEPROM_DELAY);
+
+	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS);
+	drv_usecwait(EEPROM_DELAY);
+
+	return (!!(GETCSR(efep, CSR_EECTL) & EECTL_EEDO));
+}
+
+inline void
+efe_eeprom_writebit(efe_t *efep, int bit)
+{
+	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS);
+	drv_usecwait(EEPROM_DELAY);
+
+	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS |
+	    EECTL_EESK | (bit ? EECTL_EEDI : 0));
+	drv_usecwait(EEPROM_DELAY);
+
+	PUTCSR(efep, CSR_EECTL, EECTL_ENABLE | EECTL_EECS);
+	drv_usecwait(EEPROM_DELAY);
+}
+
+void
+efe_dprintf(dev_info_t *dip, int level, const char *format, ...)
+{
+	va_list ap;
+	char buf[255];
+
+	va_start(ap, format);
+
+	(void) vsnprintf(buf, sizeof (buf), format, ap);
+
+	cmn_err(level, "?%s%d %s", ddi_driver_name(dip),
+	    ddi_get_instance(dip), buf);
+
+	va_end(ap);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/io/efe/efe.h	Wed Oct 27 08:57:45 2010 -0400
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 2010 Steven Stallion.  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. Neither the name of the copyright owner nor the names of any
+ *        contributors may be used to endorse or promote products derived
+ *        from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 COPYRIGHT OWNER 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.
+ */
+
+#ifndef	_EFE_H
+#define	_EFE_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#define	VENDOR_ID		0x10B8
+#define	DEVICE_ID		0x0005
+
+#define	RESET_DELAY		1
+#define	RESET_TEST_CYCLES	16
+
+#define	STOP_DELAY		10
+#define	STOP_DELAY_CYCLES	160
+
+#define	MII_DELAY		1
+#define	MII_DELAY_CYCLES	16
+
+#define	EEPROM_DELAY		3
+#define	EEPROM_WORDSZ		16
+
+#define	AT93C46_ADDRLEN		6
+#define	AT93C56_ADDRLEN		8
+
+#define	FLAG_RUNNING		(1UL << 0)
+#define	FLAG_SUSPENDED		(1UL << 1)
+
+#define	MCHASHL			64
+#define	MCHASHSZ		16
+
+#define	BURSTLEN		0x3F
+
+#define	RXDESCL			128
+#define	TXDESCL			128
+
+#define	BUFSZ			1536
+
+/*
+ * Control/Status registers.
+ */
+#define	CSR_COMMAND	0x00	/* Control Register */
+#define	CSR_INTSTAT	0x04	/* Interrupt Status Register */
+#define	CSR_INTMASK	0x08	/* Interrupt Mask Register */
+#define	CSR_GENCTL	0x0C	/* General Control Register */
+#define	CSR_NVCTL	0x10	/* Non-volatile Control Register */
+#define	CSR_EECTL	0x14	/* EEPROM Control Register */
+#define	CSR_PBLCNT	0x18	/* Programmable Burst Length Counter */
+#define	CSR_TEST	0x1C	/* Test Register */
+#define	CSR_CRCCNT	0x20	/* CRC Error Counter */
+#define	CSR_ALICNT	0x24	/* Frame Alignment Error Counter */
+#define	CSR_MPCNT	0x28	/* Missed Packet Counter */
+#define	CSR_RXFIFO	0x2C	/* Receive FIFO Contents */
+#define	CSR_MMCTL	0x30	/* MII Control Register */
+#define	CSR_MMDATA	0x34	/* MII Interface Register */
+#define	CSR_MMCFG	0x38	/* MII Configuration Register */
+#define	CSR_IPG		0x3C	/* Interpacket Gap Register */
+#define	CSR_LAN0	0x40	/* LAN Address Register 0 */
+#define	CSR_LAN1	0x44	/* LAN Address Register 1 */
+#define	CSR_LAN2	0x48	/* LAN Address Register 2 */
+#define	CSR_IDCHK	0x4C	/* Board ID/Checksum Register */
+#define	CSR_MC0		0x50	/* Multicast Address Register 0 */
+#define	CSR_MC1		0x54	/* Multicast Address Register 1 */
+#define	CSR_MC2		0x58	/* Multicast Address Register 2 */
+#define	CSR_MC3		0x5C	/* Multicast Address Register 3 */
+#define	CSR_RXCON	0x60	/* Receive Control Register */
+#define	CSR_RXSTAT	0x64	/* Receive Status Register */
+#define	CSR_RXCNT	0x68	/* Receive Byte Count */
+#define	CSR_RXTEST	0x6C	/* Receive Test */
+#define	CSR_TXCON	0x70	/* Transmit Control Register */
+#define	CSR_TXSTAT	0x74	/* Transmit Status Register */
+#define	CSR_TDPAR	0x78	/* Transmit Packet Address */
+#define	CSR_TXTEST	0x7C	/* Transmit Test */
+#define	CSR_PRFDAR	0x80	/* PCI Receive First Descriptor Address */
+#define	CSR_PRCDAR	0x84	/* PCI Receive Current Descriptor Address */
+#define	CSR_PRHDAR	0x88	/* PCI Receive Host Data Address */
+#define	CSR_PRFLAR	0x8C	/* PCI Receive Fragment List Address */
+#define	CSR_PRDLGTH	0x90	/* PCI Receive DMA Length/Control */
+#define	CSR_PRFCNT	0x94	/* PCI Receive Fragment Count */
+#define	CSR_PRLCAR	0x98	/* PCI Receive RAM Current Address */
+#define	CSR_PRLPAR	0x9C	/* PCI Receive RAM Packet Address */
+#define	CSR_PREFAR	0xA0	/* PCI Receive End of Frame Address */
+#define	CSR_PRSTAT	0xA4	/* PCI Receive DMA Status Register */
+#define	CSR_PRBUF	0xA8	/* Receive RAM Buffer */
+#define	CSR_RDNCAR	0xAC	/* Receive MTU Current Address */
+#define	CSR_PRCPTHR	0xB0	/* PCI Receive Copy Threshold Register */
+#define	CSR_ROMDATA	0xB4	/* ROMDATA */
+#define	CSR_PREEMPR	0xBC	/* Preemptive Interrupt */
+#define	CSR_PTFDAR	0xC0	/* PCI Transmit First Descriptor Address */
+#define	CSR_PTCDAR	0xC4	/* PCI Transmit Current Descriptor Address */
+#define	CSR_PTHDAR	0xC8	/* PCI Transmit Host Data Address */
+#define	CSR_PTFLAR	0xCC	/* PCI Transmit Fragment List Address */
+#define	CSR_PTDLGTH	0xD0	/* PCI Transmit DMA Length/Control */
+#define	CSR_PTFCNT	0xD4	/* PCI Transmit Fragment Count */
+#define	CSR_PTLCAR	0xD8	/* PCI Transmit RAM Current Address */
+#define	CSR_ETXTHR	0xDC	/* PCI Early Transmit Threshold Register */
+#define	CSR_PTETXC	0xE0	/* PCI Early Transmit Count */
+#define	CSR_PTSTAT	0xE4	/* PCI Transmit DMA Status */
+#define	CSR_PTBUF	0xE8	/* Transmit RAM Buffer */
+#define	CSR_PTFDAR2	0xEC	/* PCI Transmit 2 First Descriptor Address */
+#define	CSR_FEVTR	0xF0	/* CardBus (UNUSED) */
+#define	CSR_FEVTRMSKR	0xF4	/* CardBus (UNUSED) */
+#define	CSR_FPRSTSTR	0xF8	/* CardBus (UNUSED) */
+#define	CSR_FFRCEVTR	0xFF	/* CardBus (UNUSED) */
+
+/*
+ * Register fields.
+ */
+#define	COMMAND_STOP_RX		(1UL << 0)	/* Stop Receiver */
+#define	COMMAND_START_RX	(1UL << 1)	/* Start Receiver */
+#define	COMMAND_TXQUEUED	(1UL << 2)	/* Queue TX Descriptor */
+#define	COMMAND_RXQUEUED	(1UL << 3)	/* Queue RX Descriptor */
+#define	COMMAND_NEXTFRAME	(1UL << 4)	/* Release RX Frame */
+#define	COMMAND_STOP_TDMA	(1UL << 5)	/* Stop TX DMA */
+#define	COMMAND_STOP_RDMA	(1UL << 6)	/* Stop RX DMA */
+#define	COMMAND_TXUGO		(1UL << 7)	/* Restart Transmission */
+
+#define	INTSTAT_RCC	(1UL << 0)	/* Receive Copy Complete */
+#define	INTSTAT_HCC	(1UL << 1)	/* Header Copy Complete */
+#define	INTSTAT_RQE	(1UL << 2)	/* Receive Queue Empty */
+#define	INTSTAT_OVW	(1UL << 3)	/* Receive Overflow */
+#define	INTSTAT_RXE	(1UL << 4)	/* Receive Error */
+#define	INTSTAT_TXC	(1UL << 5)	/* Transmit Complete */
+#define	INTSTAT_TCC	(1UL << 6)	/* Transmit Chain Complete */
+#define	INTSTAT_TQE	(1UL << 7)	/* Transmit Queue Empty */
+#define	INTSTAT_TXU	(1UL << 8)	/* Transmit Underrun */
+#define	INTSTAT_CNT	(1UL << 9)	/* Counter Overflow */
+#define	INTSTAT_PREI	(1UL << 10)	/* Preemptive Interrupt */
+#define	INTSTAT_RCT	(1UL << 11)	/* Receive Copy Threshold */
+#define	INTSTAT_FATAL	(1UL << 12)	/* Fatal Error */
+#define	INTSTAT_PME	(1UL << 14)	/* Power Management Event */
+#define	INTSTAT_GP2	(1UL << 15)	/* GPIO Event */
+#define	INTSTAT_ACTV	(1UL << 16)	/* Interrupt Active */
+#define	INTSTAT_RXIDLE	(1UL << 17)	/* Receive Idle */
+#define	INTSTAT_TXIDLE	(1UL << 18)	/* Transmit Idle */
+#define	INTSTAT_RCIP	(1UL << 19)	/* Receive Copy in Progress */
+#define	INTSTAT_TCIP	(1UL << 20)	/* Transmit Copy in Progress */
+#define	INTSTAT_RBE	(1UL << 21)	/* Receive Buffers Empty */
+#define	INTSTAT_RCTS	(1UL << 22)	/* Receive Copy Threshold Status */
+#define	INTSTAT_RSV	(1UL << 23)	/* Receive Status Valid */
+#define	INTSTAT_DPE	(1UL << 24)	/* PCI Data Parity Error */
+#define	INTSTAT_APE	(1UL << 25)	/* PCI Address Parity Error */
+#define	INTSTAT_PMA	(1UL << 26)	/* PCI Master Abort */
+#define	INTSTAT_PTA	(1UL << 27)	/* PCI Target Abort */
+
+#define	INTMASK_RCC	(1UL << 0)	/* Receive Copy Complete */
+#define	INTMASK_HCC	(1UL << 1)	/* Header Copy Complete */
+#define	INTMASK_RQE	(1UL << 2)	/* Receive Queue Empty */
+#define	INTMASK_OVW	(1UL << 3)	/* Receive Overflow */
+#define	INTMASK_RXE	(1UL << 4)	/* Receive Error */
+#define	INTMASK_TXC	(1UL << 5)	/* Transmit Complete */
+#define	INTMASK_TCC	(1UL << 6)	/* Transmit Chain Complete */
+#define	INTMASK_TQE	(1UL << 7)	/* Transmit Queue Empty */
+#define	INTMASK_TXU	(1UL << 8)	/* Transmit Underrun */
+#define	INTMASK_CNT	(1UL << 9)	/* Counter Overflow */
+#define	INTMASK_PREI	(1UL << 10)	/* Preemptive Interrupt */
+#define	INTMASK_RCT	(1UL << 11)	/* Receive Copy Threshold */
+#define	INTMASK_FATAL	(1UL << 12)	/* Fatal Error */
+#define	INTMASK_PME	(1UL << 14)	/* Power Management Event */
+#define	INTMASK_GP2	(1UL << 15)	/* GPIO Event */
+
+#define	GENCTL_RESET	(1UL << 0)	/* Soft Reset */
+#define	GENCTL_INT	(1UL << 1)	/* Interrupt Enable */
+#define	GENCTL_SWINT	(1UL << 2)	/* Software Interrupt */
+#define	GENCTL_PWRDWN	(1UL << 3)	/* Power Down */
+#define	GENCTL_ONECOPY	(1UL << 4)	/* One Copy per Receive Frame */
+#define	GENCTL_BE	(1UL << 5)	/* Big Endian */
+#define	GENCTL_RDP	(1UL << 6)	/* Receive DMA Priority */
+#define	GENCTL_TDP	(1UL << 7)	/* Transmit DMA Priority */
+#define	GENCTL_RFT_32	(0UL << 8)	/* Receive FIFO Threshold (1/4) */
+#define	GENCTL_RFT_64	(1UL << 8)	/* Receive FIFO Threshold (1/2) */
+#define	GENCTL_RFT_96	(2UL << 8)	/* Receive FIFO Threshold (3/4) */
+#define	GENCTL_RFT_128	(3UL << 8)	/* Receive FIFO Threshold (FULL) */
+#define	GENCTL_MRM	(1UL << 10)	/* Memory Read Multiple */
+#define	GENCTL_MRL	(1UL << 11)	/* Memory Read Line */
+#define	GENCTL_SOFT0	(1UL << 12)	/* Software Bit 0 */
+#define	GENCTL_SOFT1	(1UL << 13)	/* Software Bit 1 */
+#define	GENCTL_RSTPHY	(1UL << 14)	/* PHY Reset */
+#define	GENCTL_SCLK	(1UL << 16)	/* System Clock */
+#define	GENCTL_RD	(1UL << 17)	/* Reset Disable */
+#define	GENCTL_MPE	(1UL << 18)	/* Magic Packet Enable */
+#define	GENCTL_PME	(1UL << 19)	/* PME Interrupt Enable */
+#define	GENCTL_PS_00	(0UL << 20)	/* Power State "00" */
+#define	GENCTL_PS_01	(1UL << 20)	/* Power State "01" */
+#define	GENCTL_PS_10	(2UL << 20)	/* Power State "10" */
+#define	GENCTL_PS_11	(3UL << 20)	/* Power State "11" */
+#define	GENCTL_OPLE	(1UL << 22)	/* On Power Loss Enable */
+
+#define	NVCTL_EMM	(1UL << 0)	/* Enable Memory Map */
+#define	NVCTL_CRS	(1UL << 1)	/* Clock Run Supported */
+#define	NVCTL_GPOE1	(1UL << 2)	/* General Purpose Output Enable 1 */
+#define	NVCTL_GPOE2	(1UL << 3)	/* General Purpose Output Enable 2 */
+#define	NVCTL_GPIO1	(1UL << 4)	/* General Purpose I/O 1 */
+#define	NVCTL_GPIO2	(1UL << 5)	/* General Purpose I/O 2 */
+#define	NVCTL_CB_MODE	(1UL << 6)	/* CardBus (UNUSED) */
+#define	NVCTL_IPG_DLY	7		/* Inter-packet Gap Timer Delay */
+
+#define	EECTL_ENABLE	(1UL << 0)	/* EEPROM Enable */
+#define	EECTL_EECS	(1UL << 1)	/* EEPROM Chip Select */
+#define	EECTL_EESK	(1UL << 2)	/* EEPROM Clock */
+#define	EECTL_EEDI	(1UL << 3)	/* EEPROM Data Input */
+#define	EECTL_EEDO	(1UL << 4)	/* EEPROM Data Output */
+#define	EECTL_EERDY	(1UL << 5)	/* EEPROM Ready */
+#define	EECTL_SIZE	(1UL << 6)	/* EEPROM Size */
+
+#define	TEST_CLOCK	(1UL << 3)	/* Clock Test */
+
+#define	MMCTL_READ	(1UL << 0)	/* MII Read */
+#define	MMCTL_WRITE	(1UL << 1)	/* MII Write */
+#define	MMCTL_RESPONDER	(1UL << 3)	/* MII Responder */
+#define	MMCTL_PHYREG	4		/* PHY Address */
+#define	MMCTL_PHYADDR	9		/* PHY Register Address */
+
+#define	MMCFG_SME	(1UL << 0)	/* Serial Mode Enable */
+#define	MMCFG_EN694	(1UL << 1)	/* EN694 Pin */
+#define	MMCFG_694LNK	(1UL << 2)	/* 694LNK Pin */
+#define	MMCFG_PHY	(1UL << 3)	/* PHY Present */
+#define	MMCFG_SMI	(1UL << 4)	/* Enable Serial Management */
+#define	MMCFG_ALTCS	(1UL << 5)	/* Alternate Clock Source */
+#define	MMCFG_ALTDATA	(1UL << 6)	/* Alternate Data */
+#define	MMCFG_STXC	(1UL << 14)	/* Select TX Clock */
+#define	MMCFG_SNTXC	(1UL << 15)	/* Set No TX Clock */
+
+#define	RXCON_SEP	(1UL << 0)	/* Save Errored Packets */
+#define	RXCON_RRF	(1UL << 1)	/* Receive Runt Frames */
+#define	RXCON_RBF	(1UL << 2)	/* Receive Broadcast Frames */
+#define	RXCON_RMF	(1UL << 3)	/* Receive Multicast Frames */
+#define	RXCON_RIIA	(1UL << 4)	/* Receive Inverse Addresses */
+#define	RXCON_PROMISC	(1UL << 5)	/* Promiscuous Mode */
+#define	RXCON_MONITOR	(1UL << 6)	/* Monitor Mode */
+#define	RXCON_ERE	(1UL << 7)	/* Early Receive Enable */
+#define	RXCON_EB_INT	(0UL << 8)	/* External Buffer (Inernal) */
+#define	RXCON_EB_16K	(1UL << 8)	/* External Buffer (16K) */
+#define	RXCON_EB_32K	(2UL << 8)	/* External Buffer (32K) */
+#define	RXCON_EB_128K	(3UL << 8)	/* External Buffer (128K) */
+
+#define	RXSTAT_PRI	(1UL << 0)	/* Packet Received Intact */
+#define	RXSTAT_FAE	(1UL << 1)	/* Frame Alignment Error */
+#define	RXSTAT_CRC	(1UL << 2)	/* CRC Error */
+#define	RXSTAT_MP	(1UL << 3)	/* Missed Packet */
+#define	RXSTAT_MAR	(1UL << 4)	/* Multicast Address Recognized */
+#define	RXSTAT_BAR	(1UL << 5)	/* Broadcast Address Recognized */
+#define	RXSTAT_RD	(1UL << 6)	/* Receiver Disabled */
+#define	RXSTAT_NSV	(1UL << 12)	/* Network Status Valid */
+#define	RXSTAT_FLE	(1UL << 13)	/* Fragment List Error */
+#define	RXSTAT_HC	(1UL << 14)	/* Header Copied */
+#define	RXSTAT_OWNER	(1UL << 15)	/* Descriptor Ownership Bit */
+
+#define	RXCTL_FRAGLIST	(1UL << 0)	/* Fragment List */
+#define	RXCTL_LFFORM	(1UL << 1)	/* Fragment List Format */
+#define	RXCTL_HEADER	(1UL << 2)	/* Header Copy */
+
+#define	TXCON_ETE	(1UL << 0)	/* Early Transmit Enable */
+#define	TXCON_LB_0	(0UL << 1)	/* Normal Operation */
+#define	TXCON_LB_1	(1UL << 1)	/* Internal Loopback */
+#define	TXCON_LB_2	(2UL << 1)	/* External Loopback */
+#define	TXCON_LB_3	(3UL << 1)	/* Full Duplex Mode */
+#define	TXCON_SLOT	3		/* Slot Time */
+
+#define	TXSTAT_PTX	(1UL << 0)	/* Packet Transmitted */
+#define	TXSTAT_ND	(1UL << 1)	/* Non-deferred Transmission */
+#define	TXSTAT_COLL	(1UL << 2)	/* Transmitted w/Collisions */
+#define	TXSTAT_CSL	(1UL << 3)	/* Carrier Sense Lost */
+#define	TXSTAT_UFLO	(1UL << 4)	/* TX Underrun */
+#define	TXSTAT_CDH	(1UL << 5)	/* Collision Detect Heartbeat */
+#define	TXSTAT_OWC	(1UL << 6)	/* Out of Window Collision */
+#define	TXSTAT_DEFER	(1UL << 7)	/* IGP Deferring */
+#define	TXSTAT_CCNT	8		/* Collision Count */
+#define	TXSTAT_CCNTMASK	0x1F		/* Collision Count Mask */
+#define	TXSTAT_EXCOLL	(1UL << 12)	/* Excessive Collisions */
+#define	TXSTAT_OWNER	(1UL << 15)	/* Descriptor Ownership Bit */
+
+#define	TXCTL_FRAGLIST	(1UL << 0)	/* Fragment List */
+#define	TXCTL_LFFORM	(1UL << 1)	/* Fragment List Format */
+#define	TXCTL_IAF	(1UL << 2)	/* Interrupt After Frame */
+#define	TXCTL_NOCRC	(1UL << 3)	/* Disable CRC Generation */
+#define	TXCTL_LASTDESCR	(1UL << 4)	/* Last Transmit Descriptor */
+
+/*
+ * Register access.
+ */
+#define	GETCSR(efep, reg) \
+	ddi_get32((efep)->efe_regs_acch, \
+	    (efep)->efe_regs + ((reg) / sizeof (uint32_t)))
+
+#define	PUTCSR(efep, reg, val) \
+	ddi_put32((efep)->efe_regs_acch, \
+	    (efep)->efe_regs + ((reg) / sizeof (uint32_t)), (val))
+
+#define	CLRBIT(efep, reg, bit) \
+	PUTCSR(efep, reg, (GETCSR(efep, reg) & ~(bit)))
+
+#define	SETBIT(efep, reg, bit) \
+	PUTCSR(efep, reg, (GETCSR(efep, reg) | (bit)))
+
+/*
+ * DMA access.
+ */
+#define	DESCSZ(x)		(sizeof (efe_desc_t) * (x))
+#define	BUFPSZ(x)		(sizeof (efe_buf_t *) * (x))
+
+#define	DESCADDR(rp, x)		((rp)->r_dmac.dmac_address + DESCSZ(x))
+#define	DESCLEN(rp)		((rp)->r_len)
+
+#define	BUFADDR(bp)		((bp)->b_dmac.dmac_address)
+#define	BUFLEN(bp)		((bp)->b_len)
+
+#define	NEXTDESC(rp, x)		(((x) + 1) % (rp)->r_len)
+#define	NEXTDESCADDR(rp, x)	DESCADDR(rp, NEXTDESC(rp, x))
+
+#define	GETDESC(rp, x) 		(&(rp)->r_descp[(x)])
+
+#define	GETDESC16(rp, addr) \
+	ddi_get16((rp)->r_acch, (addr))
+
+#define	PUTDESC16(rp, addr, val) \
+	ddi_put16((rp)->r_acch, (addr), (val))
+
+#define	GETDESC32(rp, addr) \
+	ddi_get32((rp)->r_acch, (addr))
+
+#define	PUTDESC32(rp, addr, val) \
+	ddi_put32((rp)->r_acch, (addr), (val))
+
+#define	SYNCDESC(rp, x, type) \
+	(void) ddi_dma_sync((rp)->r_dmah, DESCSZ(x), \
+	    sizeof (efe_desc_t), (type))
+
+#define	GETBUF(rp, x)		((rp)->r_bufpp[(x)])
+
+#define	SYNCBUF(bp, type) \
+	(void) ddi_dma_sync((bp)->b_dmah, 0, (bp)->b_len, (type))
+
+/*
+ * Soft state.
+ */
+typedef struct {
+	uint16_t		d_status;
+	uint16_t		d_len;
+	uint32_t		d_bufaddr;
+	uint16_t		d_buflen;
+	uint16_t		d_control;
+	uint32_t		d_next;
+} efe_desc_t;
+
+typedef struct {
+	ddi_dma_handle_t	b_dmah;
+	ddi_acc_handle_t	b_acch;
+	ddi_dma_cookie_t	b_dmac;
+	size_t			b_len;
+	caddr_t			b_kaddr;
+} efe_buf_t;
+
+typedef struct {
+	ddi_dma_handle_t	r_dmah;
+	ddi_acc_handle_t	r_acch;
+	ddi_dma_cookie_t	r_dmac;
+	size_t			r_len;
+	efe_desc_t		*r_descp;
+	efe_buf_t		**r_bufpp;
+} efe_ring_t;
+
+typedef struct {
+	dev_info_t		*efe_dip;
+
+	mii_handle_t		efe_miih;
+	mac_handle_t		efe_mh;
+
+	uint32_t		*efe_regs;
+	ddi_acc_handle_t	efe_regs_acch;
+
+	ddi_intr_handle_t	efe_intrh;
+
+	kmutex_t		efe_intrlock;
+	kmutex_t		efe_txlock;
+
+	int			efe_flags;
+	boolean_t		efe_promisc;
+
+	uint8_t			efe_macaddr[ETHERADDRL];
+
+	uint_t			efe_mccount[MCHASHL];
+	uint16_t		efe_mchash[MCHASHL / MCHASHSZ];
+
+	efe_ring_t		*efe_rx_ring;
+	uint_t			efe_rx_desc;
+
+	efe_ring_t		*efe_tx_ring;
+	uint_t			efe_tx_desc;
+	uint_t			efe_tx_sent;
+
+	/*
+	 * Driver statistics.
+	 */
+	uint64_t		efe_multircv;
+	uint64_t		efe_brdcstrcv;
+	uint64_t		efe_multixmt;
+	uint64_t		efe_brdcstxmt;
+	uint64_t		efe_norcvbuf;
+	uint64_t		efe_ierrors;
+	uint64_t		efe_noxmtbuf;
+	uint64_t		efe_oerrors;
+	uint64_t		efe_collisions;
+	uint64_t		efe_rbytes;
+	uint64_t		efe_ipackets;
+	uint64_t		efe_obytes;
+	uint64_t		efe_opackets;
+	uint64_t		efe_uflo;
+	uint64_t		efe_oflo;
+	uint64_t		efe_align_errors;
+	uint64_t		efe_fcs_errors;
+	uint64_t		efe_first_collisions;
+	uint64_t		efe_tx_late_collisions;
+	uint64_t		efe_defer_xmts;
+	uint64_t		efe_ex_collisions;
+	uint64_t		efe_macxmt_errors;
+	uint64_t		efe_carrier_errors;
+	uint64_t		efe_toolong_errors;
+	uint64_t		efe_macrcv_errors;
+	uint64_t		efe_runt_errors;
+	uint64_t		efe_jabber_errors;
+} efe_t;
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _EFE_H */
--- a/usr/src/uts/intel/Makefile.intel.shared	Mon Oct 25 11:04:06 2010 -0700
+++ b/usr/src/uts/intel/Makefile.intel.shared	Wed Oct 27 08:57:45 2010 -0400
@@ -388,6 +388,7 @@
 DRV_KMODS	+= bfe
 DRV_KMODS	+= dmfe
 DRV_KMODS	+= e1000g
+DRV_KMODS	+= efe
 DRV_KMODS	+= elxl
 DRV_KMODS	+= hme
 DRV_KMODS	+= mxfe
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/efe/Makefile	Wed Oct 27 08:57:45 2010 -0400
@@ -0,0 +1,67 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE		= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= efe
+OBJECTS		= $(EFE_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(EFE_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/intel/Makefile.intel
+
+#
+#	Define targets.
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+#	Driver flags.
+#
+CFLAGS		+= $(CCVERBOSE)
+LDFLAGS		+= -dy -N misc/mac -N misc/mii
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/intel/Makefile.targ
--- a/usr/src/uts/intel/os/master	Mon Oct 25 11:04:06 2010 -0700
+++ b/usr/src/uts/intel/os/master	Wed Oct 27 08:57:45 2010 -0400
@@ -300,7 +300,6 @@
 pci8086,1229.8086.1017 pci8086,1229 net pci iprb.bef "Intel Pro100/B Fast Ethernet"
 pci8086,2449 pci8086,2449 net pci iprb.bef "Intel i815/82559 Ethernet"
 pci8086,27dc pci8086,27dc net pci iprb.bef "Intel ICH7 82801G Ethernet"
-pci10b8,5 pci10b8,5 net pci spwr.bef "SMC EtherPower II 10/100 (9432)"
 pci101a,f2d scsi msd pci none "NCR PDS/PQS 53C896-based PCI SCSI Adapter" compatible="pci101a,f2d"
 pci101a,f2e scsi msd pci none "NCR PDS/PQS 53C896-based PCI SCSI Adapter" compatible="pci101a,f2e"
 pci101a,f2f scsi msd pci none "NCR PDS/PQS 53C896-based PCI SCSI Adapter" compatible="pci101a,f2f"
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Mon Oct 25 11:04:06 2010 -0700
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Wed Oct 27 08:57:45 2010 -0400
@@ -249,6 +249,7 @@
 DRV_KMODS	+= audiopci
 DRV_KMODS	+= audiots
 DRV_KMODS	+= e1000g
+DRV_KMODS	+= efe
 DRV_KMODS	+= hxge
 DRV_KMODS	+= mxfe
 DRV_KMODS	+= pcan
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/sparc/efe/Makefile	Wed Oct 27 08:57:45 2010 -0400
@@ -0,0 +1,67 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+#	Path to the base of the uts directory tree (usually /usr/src/uts).
+#
+UTSBASE		= ../..
+
+#
+#	Define the module and object file sets.
+#
+MODULE		= efe
+OBJECTS		= $(EFE_OBJS:%=$(OBJS_DIR)/%)
+LINTS		= $(EFE_OBJS:%.o=$(LINTS_DIR)/%.ln)
+ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
+
+#
+#	Include common rules.
+#
+include $(UTSBASE)/sparc/Makefile.sparc
+
+#
+#	Define targets.
+#
+ALL_TARGET	= $(BINARY)
+LINT_TARGET	= $(MODULE).lint
+INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
+
+#
+#	Driver flags.
+#
+CFLAGS		+= $(CCVERBOSE)
+LDFLAGS		+= -dy -N misc/mac -N misc/mii
+
+#
+#	Default build targets.
+#
+.KEEP_STATE:
+
+def:		$(DEF_DEPS)
+
+all:		$(ALL_DEPS)
+
+clean:		$(CLEAN_DEPS)
+
+clobber:	$(CLOBBER_DEPS)
+
+lint:		$(LINT_DEPS)
+
+modlintlib:	$(MODLINTLIB_DEPS)
+
+clean.lint:	$(CLEAN_LINT_DEPS)
+
+install:	$(INSTALL_DEPS)
+
+#
+#	Include common targets.
+#
+include $(UTSBASE)/sparc/Makefile.targ