1227569Sphilip/*- 2227569Sphilip * Copyright 2009 Solarflare Communications Inc. All rights reserved. 3227569Sphilip * 4227569Sphilip * Redistribution and use in source and binary forms, with or without 5227569Sphilip * modification, are permitted provided that the following conditions 6227569Sphilip * are met: 7227569Sphilip * 1. Redistributions of source code must retain the above copyright 8227569Sphilip * notice, this list of conditions and the following disclaimer. 9227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright 10227569Sphilip * notice, this list of conditions and the following disclaimer in the 11227569Sphilip * documentation and/or other materials provided with the distribution. 12227569Sphilip * 13227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND 14227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16227569Sphilip * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23227569Sphilip * SUCH DAMAGE. 24227569Sphilip */ 25228078Sphilip 26228078Sphilip#include <sys/cdefs.h> 27228078Sphilip__FBSDID("$FreeBSD$"); 28228078Sphilip 29227569Sphilip#include "efsys.h" 30227569Sphilip#include "efx.h" 31227569Sphilip#include "efx_impl.h" 32227569Sphilip 33227569Sphilip#if EFSYS_OPT_SIENA 34227569Sphilip 35227569Sphilipstatic void 36227569Sphilipsiena_phy_decode_cap( 37227569Sphilip __in uint32_t mcdi_cap, 38227569Sphilip __out uint32_t *maskp) 39227569Sphilip{ 40227569Sphilip uint32_t mask; 41227569Sphilip 42227569Sphilip mask = 0; 43227569Sphilip if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) 44227569Sphilip mask |= (1 << EFX_PHY_CAP_10HDX); 45227569Sphilip if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) 46227569Sphilip mask |= (1 << EFX_PHY_CAP_10FDX); 47227569Sphilip if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) 48227569Sphilip mask |= (1 << EFX_PHY_CAP_100HDX); 49227569Sphilip if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) 50227569Sphilip mask |= (1 << EFX_PHY_CAP_100FDX); 51227569Sphilip if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) 52227569Sphilip mask |= (1 << EFX_PHY_CAP_1000HDX); 53227569Sphilip if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) 54227569Sphilip mask |= (1 << EFX_PHY_CAP_1000FDX); 55227569Sphilip if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) 56227569Sphilip mask |= (1 << EFX_PHY_CAP_10000FDX); 57227569Sphilip if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) 58227569Sphilip mask |= (1 << EFX_PHY_CAP_PAUSE); 59227569Sphilip if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) 60227569Sphilip mask |= (1 << EFX_PHY_CAP_ASYM); 61227569Sphilip if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) 62227569Sphilip mask |= (1 << EFX_PHY_CAP_AN); 63227569Sphilip 64227569Sphilip *maskp = mask; 65227569Sphilip} 66227569Sphilip 67227569Sphilipstatic void 68227569Sphilipsiena_phy_decode_link_mode( 69227569Sphilip __in efx_nic_t *enp, 70227569Sphilip __in uint32_t link_flags, 71227569Sphilip __in unsigned int speed, 72227569Sphilip __in unsigned int fcntl, 73227569Sphilip __out efx_link_mode_t *link_modep, 74227569Sphilip __out unsigned int *fcntlp) 75227569Sphilip{ 76227569Sphilip boolean_t fd = !!(link_flags & 77227569Sphilip (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN)); 78227569Sphilip boolean_t up = !!(link_flags & 79227569Sphilip (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN)); 80227569Sphilip 81227569Sphilip _NOTE(ARGUNUSED(enp)) 82227569Sphilip 83227569Sphilip if (!up) 84227569Sphilip *link_modep = EFX_LINK_DOWN; 85227569Sphilip else if (speed == 10000 && fd) 86227569Sphilip *link_modep = EFX_LINK_10000FDX; 87227569Sphilip else if (speed == 1000) 88227569Sphilip *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX; 89227569Sphilip else if (speed == 100) 90227569Sphilip *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX; 91227569Sphilip else if (speed == 10) 92227569Sphilip *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX; 93227569Sphilip else 94227569Sphilip *link_modep = EFX_LINK_UNKNOWN; 95227569Sphilip 96227569Sphilip if (fcntl == MC_CMD_FCNTL_OFF) 97227569Sphilip *fcntlp = 0; 98227569Sphilip else if (fcntl == MC_CMD_FCNTL_RESPOND) 99227569Sphilip *fcntlp = EFX_FCNTL_RESPOND; 100227569Sphilip else if (fcntl == MC_CMD_FCNTL_BIDIR) 101227569Sphilip *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE; 102227569Sphilip else { 103227569Sphilip EFSYS_PROBE1(mc_pcol_error, int, fcntl); 104227569Sphilip *fcntlp = 0; 105227569Sphilip } 106227569Sphilip} 107227569Sphilip 108227569Sphilip void 109227569Sphilipsiena_phy_link_ev( 110227569Sphilip __in efx_nic_t *enp, 111227569Sphilip __in efx_qword_t *eqp, 112227569Sphilip __out efx_link_mode_t *link_modep) 113227569Sphilip{ 114227569Sphilip efx_port_t *epp = &(enp->en_port); 115227569Sphilip unsigned int link_flags; 116227569Sphilip unsigned int speed; 117227569Sphilip unsigned int fcntl; 118227569Sphilip efx_link_mode_t link_mode; 119227569Sphilip uint32_t lp_cap_mask; 120227569Sphilip 121227569Sphilip /* 122227569Sphilip * Convert the LINKCHANGE speed enumeration into mbit/s, in the 123227569Sphilip * same way as GET_LINK encodes the speed 124227569Sphilip */ 125227569Sphilip switch (MCDI_EV_FIELD(*eqp, LINKCHANGE_SPEED)) { 126227569Sphilip case MCDI_EVENT_LINKCHANGE_SPEED_100M: 127227569Sphilip speed = 100; 128227569Sphilip break; 129227569Sphilip case MCDI_EVENT_LINKCHANGE_SPEED_1G: 130227569Sphilip speed = 1000; 131227569Sphilip break; 132227569Sphilip case MCDI_EVENT_LINKCHANGE_SPEED_10G: 133227569Sphilip speed = 10000; 134227569Sphilip break; 135227569Sphilip default: 136227569Sphilip speed = 0; 137227569Sphilip break; 138227569Sphilip } 139227569Sphilip 140227569Sphilip link_flags = MCDI_EV_FIELD(*eqp, LINKCHANGE_LINK_FLAGS); 141227569Sphilip siena_phy_decode_link_mode(enp, link_flags, speed, 142227569Sphilip MCDI_EV_FIELD(*eqp, LINKCHANGE_FCNTL), 143227569Sphilip &link_mode, &fcntl); 144227569Sphilip siena_phy_decode_cap(MCDI_EV_FIELD(*eqp, LINKCHANGE_LP_CAP), 145227569Sphilip &lp_cap_mask); 146227569Sphilip 147227569Sphilip /* 148227569Sphilip * It's safe to update ep_lp_cap_mask without the driver's port lock 149227569Sphilip * because presumably any concurrently running efx_port_poll() is 150227569Sphilip * only going to arrive at the same value. 151227569Sphilip * 152227569Sphilip * ep_fcntl has two meanings. It's either the link common fcntl 153227569Sphilip * (if the PHY supports AN), or it's the forced link state. If 154227569Sphilip * the former, it's safe to update the value for the same reason as 155227569Sphilip * for ep_lp_cap_mask. If the latter, then just ignore the value, 156227569Sphilip * because we can race with efx_mac_fcntl_set(). 157227569Sphilip */ 158227569Sphilip epp->ep_lp_cap_mask = lp_cap_mask; 159227569Sphilip if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN)) 160227569Sphilip epp->ep_fcntl = fcntl; 161227569Sphilip 162227569Sphilip *link_modep = link_mode; 163227569Sphilip} 164227569Sphilip 165227569Sphilip __checkReturn int 166227569Sphilipsiena_phy_power( 167227569Sphilip __in efx_nic_t *enp, 168227569Sphilip __in boolean_t power) 169227569Sphilip{ 170227569Sphilip int rc; 171227569Sphilip 172227569Sphilip if (!power) 173227569Sphilip return (0); 174227569Sphilip 175227569Sphilip /* Check if the PHY is a zombie */ 176227569Sphilip if ((rc = siena_phy_verify(enp)) != 0) 177227569Sphilip goto fail1; 178227569Sphilip 179227569Sphilip enp->en_reset_flags |= EFX_RESET_PHY; 180227569Sphilip 181227569Sphilip return (0); 182227569Sphilip 183227569Sphilipfail1: 184227569Sphilip EFSYS_PROBE1(fail1, int, rc); 185227569Sphilip 186227569Sphilip return (rc); 187227569Sphilip} 188227569Sphilip 189227569Sphilip __checkReturn int 190227569Sphilipsiena_phy_get_link( 191227569Sphilip __in efx_nic_t *enp, 192227569Sphilip __out siena_link_state_t *slsp) 193227569Sphilip{ 194227569Sphilip efx_mcdi_req_t req; 195227569Sphilip uint8_t outbuf[MC_CMD_GET_LINK_OUT_LEN]; 196227569Sphilip int rc; 197227569Sphilip 198227569Sphilip req.emr_cmd = MC_CMD_GET_LINK; 199227569Sphilip EFX_STATIC_ASSERT(MC_CMD_GET_LINK_IN_LEN == 0); 200227569Sphilip req.emr_in_buf = NULL; 201227569Sphilip req.emr_in_length = 0; 202227569Sphilip req.emr_out_buf = outbuf; 203227569Sphilip req.emr_out_length = sizeof (outbuf); 204227569Sphilip 205227569Sphilip efx_mcdi_execute(enp, &req); 206227569Sphilip 207227569Sphilip if (req.emr_rc != 0) { 208227569Sphilip rc = req.emr_rc; 209227569Sphilip goto fail1; 210227569Sphilip } 211227569Sphilip 212227569Sphilip if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) { 213227569Sphilip rc = EMSGSIZE; 214227569Sphilip goto fail2; 215227569Sphilip } 216227569Sphilip 217227569Sphilip siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP), 218227569Sphilip &slsp->sls_adv_cap_mask); 219227569Sphilip siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP), 220227569Sphilip &slsp->sls_lp_cap_mask); 221227569Sphilip 222227569Sphilip siena_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS), 223227569Sphilip MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED), 224227569Sphilip MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL), 225227569Sphilip &slsp->sls_link_mode, &slsp->sls_fcntl); 226227569Sphilip 227227569Sphilip#if EFSYS_OPT_LOOPBACK 228227569Sphilip /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ 229227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); 230227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); 231227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); 232227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); 233227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); 234227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); 235227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); 236227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); 237227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); 238227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); 239227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); 240227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); 241227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); 242227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); 243227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); 244227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); 245227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); 246227569Sphilip EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); 247227569Sphilip 248227569Sphilip slsp->sls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE); 249227569Sphilip#endif /* EFSYS_OPT_LOOPBACK */ 250227569Sphilip 251227569Sphilip slsp->sls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0; 252227569Sphilip 253227569Sphilip return (0); 254227569Sphilip 255227569Sphilipfail2: 256227569Sphilip EFSYS_PROBE(fail2); 257227569Sphilipfail1: 258227569Sphilip EFSYS_PROBE1(fail1, int, rc); 259227569Sphilip 260227569Sphilip return (rc); 261227569Sphilip} 262227569Sphilip 263227569Sphilip __checkReturn int 264227569Sphilipsiena_phy_reconfigure( 265227569Sphilip __in efx_nic_t *enp) 266227569Sphilip{ 267227569Sphilip efx_port_t *epp = &(enp->en_port); 268227569Sphilip efx_mcdi_req_t req; 269227569Sphilip uint8_t payload[MAX(MC_CMD_SET_ID_LED_IN_LEN, 270227569Sphilip MC_CMD_SET_LINK_IN_LEN)]; 271227569Sphilip uint32_t cap_mask; 272227569Sphilip unsigned int led_mode; 273227569Sphilip unsigned int speed; 274227569Sphilip int rc; 275227569Sphilip 276227569Sphilip req.emr_cmd = MC_CMD_SET_LINK; 277227569Sphilip req.emr_in_buf = payload; 278227569Sphilip req.emr_in_length = MC_CMD_SET_LINK_IN_LEN; 279227569Sphilip EFX_STATIC_ASSERT(MC_CMD_SET_LINK_OUT_LEN == 0); 280227569Sphilip req.emr_out_buf = NULL; 281227569Sphilip req.emr_out_length = 0; 282227569Sphilip 283227569Sphilip cap_mask = epp->ep_adv_cap_mask; 284227569Sphilip MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP, 285227569Sphilip PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1, 286227569Sphilip PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1, 287227569Sphilip PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1, 288227569Sphilip PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1, 289227569Sphilip PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1, 290227569Sphilip PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1, 291227569Sphilip PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1, 292227569Sphilip PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1, 293227569Sphilip PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1, 294227569Sphilip PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1); 295227569Sphilip 296227569Sphilip#if EFSYS_OPT_LOOPBACK 297227569Sphilip MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, 298227569Sphilip epp->ep_loopback_type); 299227569Sphilip switch (epp->ep_loopback_link_mode) { 300227569Sphilip case EFX_LINK_100FDX: 301227569Sphilip speed = 100; 302227569Sphilip break; 303227569Sphilip case EFX_LINK_1000FDX: 304227569Sphilip speed = 1000; 305227569Sphilip break; 306227569Sphilip case EFX_LINK_10000FDX: 307227569Sphilip speed = 10000; 308227569Sphilip break; 309227569Sphilip default: 310227569Sphilip speed = 0; 311227569Sphilip } 312227569Sphilip#else 313227569Sphilip MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE); 314227569Sphilip speed = 0; 315227569Sphilip#endif /* EFSYS_OPT_LOOPBACK */ 316227569Sphilip MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed); 317227569Sphilip 318227569Sphilip#if EFSYS_OPT_PHY_FLAGS 319227569Sphilip MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags); 320227569Sphilip#else 321227569Sphilip MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0); 322227569Sphilip#endif /* EFSYS_OPT_PHY_FLAGS */ 323227569Sphilip 324227569Sphilip efx_mcdi_execute(enp, &req); 325227569Sphilip 326227569Sphilip if (req.emr_rc != 0) { 327227569Sphilip rc = req.emr_rc; 328227569Sphilip goto fail1; 329227569Sphilip } 330227569Sphilip 331227569Sphilip /* And set the blink mode */ 332227569Sphilip req.emr_cmd = MC_CMD_SET_ID_LED; 333227569Sphilip req.emr_in_buf = payload; 334227569Sphilip req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN; 335227569Sphilip EFX_STATIC_ASSERT(MC_CMD_SET_ID_LED_OUT_LEN == 0); 336227569Sphilip req.emr_out_buf = NULL; 337227569Sphilip req.emr_out_length = 0; 338227569Sphilip 339227569Sphilip#if EFSYS_OPT_PHY_LED_CONTROL 340227569Sphilip switch (epp->ep_phy_led_mode) { 341227569Sphilip case EFX_PHY_LED_DEFAULT: 342227569Sphilip led_mode = MC_CMD_LED_DEFAULT; 343227569Sphilip break; 344227569Sphilip case EFX_PHY_LED_OFF: 345227569Sphilip led_mode = MC_CMD_LED_OFF; 346227569Sphilip break; 347227569Sphilip case EFX_PHY_LED_ON: 348227569Sphilip led_mode = MC_CMD_LED_ON; 349227569Sphilip break; 350227569Sphilip default: 351227569Sphilip EFSYS_ASSERT(0); 352227569Sphilip led_mode = MC_CMD_LED_DEFAULT; 353227569Sphilip } 354227569Sphilip 355227569Sphilip MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode); 356227569Sphilip#else 357227569Sphilip MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT); 358227569Sphilip#endif /* EFSYS_OPT_PHY_LED_CONTROL */ 359227569Sphilip 360227569Sphilip efx_mcdi_execute(enp, &req); 361227569Sphilip 362227569Sphilip if (req.emr_rc != 0) { 363227569Sphilip rc = req.emr_rc; 364227569Sphilip goto fail2; 365227569Sphilip } 366227569Sphilip 367227569Sphilip return (0); 368227569Sphilip 369227569Sphilipfail2: 370227569Sphilip EFSYS_PROBE(fail2); 371227569Sphilipfail1: 372227569Sphilip EFSYS_PROBE1(fail1, int, rc); 373227569Sphilip 374227569Sphilip return (rc); 375227569Sphilip} 376227569Sphilip 377227569Sphilip __checkReturn int 378227569Sphilipsiena_phy_verify( 379227569Sphilip __in efx_nic_t *enp) 380227569Sphilip{ 381227569Sphilip efx_mcdi_req_t req; 382227569Sphilip uint8_t outbuf[MC_CMD_GET_PHY_STATE_OUT_LEN]; 383227569Sphilip uint32_t state; 384227569Sphilip int rc; 385227569Sphilip 386227569Sphilip req.emr_cmd = MC_CMD_GET_PHY_STATE; 387227569Sphilip EFX_STATIC_ASSERT(MC_CMD_GET_PHY_STATE_IN_LEN == 0); 388227569Sphilip req.emr_in_buf = NULL; 389227569Sphilip req.emr_in_length = 0; 390227569Sphilip req.emr_out_buf = outbuf; 391227569Sphilip req.emr_out_length = sizeof (outbuf); 392227569Sphilip 393227569Sphilip efx_mcdi_execute(enp, &req); 394227569Sphilip 395227569Sphilip if (req.emr_rc != 0) { 396227569Sphilip rc = req.emr_rc; 397227569Sphilip goto fail1; 398227569Sphilip } 399227569Sphilip 400227569Sphilip if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) { 401227569Sphilip rc = EMSGSIZE; 402227569Sphilip goto fail2; 403227569Sphilip } 404227569Sphilip 405227569Sphilip state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE); 406227569Sphilip if (state != MC_CMD_PHY_STATE_OK) { 407227569Sphilip if (state != MC_CMD_PHY_STATE_ZOMBIE) 408227569Sphilip EFSYS_PROBE1(mc_pcol_error, int, state); 409227569Sphilip rc = ENOTACTIVE; 410227569Sphilip goto fail3; 411227569Sphilip } 412227569Sphilip 413227569Sphilip return (0); 414227569Sphilip 415227569Sphilipfail3: 416227569Sphilip EFSYS_PROBE(fail3); 417227569Sphilipfail2: 418227569Sphilip EFSYS_PROBE(fail2); 419227569Sphilipfail1: 420227569Sphilip EFSYS_PROBE1(fail1, int, rc); 421227569Sphilip 422227569Sphilip return (rc); 423227569Sphilip} 424227569Sphilip 425227569Sphilip __checkReturn int 426227569Sphilipsiena_phy_oui_get( 427227569Sphilip __in efx_nic_t *enp, 428227569Sphilip __out uint32_t *ouip) 429227569Sphilip{ 430227569Sphilip _NOTE(ARGUNUSED(enp, ouip)) 431227569Sphilip 432227569Sphilip return (ENOTSUP); 433227569Sphilip} 434227569Sphilip 435227569Sphilip#if EFSYS_OPT_PHY_STATS 436227569Sphilip 437227569Sphilip#define SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat, \ 438227569Sphilip _mc_record, _efx_record) \ 439227569Sphilip if ((_vmask) & (1ULL << (_mc_record))) { \ 440227569Sphilip (_smask) |= (1ULL << (_efx_record)); \ 441227569Sphilip if ((_stat) != NULL && !EFSYS_MEM_IS_NULL(_esmp)) { \ 442227569Sphilip efx_dword_t dword; \ 443227569Sphilip EFSYS_MEM_READD(_esmp, (_mc_record) * 4, &dword);\ 444227569Sphilip (_stat)[_efx_record] = \ 445227569Sphilip EFX_DWORD_FIELD(dword, EFX_DWORD_0); \ 446227569Sphilip } \ 447227569Sphilip } 448227569Sphilip 449227569Sphilip#define SIENA_SIMPLE_STAT_SET2(_vmask, _esmp, _smask, _stat, _record) \ 450227569Sphilip SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat, \ 451227569Sphilip MC_CMD_ ## _record, \ 452227569Sphilip EFX_PHY_STAT_ ## _record) 453227569Sphilip 454227569Sphilip void 455227569Sphilipsiena_phy_decode_stats( 456227569Sphilip __in efx_nic_t *enp, 457227569Sphilip __in uint32_t vmask, 458227569Sphilip __in_opt efsys_mem_t *esmp, 459227569Sphilip __out_opt uint64_t *smaskp, 460227569Sphilip __out_ecount_opt(EFX_PHY_NSTATS) uint32_t *stat) 461227569Sphilip{ 462227569Sphilip uint64_t smask = 0; 463227569Sphilip 464227569Sphilip _NOTE(ARGUNUSED(enp)) 465227569Sphilip 466227569Sphilip SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, OUI); 467227569Sphilip SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_LINK_UP); 468227569Sphilip SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_RX_FAULT); 469227569Sphilip SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_TX_FAULT); 470227569Sphilip 471227569Sphilip if (vmask & (1 << MC_CMD_PMA_PMD_SIGNAL)) { 472227569Sphilip smask |= ((1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_A) | 473227569Sphilip (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_B) | 474227569Sphilip (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_C) | 475227569Sphilip (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_D)); 476227569Sphilip if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) { 477227569Sphilip efx_dword_t dword; 478227569Sphilip uint32_t sig; 479227569Sphilip EFSYS_MEM_READD(esmp, 4 * MC_CMD_PMA_PMD_SIGNAL, 480227569Sphilip &dword); 481227569Sphilip sig = EFX_DWORD_FIELD(dword, EFX_DWORD_0); 482227569Sphilip stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_A] = (sig >> 1) & 1; 483227569Sphilip stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_B] = (sig >> 2) & 1; 484227569Sphilip stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_C] = (sig >> 3) & 1; 485227569Sphilip stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_D] = (sig >> 4) & 1; 486227569Sphilip } 487227569Sphilip } 488227569Sphilip 489227569Sphilip SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_A, 490227569Sphilip EFX_PHY_STAT_SNR_A); 491227569Sphilip SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_B, 492227569Sphilip EFX_PHY_STAT_SNR_B); 493227569Sphilip SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_C, 494227569Sphilip EFX_PHY_STAT_SNR_C); 495227569Sphilip SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_D, 496227569Sphilip EFX_PHY_STAT_SNR_D); 497227569Sphilip 498227569Sphilip SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_LINK_UP); 499227569Sphilip SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_RX_FAULT); 500227569Sphilip SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_TX_FAULT); 501227569Sphilip SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BER); 502227569Sphilip SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BLOCK_ERRORS); 503227569Sphilip 504227569Sphilip SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_LINK_UP, 505227569Sphilip EFX_PHY_STAT_PHY_XS_LINK_UP); 506227569Sphilip SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_RX_FAULT, 507227569Sphilip EFX_PHY_STAT_PHY_XS_RX_FAULT); 508227569Sphilip SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_TX_FAULT, 509227569Sphilip EFX_PHY_STAT_PHY_XS_TX_FAULT); 510227569Sphilip SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_ALIGN, 511227569Sphilip EFX_PHY_STAT_PHY_XS_ALIGN); 512227569Sphilip 513227569Sphilip if (vmask & (1 << MC_CMD_PHYXS_SYNC)) { 514227569Sphilip smask |= ((1 << EFX_PHY_STAT_PHY_XS_SYNC_A) | 515227569Sphilip (1 << EFX_PHY_STAT_PHY_XS_SYNC_B) | 516227569Sphilip (1 << EFX_PHY_STAT_PHY_XS_SYNC_C) | 517227569Sphilip (1 << EFX_PHY_STAT_PHY_XS_SYNC_D)); 518227569Sphilip if (stat != NULL && !EFSYS_MEM_IS_NULL(esmp)) { 519227569Sphilip efx_dword_t dword; 520227569Sphilip uint32_t sync; 521227569Sphilip EFSYS_MEM_READD(esmp, 4 * MC_CMD_PHYXS_SYNC, &dword); 522227569Sphilip sync = EFX_DWORD_FIELD(dword, EFX_DWORD_0); 523227569Sphilip stat[EFX_PHY_STAT_PHY_XS_SYNC_A] = (sync >> 0) & 1; 524227569Sphilip stat[EFX_PHY_STAT_PHY_XS_SYNC_B] = (sync >> 1) & 1; 525227569Sphilip stat[EFX_PHY_STAT_PHY_XS_SYNC_C] = (sync >> 2) & 1; 526227569Sphilip stat[EFX_PHY_STAT_PHY_XS_SYNC_D] = (sync >> 3) & 1; 527227569Sphilip } 528227569Sphilip } 529227569Sphilip 530227569Sphilip SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_LINK_UP); 531227569Sphilip SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_COMPLETE); 532227569Sphilip 533227569Sphilip SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_CL22_LINK_UP, 534227569Sphilip EFX_PHY_STAT_CL22EXT_LINK_UP); 535227569Sphilip 536227569Sphilip if (smaskp != NULL) 537227569Sphilip *smaskp = smask; 538227569Sphilip} 539227569Sphilip 540227569Sphilip __checkReturn int 541227569Sphilipsiena_phy_stats_update( 542227569Sphilip __in efx_nic_t *enp, 543227569Sphilip __in efsys_mem_t *esmp, 544227569Sphilip __out_ecount(EFX_PHY_NSTATS) uint32_t *stat) 545227569Sphilip{ 546227569Sphilip efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 547227569Sphilip uint32_t vmask = encp->enc_siena_phy_stat_mask; 548227569Sphilip uint8_t payload[MC_CMD_PHY_STATS_IN_LEN]; 549227569Sphilip uint64_t smask; 550227569Sphilip efx_mcdi_req_t req; 551227569Sphilip int rc; 552227569Sphilip 553227569Sphilip req.emr_cmd = MC_CMD_PHY_STATS; 554227569Sphilip req.emr_in_buf = payload; 555227569Sphilip req.emr_in_length = sizeof (payload); 556227569Sphilip EFX_STATIC_ASSERT(MC_CMD_PHY_STATS_OUT_DMA_LEN == 0); 557227569Sphilip req.emr_out_buf = NULL; 558227569Sphilip req.emr_out_length = 0; 559227569Sphilip 560227569Sphilip MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_LO, 561227569Sphilip EFSYS_MEM_ADDR(esmp) & 0xffffffff); 562227569Sphilip MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_HI, 563227569Sphilip EFSYS_MEM_ADDR(esmp) >> 32); 564227569Sphilip 565227569Sphilip efx_mcdi_execute(enp, &req); 566227569Sphilip 567227569Sphilip if (req.emr_rc != 0) { 568227569Sphilip rc = req.emr_rc; 569227569Sphilip goto fail1; 570227569Sphilip } 571227569Sphilip EFSYS_ASSERT3U(req.emr_out_length, ==, MC_CMD_PHY_STATS_OUT_DMA_LEN); 572227569Sphilip 573227569Sphilip siena_phy_decode_stats(enp, vmask, esmp, &smask, stat); 574227569Sphilip EFSYS_ASSERT(smask == encp->enc_phy_stat_mask); 575227569Sphilip 576227569Sphilip return (0); 577227569Sphilip 578227569Sphilipfail1: 579227569Sphilip EFSYS_PROBE1(fail1, int, rc); 580227569Sphilip 581227569Sphilip return (0); 582227569Sphilip} 583227569Sphilip 584227569Sphilip#endif /* EFSYS_OPT_PHY_STATS */ 585227569Sphilip 586227569Sphilip#if EFSYS_OPT_PHY_PROPS 587227569Sphilip 588227569Sphilip#if EFSYS_OPT_NAMES 589227569Sphilip 590227569Sphilipextern const char __cs * 591227569Sphilipsiena_phy_prop_name( 592227569Sphilip __in efx_nic_t *enp, 593227569Sphilip __in unsigned int id) 594227569Sphilip{ 595227569Sphilip _NOTE(ARGUNUSED(enp, id)) 596227569Sphilip 597227569Sphilip return (NULL); 598227569Sphilip} 599227569Sphilip 600227569Sphilip#endif /* EFSYS_OPT_NAMES */ 601227569Sphilip 602227569Sphilipextern __checkReturn int 603227569Sphilipsiena_phy_prop_get( 604227569Sphilip __in efx_nic_t *enp, 605227569Sphilip __in unsigned int id, 606227569Sphilip __in uint32_t flags, 607227569Sphilip __out uint32_t *valp) 608227569Sphilip{ 609227569Sphilip _NOTE(ARGUNUSED(enp, id, flags, valp)) 610227569Sphilip 611227569Sphilip return (ENOTSUP); 612227569Sphilip} 613227569Sphilip 614227569Sphilipextern __checkReturn int 615227569Sphilipsiena_phy_prop_set( 616227569Sphilip __in efx_nic_t *enp, 617227569Sphilip __in unsigned int id, 618227569Sphilip __in uint32_t val) 619227569Sphilip{ 620227569Sphilip _NOTE(ARGUNUSED(enp, id, val)) 621227569Sphilip 622227569Sphilip return (ENOTSUP); 623227569Sphilip} 624227569Sphilip 625227569Sphilip#endif /* EFSYS_OPT_PHY_PROPS */ 626227569Sphilip 627227569Sphilip#if EFSYS_OPT_PHY_BIST 628227569Sphilip 629227569Sphilip __checkReturn int 630227569Sphilipsiena_phy_bist_start( 631227569Sphilip __in efx_nic_t *enp, 632227569Sphilip __in efx_phy_bist_type_t type) 633227569Sphilip{ 634227569Sphilip uint8_t payload[MC_CMD_START_BIST_IN_LEN]; 635227569Sphilip efx_mcdi_req_t req; 636227569Sphilip int rc; 637227569Sphilip 638227569Sphilip req.emr_cmd = MC_CMD_START_BIST; 639227569Sphilip req.emr_in_buf = payload; 640227569Sphilip req.emr_in_length = sizeof (payload); 641227569Sphilip EFX_STATIC_ASSERT(MC_CMD_START_BIST_OUT_LEN == 0); 642227569Sphilip req.emr_out_buf = NULL; 643227569Sphilip req.emr_out_length = 0; 644227569Sphilip 645227569Sphilip switch (type) { 646227569Sphilip case EFX_PHY_BIST_TYPE_NORMAL: 647227569Sphilip MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST); 648227569Sphilip break; 649227569Sphilip case EFX_PHY_BIST_TYPE_CABLE_SHORT: 650227569Sphilip MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 651227569Sphilip MC_CMD_PHY_BIST_CABLE_SHORT); 652227569Sphilip break; 653227569Sphilip case EFX_PHY_BIST_TYPE_CABLE_LONG: 654227569Sphilip MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 655227569Sphilip MC_CMD_PHY_BIST_CABLE_LONG); 656227569Sphilip break; 657227569Sphilip default: 658227569Sphilip EFSYS_ASSERT(0); 659227569Sphilip } 660227569Sphilip 661227569Sphilip efx_mcdi_execute(enp, &req); 662227569Sphilip 663227569Sphilip if (req.emr_rc != 0) { 664227569Sphilip rc = req.emr_rc; 665227569Sphilip goto fail1; 666227569Sphilip } 667227569Sphilip 668227569Sphilip return (0); 669227569Sphilip 670227569Sphilipfail1: 671227569Sphilip EFSYS_PROBE1(fail1, int, rc); 672227569Sphilip 673227569Sphilip return (rc); 674227569Sphilip} 675227569Sphilip 676227569Sphilipstatic __checkReturn unsigned long 677227569Sphilipsiena_phy_sft9001_bist_status( 678227569Sphilip __in uint16_t code) 679227569Sphilip{ 680227569Sphilip switch (code) { 681227569Sphilip case MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY: 682227569Sphilip return (EFX_PHY_CABLE_STATUS_BUSY); 683227569Sphilip case MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT: 684227569Sphilip return (EFX_PHY_CABLE_STATUS_INTERPAIRSHORT); 685227569Sphilip case MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT: 686227569Sphilip return (EFX_PHY_CABLE_STATUS_INTRAPAIRSHORT); 687227569Sphilip case MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN: 688227569Sphilip return (EFX_PHY_CABLE_STATUS_OPEN); 689227569Sphilip case MC_CMD_POLL_BIST_SFT9001_PAIR_OK: 690227569Sphilip return (EFX_PHY_CABLE_STATUS_OK); 691227569Sphilip default: 692227569Sphilip return (EFX_PHY_CABLE_STATUS_INVALID); 693227569Sphilip } 694227569Sphilip} 695227569Sphilip 696227569Sphilip __checkReturn int 697227569Sphilipsiena_phy_bist_poll( 698227569Sphilip __in efx_nic_t *enp, 699227569Sphilip __in efx_phy_bist_type_t type, 700227569Sphilip __out efx_phy_bist_result_t *resultp, 701227569Sphilip __out_opt __drv_when(count > 0, __notnull) 702227569Sphilip uint32_t *value_maskp, 703227569Sphilip __out_ecount_opt(count) __drv_when(count > 0, __notnull) 704227569Sphilip unsigned long *valuesp, 705227569Sphilip __in size_t count) 706227569Sphilip{ 707227569Sphilip efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 708227569Sphilip uint8_t payload[MCDI_CTL_SDU_LEN_MAX]; 709227569Sphilip uint32_t value_mask = 0; 710227569Sphilip efx_mcdi_req_t req; 711227569Sphilip uint32_t result; 712227569Sphilip int rc; 713227569Sphilip 714227569Sphilip req.emr_cmd = MC_CMD_POLL_BIST; 715227569Sphilip _NOTE(CONSTANTCONDITION) 716227569Sphilip EFSYS_ASSERT(MC_CMD_POLL_BIST_IN_LEN == 0); 717227569Sphilip req.emr_in_buf = NULL; 718227569Sphilip req.emr_in_length = 0; 719227569Sphilip req.emr_out_buf = payload; 720227569Sphilip req.emr_out_length = sizeof (payload); 721227569Sphilip 722227569Sphilip efx_mcdi_execute(enp, &req); 723227569Sphilip 724227569Sphilip if (req.emr_rc != 0) { 725227569Sphilip rc = req.emr_rc; 726227569Sphilip goto fail1; 727227569Sphilip } 728227569Sphilip 729227569Sphilip if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) { 730227569Sphilip rc = EMSGSIZE; 731227569Sphilip goto fail2; 732227569Sphilip } 733227569Sphilip 734227569Sphilip if (count > 0) 735227569Sphilip (void) memset(valuesp, '\0', count * sizeof (unsigned long)); 736227569Sphilip 737227569Sphilip result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT); 738227569Sphilip 739227569Sphilip /* Extract PHY specific results */ 740227569Sphilip if (result == MC_CMD_POLL_BIST_PASSED && 741227569Sphilip encp->enc_phy_type == EFX_PHY_SFT9001B && 742227569Sphilip req.emr_out_length_used >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN && 743227569Sphilip (type == EFX_PHY_BIST_TYPE_CABLE_SHORT || 744227569Sphilip type == EFX_PHY_BIST_TYPE_CABLE_LONG)) { 745227569Sphilip uint16_t word; 746227569Sphilip 747227569Sphilip if (count > EFX_PHY_BIST_CABLE_LENGTH_A) { 748227569Sphilip if (valuesp != NULL) 749227569Sphilip valuesp[EFX_PHY_BIST_CABLE_LENGTH_A] = 750227569Sphilip MCDI_OUT_DWORD(req, 751227569Sphilip POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A); 752227569Sphilip value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_A); 753227569Sphilip } 754227569Sphilip 755227569Sphilip if (count > EFX_PHY_BIST_CABLE_LENGTH_B) { 756227569Sphilip if (valuesp != NULL) 757227569Sphilip valuesp[EFX_PHY_BIST_CABLE_LENGTH_B] = 758227569Sphilip MCDI_OUT_DWORD(req, 759227569Sphilip POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B); 760227569Sphilip value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_B); 761227569Sphilip } 762227569Sphilip 763227569Sphilip if (count > EFX_PHY_BIST_CABLE_LENGTH_C) { 764227569Sphilip if (valuesp != NULL) 765227569Sphilip valuesp[EFX_PHY_BIST_CABLE_LENGTH_C] = 766227569Sphilip MCDI_OUT_DWORD(req, 767227569Sphilip POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C); 768227569Sphilip value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_C); 769227569Sphilip } 770227569Sphilip 771227569Sphilip if (count > EFX_PHY_BIST_CABLE_LENGTH_D) { 772227569Sphilip if (valuesp != NULL) 773227569Sphilip valuesp[EFX_PHY_BIST_CABLE_LENGTH_D] = 774227569Sphilip MCDI_OUT_DWORD(req, 775227569Sphilip POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D); 776227569Sphilip value_mask |= (1 << EFX_PHY_BIST_CABLE_LENGTH_D); 777227569Sphilip } 778227569Sphilip 779227569Sphilip if (count > EFX_PHY_BIST_CABLE_STATUS_A) { 780227569Sphilip if (valuesp != NULL) { 781227569Sphilip word = MCDI_OUT_WORD(req, 782227569Sphilip POLL_BIST_OUT_SFT9001_CABLE_STATUS_A); 783227569Sphilip valuesp[EFX_PHY_BIST_CABLE_STATUS_A] = 784227569Sphilip siena_phy_sft9001_bist_status(word); 785227569Sphilip } 786227569Sphilip value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_A); 787227569Sphilip } 788227569Sphilip 789227569Sphilip if (count > EFX_PHY_BIST_CABLE_STATUS_B) { 790227569Sphilip if (valuesp != NULL) { 791227569Sphilip word = MCDI_OUT_WORD(req, 792227569Sphilip POLL_BIST_OUT_SFT9001_CABLE_STATUS_B); 793227569Sphilip valuesp[EFX_PHY_BIST_CABLE_STATUS_B] = 794227569Sphilip siena_phy_sft9001_bist_status(word); 795227569Sphilip } 796227569Sphilip value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_B); 797227569Sphilip } 798227569Sphilip 799227569Sphilip if (count > EFX_PHY_BIST_CABLE_STATUS_C) { 800227569Sphilip if (valuesp != NULL) { 801227569Sphilip word = MCDI_OUT_WORD(req, 802227569Sphilip POLL_BIST_OUT_SFT9001_CABLE_STATUS_C); 803227569Sphilip valuesp[EFX_PHY_BIST_CABLE_STATUS_C] = 804227569Sphilip siena_phy_sft9001_bist_status(word); 805227569Sphilip } 806227569Sphilip value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_C); 807227569Sphilip } 808227569Sphilip 809227569Sphilip if (count > EFX_PHY_BIST_CABLE_STATUS_D) { 810227569Sphilip if (valuesp != NULL) { 811227569Sphilip word = MCDI_OUT_WORD(req, 812227569Sphilip POLL_BIST_OUT_SFT9001_CABLE_STATUS_D); 813227569Sphilip valuesp[EFX_PHY_BIST_CABLE_STATUS_D] = 814227569Sphilip siena_phy_sft9001_bist_status(word); 815227569Sphilip } 816227569Sphilip value_mask |= (1 << EFX_PHY_BIST_CABLE_STATUS_D); 817227569Sphilip } 818227569Sphilip 819227569Sphilip } else if (result == MC_CMD_POLL_BIST_FAILED && 820227569Sphilip encp->enc_phy_type == EFX_PHY_QLX111V && 821227569Sphilip req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN && 822227569Sphilip count > EFX_PHY_BIST_FAULT_CODE) { 823227569Sphilip if (valuesp != NULL) 824227569Sphilip valuesp[EFX_PHY_BIST_FAULT_CODE] = 825227569Sphilip MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST); 826227569Sphilip value_mask |= 1 << EFX_PHY_BIST_FAULT_CODE; 827227569Sphilip } 828227569Sphilip 829227569Sphilip if (value_maskp != NULL) 830227569Sphilip *value_maskp = value_mask; 831227569Sphilip 832227569Sphilip EFSYS_ASSERT(resultp != NULL); 833227569Sphilip if (result == MC_CMD_POLL_BIST_RUNNING) 834227569Sphilip *resultp = EFX_PHY_BIST_RESULT_RUNNING; 835227569Sphilip else if (result == MC_CMD_POLL_BIST_PASSED) 836227569Sphilip *resultp = EFX_PHY_BIST_RESULT_PASSED; 837227569Sphilip else 838227569Sphilip *resultp = EFX_PHY_BIST_RESULT_FAILED; 839227569Sphilip 840227569Sphilip return (0); 841227569Sphilip 842227569Sphilipfail2: 843227569Sphilip EFSYS_PROBE(fail2); 844227569Sphilipfail1: 845227569Sphilip EFSYS_PROBE1(fail1, int, rc); 846227569Sphilip 847227569Sphilip return (rc); 848227569Sphilip} 849227569Sphilip 850227569Sphilip void 851227569Sphilipsiena_phy_bist_stop( 852227569Sphilip __in efx_nic_t *enp, 853227569Sphilip __in efx_phy_bist_type_t type) 854227569Sphilip{ 855227569Sphilip /* There is no way to stop BIST on Siena */ 856227569Sphilip _NOTE(ARGUNUSED(enp, type)) 857227569Sphilip} 858227569Sphilip 859227569Sphilip#endif /* EFSYS_OPT_PHY_BIST */ 860227569Sphilip 861227569Sphilip#endif /* EFSYS_OPT_SIENA */ 862