Index: stable/11/sys/dev/sfxge/common/ef10_phy.c =================================================================== --- stable/11/sys/dev/sfxge/common/ef10_phy.c (revision 342423) +++ stable/11/sys/dev/sfxge/common/ef10_phy.c (revision 342424) @@ -1,634 +1,636 @@ /*- * Copyright (c) 2012-2016 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 COPYRIGHT HOLDERS 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. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD static void mcdi_phy_decode_cap( __in uint32_t mcdi_cap, __out uint32_t *maskp) { uint32_t mask; mask = 0; if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) mask |= (1 << EFX_PHY_CAP_10HDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) mask |= (1 << EFX_PHY_CAP_10FDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) mask |= (1 << EFX_PHY_CAP_100HDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) mask |= (1 << EFX_PHY_CAP_100FDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) mask |= (1 << EFX_PHY_CAP_1000HDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) mask |= (1 << EFX_PHY_CAP_1000FDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) mask |= (1 << EFX_PHY_CAP_10000FDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) mask |= (1 << EFX_PHY_CAP_40000FDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) mask |= (1 << EFX_PHY_CAP_PAUSE); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) mask |= (1 << EFX_PHY_CAP_ASYM); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) mask |= (1 << EFX_PHY_CAP_AN); *maskp = mask; } static void mcdi_phy_decode_link_mode( __in efx_nic_t *enp, __in uint32_t link_flags, __in unsigned int speed, __in unsigned int fcntl, __out efx_link_mode_t *link_modep, __out unsigned int *fcntlp) { boolean_t fd = !!(link_flags & (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN)); boolean_t up = !!(link_flags & (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN)); _NOTE(ARGUNUSED(enp)) if (!up) *link_modep = EFX_LINK_DOWN; else if (speed == 40000 && fd) *link_modep = EFX_LINK_40000FDX; else if (speed == 10000 && fd) *link_modep = EFX_LINK_10000FDX; else if (speed == 1000) *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX; else if (speed == 100) *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX; else if (speed == 10) *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX; else *link_modep = EFX_LINK_UNKNOWN; if (fcntl == MC_CMD_FCNTL_OFF) *fcntlp = 0; else if (fcntl == MC_CMD_FCNTL_RESPOND) *fcntlp = EFX_FCNTL_RESPOND; else if (fcntl == MC_CMD_FCNTL_GENERATE) *fcntlp = EFX_FCNTL_GENERATE; else if (fcntl == MC_CMD_FCNTL_BIDIR) *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE; else { EFSYS_PROBE1(mc_pcol_error, int, fcntl); *fcntlp = 0; } } void ef10_phy_link_ev( __in efx_nic_t *enp, __in efx_qword_t *eqp, __out efx_link_mode_t *link_modep) { efx_port_t *epp = &(enp->en_port); unsigned int link_flags; unsigned int speed; unsigned int fcntl; efx_link_mode_t link_mode; uint32_t lp_cap_mask; /* * Convert the LINKCHANGE speed enumeration into mbit/s, in the * same way as GET_LINK encodes the speed */ switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) { case MCDI_EVENT_LINKCHANGE_SPEED_100M: speed = 100; break; case MCDI_EVENT_LINKCHANGE_SPEED_1G: speed = 1000; break; case MCDI_EVENT_LINKCHANGE_SPEED_10G: speed = 10000; break; case MCDI_EVENT_LINKCHANGE_SPEED_40G: speed = 40000; break; default: speed = 0; break; } link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS); mcdi_phy_decode_link_mode(enp, link_flags, speed, MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL), &link_mode, &fcntl); mcdi_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP), &lp_cap_mask); /* * It's safe to update ep_lp_cap_mask without the driver's port lock * because presumably any concurrently running efx_port_poll() is * only going to arrive at the same value. * * ep_fcntl has two meanings. It's either the link common fcntl * (if the PHY supports AN), or it's the forced link state. If * the former, it's safe to update the value for the same reason as * for ep_lp_cap_mask. If the latter, then just ignore the value, * because we can race with efx_mac_fcntl_set(). */ epp->ep_lp_cap_mask = lp_cap_mask; epp->ep_fcntl = fcntl; *link_modep = link_mode; } __checkReturn efx_rc_t ef10_phy_power( __in efx_nic_t *enp, __in boolean_t power) { efx_rc_t rc; if (!power) return (0); /* Check if the PHY is a zombie */ if ((rc = ef10_phy_verify(enp)) != 0) goto fail1; enp->en_reset_flags |= EFX_RESET_PHY; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_phy_get_link( __in efx_nic_t *enp, __out ef10_link_state_t *elsp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN, MC_CMD_GET_LINK_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_LINK; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_LINK_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) { rc = EMSGSIZE; goto fail2; } mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP), &elsp->els_adv_cap_mask); mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP), &elsp->els_lp_cap_mask); mcdi_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS), MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED), MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL), &elsp->els_link_mode, &elsp->els_fcntl); #if EFSYS_OPT_LOOPBACK /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); elsp->els_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE); #endif /* EFSYS_OPT_LOOPBACK */ elsp->els_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_phy_reconfigure( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_SET_LINK_IN_LEN, MC_CMD_SET_LINK_OUT_LEN)]; uint32_t cap_mask; +#if EFSYS_OPT_PHY_LED_CONTROL unsigned int led_mode; +#endif unsigned int speed; boolean_t supported; efx_rc_t rc; if ((rc = efx_mcdi_link_control_supported(enp, &supported)) != 0) goto fail1; if (supported == B_FALSE) goto out; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_SET_LINK; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_SET_LINK_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN; cap_mask = epp->ep_adv_cap_mask; MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP, PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1, PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1, PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1, PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1, PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1, PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1, PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1, PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1, PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1, PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1); /* Too many fields for for POPULATE macros, so insert this afterwards */ MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1); #if EFSYS_OPT_LOOPBACK MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, epp->ep_loopback_type); switch (epp->ep_loopback_link_mode) { case EFX_LINK_100FDX: speed = 100; break; case EFX_LINK_1000FDX: speed = 1000; break; case EFX_LINK_10000FDX: speed = 10000; break; case EFX_LINK_40000FDX: speed = 40000; break; default: speed = 0; } #else MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE); speed = 0; #endif /* EFSYS_OPT_LOOPBACK */ MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed); #if EFSYS_OPT_PHY_FLAGS MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags); #else MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0); #endif /* EFSYS_OPT_PHY_FLAGS */ efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail2; } /* And set the blink mode */ (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_SET_ID_LED; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN; #if EFSYS_OPT_PHY_LED_CONTROL switch (epp->ep_phy_led_mode) { case EFX_PHY_LED_DEFAULT: led_mode = MC_CMD_LED_DEFAULT; break; case EFX_PHY_LED_OFF: led_mode = MC_CMD_LED_OFF; break; case EFX_PHY_LED_ON: led_mode = MC_CMD_LED_ON; break; default: EFSYS_ASSERT(0); led_mode = MC_CMD_LED_DEFAULT; } MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode); #else MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT); #endif /* EFSYS_OPT_PHY_LED_CONTROL */ efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail3; } out: return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_phy_verify( __in efx_nic_t *enp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_PHY_STATE_IN_LEN, MC_CMD_GET_PHY_STATE_OUT_LEN)]; uint32_t state; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_PHY_STATE; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) { rc = EMSGSIZE; goto fail2; } state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE); if (state != MC_CMD_PHY_STATE_OK) { if (state != MC_CMD_PHY_STATE_ZOMBIE) EFSYS_PROBE1(mc_pcol_error, int, state); rc = ENOTACTIVE; goto fail3; } return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_phy_oui_get( __in efx_nic_t *enp, __out uint32_t *ouip) { _NOTE(ARGUNUSED(enp, ouip)) return (ENOTSUP); } #if EFSYS_OPT_PHY_STATS __checkReturn efx_rc_t ef10_phy_stats_update( __in efx_nic_t *enp, __in efsys_mem_t *esmp, __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat) { /* TBD: no stats support in firmware yet */ _NOTE(ARGUNUSED(enp, esmp)) memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat)); return (0); } #endif /* EFSYS_OPT_PHY_STATS */ #if EFSYS_OPT_BIST __checkReturn efx_rc_t ef10_bist_enable_offline( __in efx_nic_t *enp) { efx_rc_t rc; if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_bist_start( __in efx_nic_t *enp, __in efx_bist_type_t type) { efx_rc_t rc; if ((rc = efx_mcdi_bist_start(enp, type)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t ef10_bist_poll( __in efx_nic_t *enp, __in efx_bist_type_t type, __out efx_bist_result_t *resultp, __out_opt __drv_when(count > 0, __notnull) uint32_t *value_maskp, __out_ecount_opt(count) __drv_when(count > 0, __notnull) unsigned long *valuesp, __in size_t count) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_POLL_BIST_IN_LEN, MCDI_CTL_SDU_LEN_MAX)]; uint32_t value_mask = 0; uint32_t result; efx_rc_t rc; _NOTE(ARGUNUSED(type)) (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_POLL_BIST; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MCDI_CTL_SDU_LEN_MAX; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) { rc = EMSGSIZE; goto fail2; } if (count > 0) (void) memset(valuesp, '\0', count * sizeof (unsigned long)); result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT); if (result == MC_CMD_POLL_BIST_FAILED && req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN && count > EFX_BIST_MEM_ECC_FATAL) { if (valuesp != NULL) { valuesp[EFX_BIST_MEM_TEST] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST); valuesp[EFX_BIST_MEM_ADDR] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR); valuesp[EFX_BIST_MEM_BUS] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS); valuesp[EFX_BIST_MEM_EXPECT] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT); valuesp[EFX_BIST_MEM_ACTUAL] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL); valuesp[EFX_BIST_MEM_ECC] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC); valuesp[EFX_BIST_MEM_ECC_PARITY] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY); valuesp[EFX_BIST_MEM_ECC_FATAL] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL); } value_mask |= (1 << EFX_BIST_MEM_TEST) | (1 << EFX_BIST_MEM_ADDR) | (1 << EFX_BIST_MEM_BUS) | (1 << EFX_BIST_MEM_EXPECT) | (1 << EFX_BIST_MEM_ACTUAL) | (1 << EFX_BIST_MEM_ECC) | (1 << EFX_BIST_MEM_ECC_PARITY) | (1 << EFX_BIST_MEM_ECC_FATAL); } else if (result == MC_CMD_POLL_BIST_FAILED && encp->enc_phy_type == EFX_PHY_XFI_FARMI && req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN && count > EFX_BIST_FAULT_CODE) { if (valuesp != NULL) valuesp[EFX_BIST_FAULT_CODE] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST); value_mask |= 1 << EFX_BIST_FAULT_CODE; } if (value_maskp != NULL) *value_maskp = value_mask; EFSYS_ASSERT(resultp != NULL); if (result == MC_CMD_POLL_BIST_RUNNING) *resultp = EFX_BIST_RESULT_RUNNING; else if (result == MC_CMD_POLL_BIST_PASSED) *resultp = EFX_BIST_RESULT_PASSED; else *resultp = EFX_BIST_RESULT_FAILED; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void ef10_bist_stop( __in efx_nic_t *enp, __in efx_bist_type_t type) { /* There is no way to stop BIST on EF10. */ _NOTE(ARGUNUSED(enp, type)) } #endif /* EFSYS_OPT_BIST */ #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ Index: stable/11/sys/dev/sfxge/common/efx_check.h =================================================================== --- stable/11/sys/dev/sfxge/common/efx_check.h (revision 342423) +++ stable/11/sys/dev/sfxge/common/efx_check.h (revision 342424) @@ -1,343 +1,343 @@ /*- * Copyright (c) 2012-2016 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 COPYRIGHT HOLDERS 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. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. * * $FreeBSD$ */ #ifndef _SYS_EFX_CHECK_H #define _SYS_EFX_CHECK_H #include "efsys.h" /* * Check that the efsys.h header in client code has a valid combination of * EFSYS_OPT_xxx options. * * NOTE: Keep checks for obsolete options here to ensure that they are removed * from client code (and do not reappear in merges from other branches). */ #ifdef EFSYS_OPT_FALCON # error "FALCON is obsolete and is not supported." #endif /* Support NVRAM based boot config */ #if EFSYS_OPT_BOOTCFG # if !EFSYS_OPT_NVRAM # error "BOOTCFG requires NVRAM" # endif #endif /* EFSYS_OPT_BOOTCFG */ /* Verify chip implements accessed registers */ #if EFSYS_OPT_CHECK_REG # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "CHECK_REG requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_CHECK_REG */ /* Decode fatal errors */ #if EFSYS_OPT_DECODE_INTR_FATAL # if !EFSYS_OPT_SIENA # error "INTR_FATAL requires SIENA" # endif #endif /* EFSYS_OPT_DECODE_INTR_FATAL */ /* Support diagnostic hardware tests */ #if EFSYS_OPT_DIAG # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "DIAG requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_DIAG */ /* Support optimized EVQ data access */ #if EFSYS_OPT_EV_PREFETCH # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "EV_PREFETCH requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_EV_PREFETCH */ #ifdef EFSYS_OPT_FALCON_NIC_CFG_OVERRIDE # error "FALCON_NIC_CFG_OVERRIDE is obsolete and is not supported." #endif /* Support hardware packet filters */ #if EFSYS_OPT_FILTER # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "FILTER requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_FILTER */ #if (EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # if !EFSYS_OPT_FILTER # error "HUNTINGTON or MEDFORD requires FILTER" # endif #endif /* EFSYS_OPT_HUNTINGTON */ /* Support hardware loopback modes */ #if EFSYS_OPT_LOOPBACK # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "LOOPBACK requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_LOOPBACK */ #ifdef EFSYS_OPT_MAC_FALCON_GMAC # error "MAC_FALCON_GMAC is obsolete and is not supported." #endif #ifdef EFSYS_OPT_MAC_FALCON_XMAC # error "MAC_FALCON_XMAC is obsolete and is not supported." #endif /* Support MAC statistics */ #if EFSYS_OPT_MAC_STATS # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "MAC_STATS requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_MAC_STATS */ /* Support management controller messages */ #if EFSYS_OPT_MCDI # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "MCDI requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_MCDI */ #if (EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # if !EFSYS_OPT_MCDI # error "SIENA or HUNTINGTON or MEDFORD requires MCDI" # endif #endif /* Support MCDI logging */ #if EFSYS_OPT_MCDI_LOGGING # if !EFSYS_OPT_MCDI # error "MCDI_LOGGING requires MCDI" # endif #endif /* EFSYS_OPT_MCDI_LOGGING */ /* Support MCDI proxy authorization */ #if EFSYS_OPT_MCDI_PROXY_AUTH # if !EFSYS_OPT_MCDI # error "MCDI_PROXY_AUTH requires MCDI" # endif #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ #ifdef EFSYS_OPT_MON_LM87 # error "MON_LM87 is obsolete and is not supported." #endif #ifdef EFSYS_OPT_MON_MAX6647 # error "MON_MAX6647 is obsolete and is not supported." #endif #ifdef EFSYS_OPT_MON_NULL # error "MON_NULL is obsolete and is not supported." #endif #ifdef EFSYS_OPT_MON_SIENA # error "MON_SIENA is obsolete (replaced by MON_MCDI)." #endif #ifdef EFSYS_OPT_MON_HUNTINGTON # error "MON_HUNTINGTON is obsolete (replaced by MON_MCDI)." #endif /* Support monitor statistics (voltage/temperature) */ #if EFSYS_OPT_MON_STATS # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "MON_STATS requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_MON_STATS */ /* Support Monitor via mcdi */ #if EFSYS_OPT_MON_MCDI # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "MON_MCDI requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_MON_MCDI*/ /* Support printable names for statistics */ #if EFSYS_OPT_NAMES # if !(EFSYS_OPT_LOOPBACK || EFSYS_OPT_MAC_STATS || EFSYS_OPT_MCDI || \ EFSYS_MON_STATS || EFSYS_OPT_PHY_STATS || EFSYS_OPT_QSTATS) # error "NAMES requires LOOPBACK or xxxSTATS or MCDI" # endif #endif /* EFSYS_OPT_NAMES */ /* Support non volatile configuration */ #if EFSYS_OPT_NVRAM # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "NVRAM requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_NVRAM */ #ifdef EFSYS_OPT_NVRAM_FALCON_BOOTROM # error "NVRAM_FALCON_BOOTROM is obsolete and is not supported." #endif #ifdef EFSYS_OPT_NVRAM_SFT9001 # error "NVRAM_SFT9001 is obsolete and is not supported." #endif #ifdef EFSYS_OPT_NVRAM_SFX7101 # error "NVRAM_SFX7101 is obsolete and is not supported." #endif #ifdef EFSYS_OPT_PCIE_TUNE # error "PCIE_TUNE is obsolete and is not supported." #endif #ifdef EFSYS_OPT_PHY_BIST # error "PHY_BIST is obsolete (replaced by BIST)." #endif /* Support PHY flags */ #if EFSYS_OPT_PHY_FLAGS # if !EFSYS_OPT_SIENA # error "PHY_FLAGS requires SIENA" # endif #endif /* EFSYS_OPT_PHY_FLAGS */ /* Support for PHY LED control */ #if EFSYS_OPT_PHY_LED_CONTROL -# if !EFSYS_OPT_SIENA -# error "PHY_LED_CONTROL requires SIENA" +# if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) +# error "PHY_LED_CONTROL requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_PHY_LED_CONTROL */ #ifdef EFSYS_OPT_PHY_NULL # error "PHY_NULL is obsolete and is not supported." #endif #ifdef EFSYS_OPT_PHY_PM8358 # error "PHY_PM8358 is obsolete and is not supported." #endif #ifdef EFSYS_OPT_PHY_PROPS # error "PHY_PROPS is obsolete and is not supported." #endif #ifdef EFSYS_OPT_PHY_QT2022C2 # error "PHY_QT2022C2 is obsolete and is not supported." #endif #ifdef EFSYS_OPT_PHY_QT2025C # error "PHY_QT2025C is obsolete and is not supported." #endif #ifdef EFSYS_OPT_PHY_SFT9001 # error "PHY_SFT9001 is obsolete and is not supported." #endif #ifdef EFSYS_OPT_PHY_SFX7101 # error "PHY_SFX7101 is obsolete and is not supported." #endif /* Support PHY statistics */ #if EFSYS_OPT_PHY_STATS # if !EFSYS_OPT_SIENA # error "PHY_STATS requires SIENA" # endif #endif /* EFSYS_OPT_PHY_STATS */ #ifdef EFSYS_OPT_PHY_TXC43128 # error "PHY_TXC43128 is obsolete and is not supported." #endif /* Support EVQ/RXQ/TXQ statistics */ #if EFSYS_OPT_QSTATS # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "QSTATS requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_QSTATS */ #ifdef EFSYS_OPT_RX_HDR_SPLIT # error "RX_HDR_SPLIT is obsolete and is not supported" #endif /* Support receive scaling (RSS) */ #if EFSYS_OPT_RX_SCALE # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "RX_SCALE requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_RX_SCALE */ /* Support receive scatter DMA */ #if EFSYS_OPT_RX_SCATTER # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "RX_SCATTER requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_RX_SCATTER */ #ifdef EFSYS_OPT_STAT_NAME # error "STAT_NAME is obsolete (replaced by NAMES)." #endif /* Support PCI Vital Product Data (VPD) */ #if EFSYS_OPT_VPD # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "VPD requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_VPD */ /* Support Wake on LAN */ #ifdef EFSYS_OPT_WOL # error "WOL is obsolete and is not supported" #endif /* EFSYS_OPT_WOL */ #ifdef EFSYS_OPT_MCAST_FILTER_LIST # error "MCAST_FILTER_LIST is obsolete and is not supported" #endif /* Support BIST */ #if EFSYS_OPT_BIST # if !(EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD) # error "BIST requires SIENA or HUNTINGTON or MEDFORD" # endif #endif /* EFSYS_OPT_BIST */ /* Support MCDI licensing API */ #if EFSYS_OPT_LICENSING # if !EFSYS_OPT_MCDI # error "LICENSING requires MCDI" # endif # if !EFSYS_HAS_UINT64 # error "LICENSING requires UINT64" # endif #endif /* EFSYS_OPT_LICENSING */ /* Support adapters with missing static config (for factory use only) */ #if EFSYS_OPT_ALLOW_UNCONFIGURED_NIC # if !EFSYS_OPT_MEDFORD # error "ALLOW_UNCONFIGURED_NIC requires MEDFORD" # endif #endif /* EFSYS_OPT_ALLOW_UNCONFIGURED_NIC */ #endif /* _SYS_EFX_CHECK_H */ Index: stable/11/sys/dev/sfxge/common/siena_nic.c =================================================================== --- stable/11/sys/dev/sfxge/common/siena_nic.c (revision 342423) +++ stable/11/sys/dev/sfxge/common/siena_nic.c (revision 342424) @@ -1,586 +1,588 @@ /*- * Copyright (c) 2009-2016 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 COPYRIGHT HOLDERS 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. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #include "mcdi_mon.h" #if EFSYS_OPT_SIENA #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM static __checkReturn efx_rc_t siena_nic_get_partn_mask( __in efx_nic_t *enp, __out unsigned int *maskp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_NVRAM_TYPES_IN_LEN, MC_CMD_NVRAM_TYPES_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_NVRAM_TYPES; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_NVRAM_TYPES_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_NVRAM_TYPES_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_NVRAM_TYPES_OUT_LEN) { rc = EMSGSIZE; goto fail2; } *maskp = MCDI_OUT_DWORD(req, NVRAM_TYPES_OUT_TYPES); return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_VPD || EFSYS_OPT_NVRAM */ static __checkReturn efx_rc_t siena_board_cfg( __in efx_nic_t *enp) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); uint8_t mac_addr[6]; efx_dword_t capabilities; uint32_t board_type; uint32_t nevq, nrxq, ntxq; efx_rc_t rc; /* External port identifier using one-based port numbering */ encp->enc_external_port = (uint8_t)enp->en_mcdi.em_emip.emi_port; /* Board configuration */ if ((rc = efx_mcdi_get_board_cfg(enp, &board_type, &capabilities, mac_addr)) != 0) goto fail1; EFX_MAC_ADDR_COPY(encp->enc_mac_addr, mac_addr); encp->enc_board_type = board_type; /* * There is no possibility to determine the number of PFs on Siena * by issuing MCDI request, and it is not an easy task to find the * value based on the board type, so 'enc_hw_pf_count' is set to 1 */ encp->enc_hw_pf_count = 1; /* Additional capabilities */ encp->enc_clk_mult = 1; if (EFX_DWORD_FIELD(capabilities, MC_CMD_CAPABILITIES_TURBO)) { enp->en_features |= EFX_FEATURE_TURBO; if (EFX_DWORD_FIELD(capabilities, MC_CMD_CAPABILITIES_TURBO_ACTIVE)) { encp->enc_clk_mult = 2; } } encp->enc_evq_timer_quantum_ns = EFX_EVQ_SIENA_TIMER_QUANTUM_NS / encp->enc_clk_mult; encp->enc_evq_timer_max_us = (encp->enc_evq_timer_quantum_ns << FRF_CZ_TC_TIMER_VAL_WIDTH) / 1000; /* When hash header insertion is enabled, Siena inserts 16 bytes */ encp->enc_rx_prefix_size = 16; /* Alignment for receive packet DMA buffers */ encp->enc_rx_buf_align_start = 1; encp->enc_rx_buf_align_end = 1; /* Alignment for WPTR updates */ encp->enc_rx_push_align = 1; encp->enc_tx_dma_desc_size_max = EFX_MASK32(FSF_AZ_TX_KER_BYTE_COUNT); /* Fragments must not span 4k boundaries. */ encp->enc_tx_dma_desc_boundary = 4096; /* Resource limits */ rc = efx_mcdi_get_resource_limits(enp, &nevq, &nrxq, &ntxq); if (rc != 0) { if (rc != ENOTSUP) goto fail2; nevq = 1024; nrxq = EFX_RXQ_LIMIT_TARGET; ntxq = EFX_TXQ_LIMIT_TARGET; } encp->enc_evq_limit = nevq; encp->enc_rxq_limit = MIN(EFX_RXQ_LIMIT_TARGET, nrxq); encp->enc_txq_limit = MIN(EFX_TXQ_LIMIT_TARGET, ntxq); encp->enc_txq_max_ndescs = 4096; encp->enc_buftbl_limit = SIENA_SRAM_ROWS - (encp->enc_txq_limit * EFX_TXQ_DC_NDESCS(EFX_TXQ_DC_SIZE)) - (encp->enc_rxq_limit * EFX_RXQ_DC_NDESCS(EFX_RXQ_DC_SIZE)); encp->enc_hw_tx_insert_vlan_enabled = B_FALSE; encp->enc_fw_assisted_tso_enabled = B_FALSE; encp->enc_fw_assisted_tso_v2_enabled = B_FALSE; encp->enc_fw_assisted_tso_v2_n_contexts = 0; encp->enc_allow_set_mac_with_installed_filters = B_TRUE; /* Siena supports two 10G ports, and 8 lanes of PCIe Gen2 */ encp->enc_required_pcie_bandwidth_mbps = 2 * 10000; encp->enc_max_pcie_link_gen = EFX_PCIE_LINK_SPEED_GEN2; encp->enc_fw_verified_nvram_update_required = B_FALSE; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn efx_rc_t siena_phy_cfg( __in efx_nic_t *enp) { +#if EFSYS_OPT_PHY_STATS efx_nic_cfg_t *encp = &(enp->en_nic_cfg); +#endif /* EFSYS_OPT_PHY_STATS */ efx_rc_t rc; /* Fill out fields in enp->en_port and enp->en_nic_cfg from MCDI */ if ((rc = efx_mcdi_get_phy_cfg(enp)) != 0) goto fail1; #if EFSYS_OPT_PHY_STATS /* Convert the MCDI statistic mask into the EFX_PHY_STAT mask */ siena_phy_decode_stats(enp, encp->enc_mcdi_phy_stat_mask, NULL, &encp->enc_phy_stat_mask, NULL); #endif /* EFSYS_OPT_PHY_STATS */ return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t siena_nic_probe( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); efx_nic_cfg_t *encp = &(enp->en_nic_cfg); siena_link_state_t sls; unsigned int mask; efx_oword_t oword; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); /* Test BIU */ if ((rc = efx_nic_biu_test(enp)) != 0) goto fail1; /* Clear the region register */ EFX_POPULATE_OWORD_4(oword, FRF_AZ_ADR_REGION0, 0, FRF_AZ_ADR_REGION1, (1 << 16), FRF_AZ_ADR_REGION2, (2 << 16), FRF_AZ_ADR_REGION3, (3 << 16)); EFX_BAR_WRITEO(enp, FR_AZ_ADR_REGION_REG, &oword); /* Read clear any assertion state */ if ((rc = efx_mcdi_read_assertion(enp)) != 0) goto fail2; /* Exit the assertion handler */ if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) goto fail3; /* Wrestle control from the BMC */ if ((rc = efx_mcdi_drv_attach(enp, B_TRUE)) != 0) goto fail4; if ((rc = siena_board_cfg(enp)) != 0) goto fail5; if ((rc = siena_phy_cfg(enp)) != 0) goto fail6; /* Obtain the default PHY advertised capabilities */ if ((rc = siena_nic_reset(enp)) != 0) goto fail7; if ((rc = siena_phy_get_link(enp, &sls)) != 0) goto fail8; epp->ep_default_adv_cap_mask = sls.sls_adv_cap_mask; epp->ep_adv_cap_mask = sls.sls_adv_cap_mask; #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM if ((rc = siena_nic_get_partn_mask(enp, &mask)) != 0) goto fail9; enp->en_u.siena.enu_partn_mask = mask; #endif #if EFSYS_OPT_MAC_STATS /* Wipe the MAC statistics */ if ((rc = efx_mcdi_mac_stats_clear(enp)) != 0) goto fail10; #endif #if EFSYS_OPT_LOOPBACK if ((rc = efx_mcdi_get_loopback_modes(enp)) != 0) goto fail11; #endif #if EFSYS_OPT_MON_STATS if ((rc = mcdi_mon_cfg_build(enp)) != 0) goto fail12; #endif encp->enc_features = enp->en_features; return (0); #if EFSYS_OPT_MON_STATS fail12: EFSYS_PROBE(fail12); #endif #if EFSYS_OPT_LOOPBACK fail11: EFSYS_PROBE(fail11); #endif #if EFSYS_OPT_MAC_STATS fail10: EFSYS_PROBE(fail10); #endif #if EFSYS_OPT_VPD || EFSYS_OPT_NVRAM fail9: EFSYS_PROBE(fail9); #endif fail8: EFSYS_PROBE(fail8); fail7: EFSYS_PROBE(fail7); fail6: EFSYS_PROBE(fail6); fail5: EFSYS_PROBE(fail5); fail4: EFSYS_PROBE(fail4); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t siena_nic_reset( __in efx_nic_t *enp) { efx_mcdi_req_t req; efx_rc_t rc; EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); /* siena_nic_reset() is called to recover from BADASSERT failures. */ if ((rc = efx_mcdi_read_assertion(enp)) != 0) goto fail1; if ((rc = efx_mcdi_exit_assertion_handler(enp)) != 0) goto fail2; /* * Bug24908: ENTITY_RESET_IN_LEN is non zero but zero may be supplied * for backwards compatibility with PORT_RESET_IN_LEN. */ EFX_STATIC_ASSERT(MC_CMD_ENTITY_RESET_OUT_LEN == 0); req.emr_cmd = MC_CMD_ENTITY_RESET; req.emr_in_buf = NULL; req.emr_in_length = 0; req.emr_out_buf = NULL; req.emr_out_length = 0; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail3; } return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (0); } static void siena_nic_rx_cfg( __in efx_nic_t *enp) { efx_oword_t oword; /* * RX_INGR_EN is always enabled on Siena, because we rely on * the RX parser to be resiliant to missing SOP/EOP. */ EFX_BAR_READO(enp, FR_AZ_RX_CFG_REG, &oword); EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_INGR_EN, 1); EFX_BAR_WRITEO(enp, FR_AZ_RX_CFG_REG, &oword); /* Disable parsing of additional 802.1Q in Q packets */ EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); EFX_SET_OWORD_FIELD(oword, FRF_CZ_RX_FILTER_ALL_VLAN_ETHERTYPES, 0); EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); } static void siena_nic_usrev_dis( __in efx_nic_t *enp) { efx_oword_t oword; EFX_POPULATE_OWORD_1(oword, FRF_CZ_USREV_DIS, 1); EFX_BAR_WRITEO(enp, FR_CZ_USR_EV_CFG, &oword); } __checkReturn efx_rc_t siena_nic_init( __in efx_nic_t *enp) { efx_rc_t rc; EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_SIENA); /* Enable reporting of some events (e.g. link change) */ if ((rc = efx_mcdi_log_ctrl(enp)) != 0) goto fail1; siena_sram_init(enp); /* Configure Siena's RX block */ siena_nic_rx_cfg(enp); /* Disable USR_EVents for now */ siena_nic_usrev_dis(enp); /* bug17057: Ensure set_link is called */ if ((rc = siena_phy_reconfigure(enp)) != 0) goto fail2; enp->en_nic_cfg.enc_mcdi_max_payload_length = MCDI_CTL_SDU_LEN_MAX_V1; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void siena_nic_fini( __in efx_nic_t *enp) { _NOTE(ARGUNUSED(enp)) } void siena_nic_unprobe( __in efx_nic_t *enp) { #if EFSYS_OPT_MON_STATS mcdi_mon_cfg_free(enp); #endif /* EFSYS_OPT_MON_STATS */ (void) efx_mcdi_drv_attach(enp, B_FALSE); } #if EFSYS_OPT_DIAG static efx_register_set_t __siena_registers[] = { { FR_AZ_ADR_REGION_REG_OFST, 0, 1 }, { FR_CZ_USR_EV_CFG_OFST, 0, 1 }, { FR_AZ_RX_CFG_REG_OFST, 0, 1 }, { FR_AZ_TX_CFG_REG_OFST, 0, 1 }, { FR_AZ_TX_RESERVED_REG_OFST, 0, 1 }, { FR_AZ_SRM_TX_DC_CFG_REG_OFST, 0, 1 }, { FR_AZ_RX_DC_CFG_REG_OFST, 0, 1 }, { FR_AZ_RX_DC_PF_WM_REG_OFST, 0, 1 }, { FR_AZ_DP_CTRL_REG_OFST, 0, 1 }, { FR_BZ_RX_RSS_TKEY_REG_OFST, 0, 1}, { FR_CZ_RX_RSS_IPV6_REG1_OFST, 0, 1}, { FR_CZ_RX_RSS_IPV6_REG2_OFST, 0, 1}, { FR_CZ_RX_RSS_IPV6_REG3_OFST, 0, 1} }; static const uint32_t __siena_register_masks[] = { 0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x000103FF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0x0003FFFF, 0x00000000, 0x7FFF0037, 0xFFFF8000, 0xFFFFFFFF, 0x03FFFFFF, 0xFFFEFE80, 0x1FFFFFFF, 0x020000FE, 0x007FFFFF, 0x001FFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000000, 0x000003FF, 0x00000000, 0x00000000, 0x00000000, 0x00000FFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000007, 0x00000000 }; static efx_register_set_t __siena_tables[] = { { FR_AZ_RX_FILTER_TBL0_OFST, FR_AZ_RX_FILTER_TBL0_STEP, FR_AZ_RX_FILTER_TBL0_ROWS }, { FR_CZ_RX_MAC_FILTER_TBL0_OFST, FR_CZ_RX_MAC_FILTER_TBL0_STEP, FR_CZ_RX_MAC_FILTER_TBL0_ROWS }, { FR_AZ_RX_DESC_PTR_TBL_OFST, FR_AZ_RX_DESC_PTR_TBL_STEP, FR_CZ_RX_DESC_PTR_TBL_ROWS }, { FR_AZ_TX_DESC_PTR_TBL_OFST, FR_AZ_TX_DESC_PTR_TBL_STEP, FR_CZ_TX_DESC_PTR_TBL_ROWS }, { FR_AZ_TIMER_TBL_OFST, FR_AZ_TIMER_TBL_STEP, FR_CZ_TIMER_TBL_ROWS }, { FR_CZ_TX_FILTER_TBL0_OFST, FR_CZ_TX_FILTER_TBL0_STEP, FR_CZ_TX_FILTER_TBL0_ROWS }, { FR_CZ_TX_MAC_FILTER_TBL0_OFST, FR_CZ_TX_MAC_FILTER_TBL0_STEP, FR_CZ_TX_MAC_FILTER_TBL0_ROWS } }; static const uint32_t __siena_table_masks[] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000003FF, 0xFFFF0FFF, 0xFFFFFFFF, 0x00000E7F, 0x00000000, 0xFFFFFFFE, 0x0FFFFFFF, 0x01800000, 0x00000000, 0xFFFFFFFE, 0x0FFFFFFF, 0x0C000000, 0x00000000, 0x3FFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000013FF, 0xFFFF07FF, 0xFFFFFFFF, 0x0000007F, 0x00000000, }; __checkReturn efx_rc_t siena_nic_register_test( __in efx_nic_t *enp) { efx_register_set_t *rsp; const uint32_t *dwordp; unsigned int nitems; unsigned int count; efx_rc_t rc; /* Fill out the register mask entries */ EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_register_masks) == EFX_ARRAY_SIZE(__siena_registers) * 4); nitems = EFX_ARRAY_SIZE(__siena_registers); dwordp = __siena_register_masks; for (count = 0; count < nitems; ++count) { rsp = __siena_registers + count; rsp->mask.eo_u32[0] = *dwordp++; rsp->mask.eo_u32[1] = *dwordp++; rsp->mask.eo_u32[2] = *dwordp++; rsp->mask.eo_u32[3] = *dwordp++; } /* Fill out the register table entries */ EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(__siena_table_masks) == EFX_ARRAY_SIZE(__siena_tables) * 4); nitems = EFX_ARRAY_SIZE(__siena_tables); dwordp = __siena_table_masks; for (count = 0; count < nitems; ++count) { rsp = __siena_tables + count; rsp->mask.eo_u32[0] = *dwordp++; rsp->mask.eo_u32[1] = *dwordp++; rsp->mask.eo_u32[2] = *dwordp++; rsp->mask.eo_u32[3] = *dwordp++; } if ((rc = efx_nic_test_registers(enp, __siena_registers, EFX_ARRAY_SIZE(__siena_registers))) != 0) goto fail1; if ((rc = efx_nic_test_tables(enp, __siena_tables, EFX_PATTERN_BYTE_ALTERNATE, EFX_ARRAY_SIZE(__siena_tables))) != 0) goto fail2; if ((rc = efx_nic_test_tables(enp, __siena_tables, EFX_PATTERN_BYTE_CHANGING, EFX_ARRAY_SIZE(__siena_tables))) != 0) goto fail3; if ((rc = efx_nic_test_tables(enp, __siena_tables, EFX_PATTERN_BIT_SWEEP, EFX_ARRAY_SIZE(__siena_tables))) != 0) goto fail4; return (0); fail4: EFSYS_PROBE(fail4); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } #endif /* EFSYS_OPT_DIAG */ #endif /* EFSYS_OPT_SIENA */ Index: stable/11/sys/dev/sfxge/common/siena_phy.c =================================================================== --- stable/11/sys/dev/sfxge/common/siena_phy.c (revision 342423) +++ stable/11/sys/dev/sfxge/common/siena_phy.c (revision 342424) @@ -1,800 +1,802 @@ /*- * Copyright (c) 2009-2016 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 COPYRIGHT HOLDERS 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. * * The views and conclusions contained in the software and documentation are * those of the authors and should not be interpreted as representing official * policies, either expressed or implied, of the FreeBSD Project. */ #include __FBSDID("$FreeBSD$"); #include "efx.h" #include "efx_impl.h" #if EFSYS_OPT_SIENA static void siena_phy_decode_cap( __in uint32_t mcdi_cap, __out uint32_t *maskp) { uint32_t mask; mask = 0; if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) mask |= (1 << EFX_PHY_CAP_10HDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) mask |= (1 << EFX_PHY_CAP_10FDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) mask |= (1 << EFX_PHY_CAP_100HDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) mask |= (1 << EFX_PHY_CAP_100FDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) mask |= (1 << EFX_PHY_CAP_1000HDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) mask |= (1 << EFX_PHY_CAP_1000FDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) mask |= (1 << EFX_PHY_CAP_10000FDX); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) mask |= (1 << EFX_PHY_CAP_PAUSE); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) mask |= (1 << EFX_PHY_CAP_ASYM); if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) mask |= (1 << EFX_PHY_CAP_AN); *maskp = mask; } static void siena_phy_decode_link_mode( __in efx_nic_t *enp, __in uint32_t link_flags, __in unsigned int speed, __in unsigned int fcntl, __out efx_link_mode_t *link_modep, __out unsigned int *fcntlp) { boolean_t fd = !!(link_flags & (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN)); boolean_t up = !!(link_flags & (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN)); _NOTE(ARGUNUSED(enp)) if (!up) *link_modep = EFX_LINK_DOWN; else if (speed == 10000 && fd) *link_modep = EFX_LINK_10000FDX; else if (speed == 1000) *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX; else if (speed == 100) *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX; else if (speed == 10) *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX; else *link_modep = EFX_LINK_UNKNOWN; if (fcntl == MC_CMD_FCNTL_OFF) *fcntlp = 0; else if (fcntl == MC_CMD_FCNTL_RESPOND) *fcntlp = EFX_FCNTL_RESPOND; else if (fcntl == MC_CMD_FCNTL_BIDIR) *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE; else { EFSYS_PROBE1(mc_pcol_error, int, fcntl); *fcntlp = 0; } } void siena_phy_link_ev( __in efx_nic_t *enp, __in efx_qword_t *eqp, __out efx_link_mode_t *link_modep) { efx_port_t *epp = &(enp->en_port); unsigned int link_flags; unsigned int speed; unsigned int fcntl; efx_link_mode_t link_mode; uint32_t lp_cap_mask; /* * Convert the LINKCHANGE speed enumeration into mbit/s, in the * same way as GET_LINK encodes the speed */ switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) { case MCDI_EVENT_LINKCHANGE_SPEED_100M: speed = 100; break; case MCDI_EVENT_LINKCHANGE_SPEED_1G: speed = 1000; break; case MCDI_EVENT_LINKCHANGE_SPEED_10G: speed = 10000; break; default: speed = 0; break; } link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS); siena_phy_decode_link_mode(enp, link_flags, speed, MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL), &link_mode, &fcntl); siena_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP), &lp_cap_mask); /* * It's safe to update ep_lp_cap_mask without the driver's port lock * because presumably any concurrently running efx_port_poll() is * only going to arrive at the same value. * * ep_fcntl has two meanings. It's either the link common fcntl * (if the PHY supports AN), or it's the forced link state. If * the former, it's safe to update the value for the same reason as * for ep_lp_cap_mask. If the latter, then just ignore the value, * because we can race with efx_mac_fcntl_set(). */ epp->ep_lp_cap_mask = lp_cap_mask; if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN)) epp->ep_fcntl = fcntl; *link_modep = link_mode; } __checkReturn efx_rc_t siena_phy_power( __in efx_nic_t *enp, __in boolean_t power) { efx_rc_t rc; if (!power) return (0); /* Check if the PHY is a zombie */ if ((rc = siena_phy_verify(enp)) != 0) goto fail1; enp->en_reset_flags |= EFX_RESET_PHY; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t siena_phy_get_link( __in efx_nic_t *enp, __out siena_link_state_t *slsp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN, MC_CMD_GET_LINK_OUT_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_LINK; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_LINK_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) { rc = EMSGSIZE; goto fail2; } siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP), &slsp->sls_adv_cap_mask); siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP), &slsp->sls_lp_cap_mask); siena_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS), MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED), MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL), &slsp->sls_link_mode, &slsp->sls_fcntl); #if EFSYS_OPT_LOOPBACK /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); slsp->sls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE); #endif /* EFSYS_OPT_LOOPBACK */ slsp->sls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t siena_phy_reconfigure( __in efx_nic_t *enp) { efx_port_t *epp = &(enp->en_port); efx_mcdi_req_t req; uint8_t payload[MAX(MAX(MC_CMD_SET_ID_LED_IN_LEN, MC_CMD_SET_ID_LED_OUT_LEN), MAX(MC_CMD_SET_LINK_IN_LEN, MC_CMD_SET_LINK_OUT_LEN))]; uint32_t cap_mask; +#if EFSYS_OPT_PHY_LED_CONTROL unsigned int led_mode; +#endif unsigned int speed; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_SET_LINK; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_SET_LINK_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN; cap_mask = epp->ep_adv_cap_mask; MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP, PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1, PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1, PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1, PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1, PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1, PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1, PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1, PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1, PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1, PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1); #if EFSYS_OPT_LOOPBACK MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, epp->ep_loopback_type); switch (epp->ep_loopback_link_mode) { case EFX_LINK_100FDX: speed = 100; break; case EFX_LINK_1000FDX: speed = 1000; break; case EFX_LINK_10000FDX: speed = 10000; break; default: speed = 0; } #else MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE); speed = 0; #endif /* EFSYS_OPT_LOOPBACK */ MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed); #if EFSYS_OPT_PHY_FLAGS MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags); #else MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0); #endif /* EFSYS_OPT_PHY_FLAGS */ efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } /* And set the blink mode */ (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_SET_ID_LED; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN; #if EFSYS_OPT_PHY_LED_CONTROL switch (epp->ep_phy_led_mode) { case EFX_PHY_LED_DEFAULT: led_mode = MC_CMD_LED_DEFAULT; break; case EFX_PHY_LED_OFF: led_mode = MC_CMD_LED_OFF; break; case EFX_PHY_LED_ON: led_mode = MC_CMD_LED_ON; break; default: EFSYS_ASSERT(0); led_mode = MC_CMD_LED_DEFAULT; } MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode); #else MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT); #endif /* EFSYS_OPT_PHY_LED_CONTROL */ efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail2; } return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t siena_phy_verify( __in efx_nic_t *enp) { efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_GET_PHY_STATE_IN_LEN, MC_CMD_GET_PHY_STATE_OUT_LEN)]; uint32_t state; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_GET_PHY_STATE; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) { rc = EMSGSIZE; goto fail2; } state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE); if (state != MC_CMD_PHY_STATE_OK) { if (state != MC_CMD_PHY_STATE_ZOMBIE) EFSYS_PROBE1(mc_pcol_error, int, state); rc = ENOTACTIVE; goto fail3; } return (0); fail3: EFSYS_PROBE(fail3); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } __checkReturn efx_rc_t siena_phy_oui_get( __in efx_nic_t *enp, __out uint32_t *ouip) { _NOTE(ARGUNUSED(enp, ouip)) return (ENOTSUP); } #if EFSYS_OPT_PHY_STATS #define SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat, \ _mc_record, _efx_record) \ if ((_vmask) & (1ULL << (_mc_record))) { \ (_smask) |= (1ULL << (_efx_record)); \ if ((_stat) != NULL && !EFSYS_MEM_IS_NULL(_esmp)) { \ efx_dword_t dword; \ EFSYS_MEM_READD(_esmp, (_mc_record) * 4, &dword);\ (_stat)[_efx_record] = \ EFX_DWORD_FIELD(dword, EFX_DWORD_0); \ } \ } #define SIENA_SIMPLE_STAT_SET2(_vmask, _esmp, _smask, _stat, _record) \ SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat, \ MC_CMD_ ## _record, \ EFX_PHY_STAT_ ## _record) void siena_phy_decode_stats( __in efx_nic_t *enp, __in uint32_t vmask, __in_opt efsys_mem_t *esmp, __out_opt uint64_t *smaskp, __inout_ecount_opt(EFX_PHY_NSTATS) uint32_t *stat) { uint64_t smask = 0; _NOTE(ARGUNUSED(enp)) SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, OUI); SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_LINK_UP); SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_RX_FAULT); SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_TX_FAULT); if (vmask & (1 << MC_CMD_PMA_PMD_SIGNAL)) { smask |= ((1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_A) | (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_B) | (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_C) | (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_D)); if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) { efx_dword_t dword; uint32_t sig; EFSYS_MEM_READD(esmp, 4 * MC_CMD_PMA_PMD_SIGNAL, &dword); sig = EFX_DWORD_FIELD(dword, EFX_DWORD_0); stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_A] = (sig >> 1) & 1; stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_B] = (sig >> 2) & 1; stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_C] = (sig >> 3) & 1; stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_D] = (sig >> 4) & 1; } } SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_A, EFX_PHY_STAT_SNR_A); SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_B, EFX_PHY_STAT_SNR_B); SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_C, EFX_PHY_STAT_SNR_C); SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_D, EFX_PHY_STAT_SNR_D); SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_LINK_UP); SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_RX_FAULT); SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_TX_FAULT); SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BER); SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BLOCK_ERRORS); SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_LINK_UP, EFX_PHY_STAT_PHY_XS_LINK_UP); SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_RX_FAULT, EFX_PHY_STAT_PHY_XS_RX_FAULT); SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_TX_FAULT, EFX_PHY_STAT_PHY_XS_TX_FAULT); SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_ALIGN, EFX_PHY_STAT_PHY_XS_ALIGN); if (vmask & (1 << MC_CMD_PHYXS_SYNC)) { smask |= ((1 << EFX_PHY_STAT_PHY_XS_SYNC_A) | (1 << EFX_PHY_STAT_PHY_XS_SYNC_B) | (1 << EFX_PHY_STAT_PHY_XS_SYNC_C) | (1 << EFX_PHY_STAT_PHY_XS_SYNC_D)); if (stat != NULL && !EFSYS_MEM_IS_NULL(esmp)) { efx_dword_t dword; uint32_t sync; EFSYS_MEM_READD(esmp, 4 * MC_CMD_PHYXS_SYNC, &dword); sync = EFX_DWORD_FIELD(dword, EFX_DWORD_0); stat[EFX_PHY_STAT_PHY_XS_SYNC_A] = (sync >> 0) & 1; stat[EFX_PHY_STAT_PHY_XS_SYNC_B] = (sync >> 1) & 1; stat[EFX_PHY_STAT_PHY_XS_SYNC_C] = (sync >> 2) & 1; stat[EFX_PHY_STAT_PHY_XS_SYNC_D] = (sync >> 3) & 1; } } SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_LINK_UP); SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_COMPLETE); SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_CL22_LINK_UP, EFX_PHY_STAT_CL22EXT_LINK_UP); if (smaskp != NULL) *smaskp = smask; } __checkReturn efx_rc_t siena_phy_stats_update( __in efx_nic_t *enp, __in efsys_mem_t *esmp, __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); uint32_t vmask = encp->enc_mcdi_phy_stat_mask; uint64_t smask; efx_mcdi_req_t req; uint8_t payload[MAX(MC_CMD_PHY_STATS_IN_LEN, MC_CMD_PHY_STATS_OUT_DMA_LEN)]; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_PHY_STATS; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_PHY_STATS_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MC_CMD_PHY_STATS_OUT_DMA_LEN; MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_LO, EFSYS_MEM_ADDR(esmp) & 0xffffffff); MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_HI, EFSYS_MEM_ADDR(esmp) >> 32); efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } EFSYS_ASSERT3U(req.emr_out_length, ==, MC_CMD_PHY_STATS_OUT_DMA_LEN); siena_phy_decode_stats(enp, vmask, esmp, &smask, stat); EFSYS_ASSERT(smask == encp->enc_phy_stat_mask); return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (0); } #endif /* EFSYS_OPT_PHY_STATS */ #if EFSYS_OPT_BIST __checkReturn efx_rc_t siena_phy_bist_start( __in efx_nic_t *enp, __in efx_bist_type_t type) { efx_rc_t rc; if ((rc = efx_mcdi_bist_start(enp, type)) != 0) goto fail1; return (0); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } static __checkReturn unsigned long siena_phy_sft9001_bist_status( __in uint16_t code) { switch (code) { case MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY: return (EFX_PHY_CABLE_STATUS_BUSY); case MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT: return (EFX_PHY_CABLE_STATUS_INTERPAIRSHORT); case MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT: return (EFX_PHY_CABLE_STATUS_INTRAPAIRSHORT); case MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN: return (EFX_PHY_CABLE_STATUS_OPEN); case MC_CMD_POLL_BIST_SFT9001_PAIR_OK: return (EFX_PHY_CABLE_STATUS_OK); default: return (EFX_PHY_CABLE_STATUS_INVALID); } } __checkReturn efx_rc_t siena_phy_bist_poll( __in efx_nic_t *enp, __in efx_bist_type_t type, __out efx_bist_result_t *resultp, __out_opt __drv_when(count > 0, __notnull) uint32_t *value_maskp, __out_ecount_opt(count) __drv_when(count > 0, __notnull) unsigned long *valuesp, __in size_t count) { efx_nic_cfg_t *encp = &(enp->en_nic_cfg); uint8_t payload[MAX(MC_CMD_POLL_BIST_IN_LEN, MCDI_CTL_SDU_LEN_MAX)]; uint32_t value_mask = 0; efx_mcdi_req_t req; uint32_t result; efx_rc_t rc; (void) memset(payload, 0, sizeof (payload)); req.emr_cmd = MC_CMD_POLL_BIST; req.emr_in_buf = payload; req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN; req.emr_out_buf = payload; req.emr_out_length = MCDI_CTL_SDU_LEN_MAX; efx_mcdi_execute(enp, &req); if (req.emr_rc != 0) { rc = req.emr_rc; goto fail1; } if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) { rc = EMSGSIZE; goto fail2; } if (count > 0) (void) memset(valuesp, '\0', count * sizeof (unsigned long)); result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT); /* Extract PHY specific results */ if (result == MC_CMD_POLL_BIST_PASSED && encp->enc_phy_type == EFX_PHY_SFT9001B && req.emr_out_length_used >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN && (type == EFX_BIST_TYPE_PHY_CABLE_SHORT || type == EFX_BIST_TYPE_PHY_CABLE_LONG)) { uint16_t word; if (count > EFX_BIST_PHY_CABLE_LENGTH_A) { if (valuesp != NULL) valuesp[EFX_BIST_PHY_CABLE_LENGTH_A] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A); value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_A); } if (count > EFX_BIST_PHY_CABLE_LENGTH_B) { if (valuesp != NULL) valuesp[EFX_BIST_PHY_CABLE_LENGTH_B] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B); value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_B); } if (count > EFX_BIST_PHY_CABLE_LENGTH_C) { if (valuesp != NULL) valuesp[EFX_BIST_PHY_CABLE_LENGTH_C] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C); value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_C); } if (count > EFX_BIST_PHY_CABLE_LENGTH_D) { if (valuesp != NULL) valuesp[EFX_BIST_PHY_CABLE_LENGTH_D] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D); value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_D); } if (count > EFX_BIST_PHY_CABLE_STATUS_A) { if (valuesp != NULL) { word = MCDI_OUT_WORD(req, POLL_BIST_OUT_SFT9001_CABLE_STATUS_A); valuesp[EFX_BIST_PHY_CABLE_STATUS_A] = siena_phy_sft9001_bist_status(word); } value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_A); } if (count > EFX_BIST_PHY_CABLE_STATUS_B) { if (valuesp != NULL) { word = MCDI_OUT_WORD(req, POLL_BIST_OUT_SFT9001_CABLE_STATUS_B); valuesp[EFX_BIST_PHY_CABLE_STATUS_B] = siena_phy_sft9001_bist_status(word); } value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_B); } if (count > EFX_BIST_PHY_CABLE_STATUS_C) { if (valuesp != NULL) { word = MCDI_OUT_WORD(req, POLL_BIST_OUT_SFT9001_CABLE_STATUS_C); valuesp[EFX_BIST_PHY_CABLE_STATUS_C] = siena_phy_sft9001_bist_status(word); } value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_C); } if (count > EFX_BIST_PHY_CABLE_STATUS_D) { if (valuesp != NULL) { word = MCDI_OUT_WORD(req, POLL_BIST_OUT_SFT9001_CABLE_STATUS_D); valuesp[EFX_BIST_PHY_CABLE_STATUS_D] = siena_phy_sft9001_bist_status(word); } value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_D); } } else if (result == MC_CMD_POLL_BIST_FAILED && encp->enc_phy_type == EFX_PHY_QLX111V && req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN && count > EFX_BIST_FAULT_CODE) { if (valuesp != NULL) valuesp[EFX_BIST_FAULT_CODE] = MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST); value_mask |= 1 << EFX_BIST_FAULT_CODE; } if (value_maskp != NULL) *value_maskp = value_mask; EFSYS_ASSERT(resultp != NULL); if (result == MC_CMD_POLL_BIST_RUNNING) *resultp = EFX_BIST_RESULT_RUNNING; else if (result == MC_CMD_POLL_BIST_PASSED) *resultp = EFX_BIST_RESULT_PASSED; else *resultp = EFX_BIST_RESULT_FAILED; return (0); fail2: EFSYS_PROBE(fail2); fail1: EFSYS_PROBE1(fail1, efx_rc_t, rc); return (rc); } void siena_phy_bist_stop( __in efx_nic_t *enp, __in efx_bist_type_t type) { /* There is no way to stop BIST on Siena */ _NOTE(ARGUNUSED(enp, type)) } #endif /* EFSYS_OPT_BIST */ #endif /* EFSYS_OPT_SIENA */ Index: stable/11 =================================================================== --- stable/11 (revision 342423) +++ stable/11 (revision 342424) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r340875