--- /dev/null	2013-08-22 18:57:28.000000000 -0400
+++ new/usr/src/uts/common/io/sfxge/efx_mac.c	2013-08-22 18:57:28.062447405 -0400
@@ -0,0 +1,684 @@
+/*
+ * Copyright 2007-2013 Solarflare Communications 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.
+ *
+ * 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 AUTHOR 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 "efsys.h"
+#include "efx.h"
+#include "efx_types.h"
+#include "efx_impl.h"
+
+#if EFSYS_OPT_MAC_FALCON_GMAC
+#include "falcon_gmac.h"
+#endif
+
+#if EFSYS_OPT_MAC_FALCON_XMAC
+#include "falcon_xmac.h"
+#endif
+
+#if EFSYS_OPT_MAC_FALCON_GMAC
+static efx_mac_ops_t	__cs __efx_falcon_gmac_ops = {
+	falcon_gmac_reset,		/* emo_reset */
+	falcon_mac_poll,		/* emo_poll */
+	falcon_mac_up,			/* emo_up */
+	falcon_gmac_reconfigure,	/* emo_reconfigure */
+#if EFSYS_OPT_LOOPBACK
+	falcon_mac_loopback_set,	/* emo_loopback_set */
+#endif	/* EFSYS_OPT_LOOPBACK */
+#if EFSYS_OPT_MAC_STATS
+	falcon_mac_stats_upload,	/* emo_stats_upload */
+	NULL,				/* emo_stats_periodic */
+	falcon_gmac_stats_update	/* emo_stats_update */
+#endif	/* EFSYS_OPT_MAC_STATS */
+};
+#endif	/* EFSYS_OPT_MAC_FALCON_GMAC */
+
+#if EFSYS_OPT_MAC_FALCON_XMAC
+static efx_mac_ops_t	__cs __efx_falcon_xmac_ops = {
+	falcon_xmac_reset,		/* emo_reset */
+	falcon_mac_poll,		/* emo_poll */
+	falcon_mac_up,			/* emo_up */
+	falcon_xmac_reconfigure,	/* emo_reconfigure */
+#if EFSYS_OPT_LOOPBACK
+	falcon_mac_loopback_set,	/* emo_loopback_set */
+#endif	/* EFSYS_OPT_LOOPBACK */
+#if EFSYS_OPT_MAC_STATS
+	falcon_mac_stats_upload,	/* emo_stats_upload */
+	NULL,				/* emo_stats_periodic */
+	falcon_xmac_stats_update	/* emo_stats_update */
+#endif	/* EFSYS_OPT_MAC_STATS */
+};
+#endif	/* EFSYS_OPT_MAC_FALCON_XMAC */
+
+#if EFSYS_OPT_SIENA
+static efx_mac_ops_t	__cs __efx_siena_mac_ops = {
+	NULL,				/* emo_reset */
+	siena_mac_poll,			/* emo_poll */
+	siena_mac_up,			/* emo_up */
+	siena_mac_reconfigure,		/* emo_reconfigure */
+#if EFSYS_OPT_LOOPBACK
+	siena_mac_loopback_set,		/* emo_loopback_set */
+#endif	/* EFSYS_OPT_LOOPBACK */
+#if EFSYS_OPT_MAC_STATS
+	siena_mac_stats_upload,		/* emo_stats_upload */
+	siena_mac_stats_periodic,	/* emo_stats_periodic */
+	siena_mac_stats_update		/* emo_stats_update */
+#endif	/* EFSYS_OPT_MAC_STATS */
+};
+#endif	/* EFSYS_OPT_SIENA */
+
+static efx_mac_ops_t	__cs * __cs __efx_mac_ops[] = {
+	NULL,
+#if EFSYS_OPT_MAC_FALCON_GMAC
+	&__efx_falcon_gmac_ops,
+#else
+	NULL,
+#endif	/* EFSYS_OPT_MAC_FALCON_GMAC */
+#if EFSYS_OPT_MAC_FALCON_XMAC
+	&__efx_falcon_xmac_ops,
+#else
+	NULL,
+#endif	/* EFSYS_OPT_MAC_FALCON_XMAC */
+#if EFSYS_OPT_SIENA
+	&__efx_siena_mac_ops,
+#else
+	NULL,
+#endif	/* EFSYS_OPT_SIENA */
+};
+
+	__checkReturn			int
+efx_mac_pdu_set(
+	__in				efx_nic_t *enp,
+	__in				size_t pdu)
+{
+	efx_port_t *epp = &(enp->en_port);
+	efx_mac_ops_t *emop = epp->ep_emop;
+	uint32_t old_pdu;
+	int rc;
+
+	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
+	EFSYS_ASSERT(emop != NULL);
+
+	if (pdu < EFX_MAC_PDU_MIN) {
+		rc = EINVAL;
+		goto fail1;
+	}
+
+	if (pdu > EFX_MAC_PDU_MAX) {
+		rc = EINVAL;
+		goto fail2;
+	}
+
+	old_pdu = epp->ep_mac_pdu;
+	epp->ep_mac_pdu = (uint32_t)pdu;
+	if ((rc = emop->emo_reconfigure(enp)) != 0)
+		goto fail3;
+
+	return (0);
+
+fail3:
+	EFSYS_PROBE(fail3);
+
+	epp->ep_mac_pdu = old_pdu;
+
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, int, rc);
+
+	return (rc);
+}
+
+	__checkReturn			int
+efx_mac_addr_set(
+	__in				efx_nic_t *enp,
+	__in				uint8_t *addr)
+{
+	efx_port_t *epp = &(enp->en_port);
+	efx_mac_ops_t *emop = epp->ep_emop;
+	uint8_t old_addr[6];
+	uint32_t oui;
+	int rc;
+
+	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
+
+	if (addr[0] & 0x01) {
+		rc = EINVAL;
+		goto fail1;
+	}
+
+	oui = addr[0] << 16 | addr[1] << 8 | addr[2];
+	if (oui == 0x000000) {
+		rc = EINVAL;
+		goto fail2;
+	}
+
+	EFX_MAC_ADDR_COPY(old_addr, epp->ep_mac_addr);
+	EFX_MAC_ADDR_COPY(epp->ep_mac_addr, addr);
+	if ((rc = emop->emo_reconfigure(enp)) != 0)
+		goto fail3;
+
+	return (0);
+
+fail3:
+	EFSYS_PROBE(fail3);
+
+	EFX_MAC_ADDR_COPY(epp->ep_mac_addr, old_addr);
+
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, int, rc);
+
+	return (rc);
+}
+
+	__checkReturn			int
+efx_mac_filter_set(
+	__in				efx_nic_t *enp,
+	__in				boolean_t unicst,
+	__in				boolean_t brdcst)
+{
+	efx_port_t *epp = &(enp->en_port);
+	efx_mac_ops_t *emop = epp->ep_emop;
+	boolean_t old_unicst;
+	boolean_t old_brdcst;
+	int rc;
+
+	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
+
+	old_unicst = unicst;
+	old_brdcst = brdcst;
+
+	epp->ep_unicst = unicst;
+	epp->ep_brdcst = brdcst;
+
+	if ((rc = emop->emo_reconfigure(enp)) != 0)
+		goto fail1;
+
+	return (0);
+
+fail1:
+	EFSYS_PROBE1(fail1, int, rc);
+
+	epp->ep_unicst = old_unicst;
+	epp->ep_brdcst = old_brdcst;
+
+	return (rc);
+}
+
+	__checkReturn			int
+efx_mac_drain(
+	__in				efx_nic_t *enp,
+	__in				boolean_t enabled)
+{
+	efx_port_t *epp = &(enp->en_port);
+	efx_mac_ops_t *emop = epp->ep_emop;
+	int rc;
+
+	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
+	EFSYS_ASSERT(emop != NULL);
+
+	if (epp->ep_mac_drain == enabled)
+		return (0);
+
+	epp->ep_mac_drain = enabled;
+
+	if (enabled && emop->emo_reset != NULL) {
+		if ((rc = emop->emo_reset(enp)) != 0)
+			goto fail1;
+
+		EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_MAC);
+		enp->en_reset_flags &= ~EFX_RESET_PHY;
+	}
+
+	if ((rc = emop->emo_reconfigure(enp)) != 0)
+		goto fail2;
+
+	return (0);
+
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, int, rc);
+
+	return (rc);
+}
+
+	__checkReturn	int
+efx_mac_up(
+	__in		efx_nic_t *enp,
+	__out		boolean_t *mac_upp)
+{
+	efx_port_t *epp = &(enp->en_port);
+	efx_mac_ops_t *emop = epp->ep_emop;
+	int rc;
+
+	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
+
+	if ((rc = emop->emo_up(enp, mac_upp)) != 0)
+		goto fail1;
+
+	return (0);
+
+fail1:
+	EFSYS_PROBE1(fail1, int, rc);
+
+	return (rc);
+}
+
+	__checkReturn			int
+efx_mac_fcntl_set(
+	__in				efx_nic_t *enp,
+	__in				unsigned int fcntl,
+	__in				boolean_t autoneg)
+{
+	efx_port_t *epp = &(enp->en_port);
+	efx_mac_ops_t *emop = epp->ep_emop;
+	efx_phy_ops_t *epop = epp->ep_epop;
+	unsigned int old_fcntl;
+	boolean_t old_autoneg;
+	unsigned int old_adv_cap;
+	int rc;
+
+	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
+
+	if ((fcntl & ~(EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE)) != 0) {
+		rc = EINVAL;
+		goto fail1;
+	}
+
+	/*
+	 * Ignore a request to set flow control autonegotiation
+	 * if the PHY doesn't support it.
+	 */
+	if (~epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
+		autoneg = B_FALSE;
+
+	old_fcntl = epp->ep_fcntl;
+	old_autoneg = autoneg;
+	old_adv_cap = epp->ep_adv_cap_mask;
+
+	epp->ep_fcntl = fcntl;
+	epp->ep_fcntl_autoneg = autoneg;
+
+	/*
+	 * If the PHY supports autonegotiation, then encode the flow control
+	 * settings in the advertised capabilities, and restart AN. Otherwise,
+	 * just push the new settings directly to the MAC.
+	 */
+	if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN)) {
+		if (fcntl & EFX_FCNTL_RESPOND)
+			epp->ep_adv_cap_mask |=    (1 << EFX_PHY_CAP_PAUSE |
+						    1 << EFX_PHY_CAP_ASYM);
+		else
+			epp->ep_adv_cap_mask &=   ~(1 << EFX_PHY_CAP_PAUSE |
+						    1 << EFX_PHY_CAP_ASYM);
+
+		if (fcntl & EFX_FCNTL_GENERATE)
+			epp->ep_adv_cap_mask ^= (1 << EFX_PHY_CAP_ASYM);
+
+		if ((rc = epop->epo_reconfigure(enp)) != 0)
+			goto fail2;
+
+	} else {
+		if ((rc = emop->emo_reconfigure(enp)) != 0)
+			goto fail2;
+	}
+
+	return (0);
+
+fail2:
+	EFSYS_PROBE(fail2);
+
+	epp->ep_fcntl = old_fcntl;
+	epp->ep_fcntl_autoneg = old_autoneg;
+	epp->ep_adv_cap_mask = old_adv_cap;
+
+fail1:
+	EFSYS_PROBE1(fail1, int, rc);
+
+	return (rc);
+}
+
+			void
+efx_mac_fcntl_get(
+	__in		efx_nic_t *enp,
+	__out		unsigned int *fcntl_wantedp,
+	__out		unsigned int *fcntl_linkp)
+{
+	efx_port_t *epp = &(enp->en_port);
+	unsigned int wanted;
+
+	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
+
+	/*
+	 * If the PHY supports auto negotiation, then the requested flow
+	 * control settings are encoded in the advertised capabilities.
+	 */
+	if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN)) {
+		wanted = 0;
+
+		if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_PAUSE))
+			wanted = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
+		if (epp->ep_adv_cap_mask & (1 << EFX_PHY_CAP_ASYM))
+			wanted ^= EFX_FCNTL_GENERATE;
+	} else
+		wanted = epp->ep_fcntl;
+
+	*fcntl_linkp = epp->ep_fcntl;
+	*fcntl_wantedp = wanted;
+}
+
+	__checkReturn			int
+efx_mac_hash_set(
+	__in				efx_nic_t *enp,
+	__in_ecount(EFX_MAC_HASH_BITS)	unsigned int const *bucket)
+{
+	efx_port_t *epp = &(enp->en_port);
+	efx_mac_ops_t *emop = epp->ep_emop;
+	efx_oword_t old_hash[2];
+	unsigned int index;
+	int rc;
+
+	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
+
+	memcpy(old_hash, epp->ep_multicst_hash, sizeof (old_hash));
+
+	/* Set the lower 128 bits of the hash */
+	EFX_ZERO_OWORD(epp->ep_multicst_hash[0]);
+	for (index = 0; index < 128; index++) {
+		if (bucket[index] != 0)
+			EFX_SET_OWORD_BIT(epp->ep_multicst_hash[0], index);
+	}
+
+	/* Set the upper 128 bits of the hash */
+	EFX_ZERO_OWORD(epp->ep_multicst_hash[1]);
+	for (index = 0; index < 128; index++) {
+		if (bucket[index + 128] != 0)
+			EFX_SET_OWORD_BIT(epp->ep_multicst_hash[1], index);
+	}
+
+	if ((rc = emop->emo_reconfigure(enp)) != 0)
+		goto fail1;
+
+	return (0);
+
+fail1:
+	EFSYS_PROBE1(fail1, int, rc);
+
+	memcpy(epp->ep_multicst_hash, old_hash, sizeof (old_hash));
+
+	return (rc);
+}
+
+#if EFSYS_OPT_MAC_STATS
+
+#if EFSYS_OPT_NAMES
+
+/* START MKCONFIG GENERATED EfxMacStatNamesBlock adf707adba80813e */
+static const char 	__cs * __cs __efx_mac_stat_name[] = {
+	"rx_octets",
+	"rx_pkts",
+	"rx_unicst_pkts",
+	"rx_multicst_pkts",
+	"rx_brdcst_pkts",
+	"rx_pause_pkts",
+	"rx_le_64_pkts",
+	"rx_65_to_127_pkts",
+	"rx_128_to_255_pkts",
+	"rx_256_to_511_pkts",
+	"rx_512_to_1023_pkts",
+	"rx_1024_to_15xx_pkts",
+	"rx_ge_15xx_pkts",
+	"rx_errors",
+	"rx_fcs_errors",
+	"rx_drop_events",
+	"rx_false_carrier_errors",
+	"rx_symbol_errors",
+	"rx_align_errors",
+	"rx_internal_errors",
+	"rx_jabber_pkts",
+	"rx_lane0_char_err",
+	"rx_lane1_char_err",
+	"rx_lane2_char_err",
+	"rx_lane3_char_err",
+	"rx_lane0_disp_err",
+	"rx_lane1_disp_err",
+	"rx_lane2_disp_err",
+	"rx_lane3_disp_err",
+	"rx_match_fault",
+	"rx_nodesc_drop_cnt",
+	"tx_octets",
+	"tx_pkts",
+	"tx_unicst_pkts",
+	"tx_multicst_pkts",
+	"tx_brdcst_pkts",
+	"tx_pause_pkts",
+	"tx_le_64_pkts",
+	"tx_65_to_127_pkts",
+	"tx_128_to_255_pkts",
+	"tx_256_to_511_pkts",
+	"tx_512_to_1023_pkts",
+	"tx_1024_to_15xx_pkts",
+	"tx_ge_15xx_pkts",
+	"tx_errors",
+	"tx_sgl_col_pkts",
+	"tx_mult_col_pkts",
+	"tx_ex_col_pkts",
+	"tx_late_col_pkts",
+	"tx_def_pkts",
+	"tx_ex_def_pkts",
+};
+/* END MKCONFIG GENERATED EfxMacStatNamesBlock */
+
+	__checkReturn			const char __cs *
+efx_mac_stat_name(
+	__in				efx_nic_t *enp,
+	__in				unsigned int id)
+{
+	_NOTE(ARGUNUSED(enp))
+	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+
+	EFSYS_ASSERT3U(id, <, EFX_MAC_NSTATS);
+	return (__efx_mac_stat_name[id]);
+}
+
+#endif	/* EFSYS_OPT_STAT_NAME */
+
+	__checkReturn			int
+efx_mac_stats_upload(
+	__in				efx_nic_t *enp,
+	__in				efsys_mem_t *esmp)
+{
+	efx_port_t *epp = &(enp->en_port);
+	efx_mac_ops_t *emop = epp->ep_emop;
+	int rc;
+
+	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
+	EFSYS_ASSERT(emop != NULL);
+
+	/*
+	 * Don't assert !ep_mac_stats_pending, because the client might
+	 * have failed to finalise statistics when previously stopping
+	 * the port.
+	 */
+	if ((rc = emop->emo_stats_upload(enp, esmp)) != 0)
+		goto fail1;
+
+	epp->ep_mac_stats_pending = B_TRUE;
+
+	return (0);
+
+fail1:
+	EFSYS_PROBE1(fail1, int, rc);
+
+	return (rc);
+}
+
+	__checkReturn			int
+efx_mac_stats_periodic(
+	__in				efx_nic_t *enp,
+	__in				efsys_mem_t *esmp,
+	__in				uint16_t period_ms,
+	__in				boolean_t events)
+{
+	efx_port_t *epp = &(enp->en_port);
+	efx_mac_ops_t *emop = epp->ep_emop;
+	int rc;
+
+	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
+
+	EFSYS_ASSERT(emop != NULL);
+
+	if (emop->emo_stats_periodic == NULL) {
+		rc = EINVAL;
+		goto fail1;
+	}
+
+	if ((rc = emop->emo_stats_periodic(enp, esmp, period_ms, events)) != 0)
+		goto fail2;
+
+	return (0);
+
+fail2:
+	EFSYS_PROBE(fail2);
+fail1:
+	EFSYS_PROBE1(fail1, int, rc);
+
+	return (rc);
+}
+
+
+	__checkReturn			int
+efx_mac_stats_update(
+	__in				efx_nic_t *enp,
+	__in				efsys_mem_t *esmp,
+	__inout_ecount(EFX_MAC_NSTATS)	efsys_stat_t *essp,
+	__in				uint32_t *generationp)
+{
+	efx_port_t *epp = &(enp->en_port);
+	efx_mac_ops_t *emop = epp->ep_emop;
+	int rc;
+
+	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
+	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT);
+	EFSYS_ASSERT(emop != NULL);
+
+	rc = emop->emo_stats_update(enp, esmp, essp, generationp);
+	if (rc == 0)
+		epp->ep_mac_stats_pending = B_FALSE;
+
+	return (rc);
+}
+
+#endif	/* EFSYS_OPT_MAC_STATS */
+
+	__checkReturn			int
+efx_mac_select(
+	__in				efx_nic_t *enp)
+{
+	efx_port_t *epp = &(enp->en_port);
+	efx_mac_type_t type = EFX_MAC_INVALID;
+	efx_mac_ops_t *emop;
+	int rc = EINVAL;
+
+#if EFSYS_OPT_SIENA
+	if (enp->en_family == EFX_FAMILY_SIENA) {
+		type = EFX_MAC_SIENA;
+		goto chosen;
+	}
+#endif
+
+#if EFSYS_OPT_FALCON
+	switch (epp->ep_link_mode) {
+#if EFSYS_OPT_MAC_FALCON_GMAC
+	case EFX_LINK_100HDX:
+	case EFX_LINK_100FDX:
+	case EFX_LINK_1000HDX:
+	case EFX_LINK_1000FDX:
+		type = EFX_MAC_FALCON_GMAC;
+		goto chosen;
+#endif	/* EFSYS_OPT_FALCON_GMAC */
+
+#if EFSYS_OPT_MAC_FALCON_XMAC
+	case EFX_LINK_10000FDX:
+		type = EFX_MAC_FALCON_XMAC;
+		goto chosen;
+#endif	/* EFSYS_OPT_FALCON_XMAC */
+
+	default:
+#if EFSYS_OPT_MAC_FALCON_GMAC && EFSYS_OPT_MAC_FALCON_XMAC
+		/* Only initialise a MAC supported by the PHY */
+		if (epp->ep_phy_cap_mask &
+		    ((1 << EFX_PHY_CAP_1000FDX) |
+		    (1 << EFX_PHY_CAP_1000HDX) |
+		    (1 << EFX_PHY_CAP_100FDX) |
+		    (1 << EFX_PHY_CAP_100HDX) |
+		    (1 << EFX_PHY_CAP_10FDX) |
+		    (1 << EFX_PHY_CAP_10FDX)))
+			type = EFX_MAC_FALCON_GMAC;
+		else
+			type = EFX_MAC_FALCON_XMAC;
+#elif EFSYS_OPT_MAC_FALCON_GMAC
+		type = EFX_MAC_FALCON_GMAC;
+#else
+		type = EFX_MAC_FALCON_XMAC;
+#endif
+		goto chosen;
+	}
+#endif	/* EFSYS_OPT_FALCON */
+
+chosen:
+	EFSYS_ASSERT(type != EFX_MAC_INVALID);
+	EFSYS_ASSERT3U(type, <, EFX_MAC_NTYPES);
+	emop = epp->ep_emop = (efx_mac_ops_t *)__efx_mac_ops[type];
+	EFSYS_ASSERT(emop != NULL);
+
+	epp->ep_mac_type = type;
+
+	if (emop->emo_reset != NULL) {
+		if ((rc = emop->emo_reset(enp)) != 0)
+			goto fail1;
+
+		EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_MAC);
+		enp->en_reset_flags &= ~EFX_RESET_MAC;
+	}
+
+	return (0);
+
+fail1:
+	EFSYS_PROBE1(fail1, int, rc);
+
+	return (rc);
+}
