1/*- 2 * Copyright (c) 2012-2015 Solarflare Communications Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * The views and conclusions contained in the software and documentation are 27 * those of the authors and should not be interpreted as representing official 28 * policies, either expressed or implied, of the FreeBSD Project. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: releng/10.2/sys/dev/sfxge/common/hunt_phy.c 284555 2015-06-18 15:46:39Z arybchik $"); 33 34#include "efsys.h" 35#include "efx.h" 36#include "efx_impl.h" 37 38#if EFSYS_OPT_HUNTINGTON 39 40static void 41hunt_phy_decode_cap( 42 __in uint32_t mcdi_cap, 43 __out uint32_t *maskp) 44{ 45 /* 46 * TBD: consider common Siena/Hunt function: Hunt is a superset of 47 * Siena here (adds 40G) 48 */ 49 50 uint32_t mask; 51 52 mask = 0; 53 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) 54 mask |= (1 << EFX_PHY_CAP_10HDX); 55 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) 56 mask |= (1 << EFX_PHY_CAP_10FDX); 57 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) 58 mask |= (1 << EFX_PHY_CAP_100HDX); 59 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) 60 mask |= (1 << EFX_PHY_CAP_100FDX); 61 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) 62 mask |= (1 << EFX_PHY_CAP_1000HDX); 63 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) 64 mask |= (1 << EFX_PHY_CAP_1000FDX); 65 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) 66 mask |= (1 << EFX_PHY_CAP_10000FDX); 67 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) 68 mask |= (1 << EFX_PHY_CAP_40000FDX); 69 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) 70 mask |= (1 << EFX_PHY_CAP_PAUSE); 71 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) 72 mask |= (1 << EFX_PHY_CAP_ASYM); 73 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) 74 mask |= (1 << EFX_PHY_CAP_AN); 75 76 *maskp = mask; 77} 78 79static void 80hunt_phy_decode_link_mode( 81 __in efx_nic_t *enp, 82 __in uint32_t link_flags, 83 __in unsigned int speed, 84 __in unsigned int fcntl, 85 __out efx_link_mode_t *link_modep, 86 __out unsigned int *fcntlp) 87{ 88 /* 89 * TBD: consider common Siena/Hunt function: Hunt is a superset of 90 * Siena here (adds 40G and generate-only flow control) 91 */ 92 93 boolean_t fd = !!(link_flags & 94 (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN)); 95 boolean_t up = !!(link_flags & 96 (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN)); 97 98 _NOTE(ARGUNUSED(enp)) 99 100 if (!up) 101 *link_modep = EFX_LINK_DOWN; 102 else if (speed == 40000 && fd) 103 *link_modep = EFX_LINK_40000FDX; 104 else if (speed == 10000 && fd) 105 *link_modep = EFX_LINK_10000FDX; 106 else if (speed == 1000) 107 *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX; 108 else if (speed == 100) 109 *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX; 110 else if (speed == 10) 111 *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX; 112 else 113 *link_modep = EFX_LINK_UNKNOWN; 114 115 if (fcntl == MC_CMD_FCNTL_OFF) 116 *fcntlp = 0; 117 else if (fcntl == MC_CMD_FCNTL_RESPOND) 118 *fcntlp = EFX_FCNTL_RESPOND; 119 else if (fcntl == MC_CMD_FCNTL_GENERATE) 120 *fcntlp = EFX_FCNTL_GENERATE; 121 else if (fcntl == MC_CMD_FCNTL_BIDIR) 122 *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE; 123 else { 124 EFSYS_PROBE1(mc_pcol_error, int, fcntl); 125 *fcntlp = 0; 126 } 127} 128 129 130 void 131hunt_phy_link_ev( 132 __in efx_nic_t *enp, 133 __in efx_qword_t *eqp, 134 __out efx_link_mode_t *link_modep) 135{ 136 /* 137 * TBD: consider common Siena/Hunt function: Hunt is a superset of 138 * Siena here (adds 40G) 139 */ 140 141 efx_port_t *epp = &(enp->en_port); 142 unsigned int link_flags; 143 unsigned int speed; 144 unsigned int fcntl; 145 efx_link_mode_t link_mode; 146 uint32_t lp_cap_mask; 147 148 /* 149 * Convert the LINKCHANGE speed enumeration into mbit/s, in the 150 * same way as GET_LINK encodes the speed 151 */ 152 switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) { 153 case MCDI_EVENT_LINKCHANGE_SPEED_100M: 154 speed = 100; 155 break; 156 case MCDI_EVENT_LINKCHANGE_SPEED_1G: 157 speed = 1000; 158 break; 159 case MCDI_EVENT_LINKCHANGE_SPEED_10G: 160 speed = 10000; 161 break; 162 case MCDI_EVENT_LINKCHANGE_SPEED_40G: 163 speed = 40000; 164 break; 165 default: 166 speed = 0; 167 break; 168 } 169 170 link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS); 171 hunt_phy_decode_link_mode(enp, link_flags, speed, 172 MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL), 173 &link_mode, &fcntl); 174 hunt_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP), 175 &lp_cap_mask); 176 177 /* 178 * It's safe to update ep_lp_cap_mask without the driver's port lock 179 * because presumably any concurrently running efx_port_poll() is 180 * only going to arrive at the same value. 181 * 182 * ep_fcntl has two meanings. It's either the link common fcntl 183 * (if the PHY supports AN), or it's the forced link state. If 184 * the former, it's safe to update the value for the same reason as 185 * for ep_lp_cap_mask. If the latter, then just ignore the value, 186 * because we can race with efx_mac_fcntl_set(). 187 */ 188 epp->ep_lp_cap_mask = lp_cap_mask; 189 epp->ep_fcntl = fcntl; 190 191 *link_modep = link_mode; 192} 193 194 __checkReturn int 195hunt_phy_power( 196 __in efx_nic_t *enp, 197 __in boolean_t power) 198{ 199 /* TBD: consider common Siena/Hunt function: essentially identical */ 200 201 int rc; 202 203 if (!power) 204 return (0); 205 206 /* Check if the PHY is a zombie */ 207 if ((rc = hunt_phy_verify(enp)) != 0) 208 goto fail1; 209 210 enp->en_reset_flags |= EFX_RESET_PHY; 211 212 return (0); 213 214fail1: 215 EFSYS_PROBE1(fail1, int, rc); 216 217 return (rc); 218} 219 220 __checkReturn int 221hunt_phy_get_link( 222 __in efx_nic_t *enp, 223 __out hunt_link_state_t *hlsp) 224{ 225 /* 226 * TBD: consider common Siena/Hunt function: Hunt is very similar 227 * (at least for now; not clear that the loopbacks should necessarily 228 * be quite the same...) 229 */ 230 231 efx_mcdi_req_t req; 232 uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN, 233 MC_CMD_GET_LINK_OUT_LEN)]; 234 int rc; 235 236 (void) memset(payload, 0, sizeof (payload)); 237 req.emr_cmd = MC_CMD_GET_LINK; 238 req.emr_in_buf = payload; 239 req.emr_in_length = MC_CMD_GET_LINK_IN_LEN; 240 req.emr_out_buf = payload; 241 req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN; 242 243 efx_mcdi_execute(enp, &req); 244 245 if (req.emr_rc != 0) { 246 rc = req.emr_rc; 247 goto fail1; 248 } 249 250 if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) { 251 rc = EMSGSIZE; 252 goto fail2; 253 } 254 255 hunt_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP), 256 &hlsp->hls_adv_cap_mask); 257 hunt_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP), 258 &hlsp->hls_lp_cap_mask); 259 260 hunt_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS), 261 MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED), 262 MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL), 263 &hlsp->hls_link_mode, &hlsp->hls_fcntl); 264 265#if EFSYS_OPT_LOOPBACK 266 /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */ 267 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF); 268 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA); 269 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC); 270 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII); 271 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS); 272 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI); 273 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII); 274 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII); 275 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR); 276 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI); 277 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR); 278 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR); 279 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR); 280 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR); 281 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY); 282 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS); 283 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS); 284 EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD); 285 286 hlsp->hls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE); 287#endif /* EFSYS_OPT_LOOPBACK */ 288 289 hlsp->hls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0; 290 291 return (0); 292 293fail2: 294 EFSYS_PROBE(fail2); 295fail1: 296 EFSYS_PROBE1(fail1, int, rc); 297 298 return (rc); 299} 300 301 __checkReturn int 302hunt_phy_reconfigure( 303 __in efx_nic_t *enp) 304{ 305 /* 306 * TBD: this is a little different for now (no LED support for Hunt 307 * yet), but ultimately should consider common Siena/Hunt function: 308 * Hunt should be a superset of Siena here (adds 40G) 309 */ 310 311 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 312 efx_port_t *epp = &(enp->en_port); 313 efx_mcdi_req_t req; 314 uint8_t payload[MAX(MC_CMD_SET_LINK_IN_LEN, 315 MC_CMD_SET_LINK_OUT_LEN)]; 316 uint32_t cap_mask; 317 unsigned int led_mode; 318 unsigned int speed; 319 int rc; 320 321 if (~encp->enc_func_flags & EFX_NIC_FUNC_LINKCTRL) 322 goto out; 323 324 (void) memset(payload, 0, sizeof (payload)); 325 req.emr_cmd = MC_CMD_SET_LINK; 326 req.emr_in_buf = payload; 327 req.emr_in_length = MC_CMD_SET_LINK_IN_LEN; 328 req.emr_out_buf = payload; 329 req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN; 330 331 cap_mask = epp->ep_adv_cap_mask; 332 MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP, 333 PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1, 334 PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1, 335 PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1, 336 PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1, 337 PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1, 338 PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1, 339 PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1, 340 PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1, 341 PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1, 342 PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1); 343 /* Too many fields for for POPULATE macros, so insert this afterwards */ 344 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, 345 PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1); 346 347#if EFSYS_OPT_LOOPBACK 348 MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, 349 epp->ep_loopback_type); 350 switch (epp->ep_loopback_link_mode) { 351 case EFX_LINK_100FDX: 352 speed = 100; 353 break; 354 case EFX_LINK_1000FDX: 355 speed = 1000; 356 break; 357 case EFX_LINK_10000FDX: 358 speed = 10000; 359 break; 360 case EFX_LINK_40000FDX: 361 speed = 40000; 362 break; 363 default: 364 speed = 0; 365 } 366#else 367 MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE); 368 speed = 0; 369#endif /* EFSYS_OPT_LOOPBACK */ 370 MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed); 371 372#if EFSYS_OPT_PHY_FLAGS 373 MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags); 374#else 375 MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0); 376#endif /* EFSYS_OPT_PHY_FLAGS */ 377 378 efx_mcdi_execute(enp, &req); 379 380 if (req.emr_rc != 0) { 381 rc = req.emr_rc; 382 goto fail1; 383 } 384 385 /* And set the blink mode */ 386 (void) memset(payload, 0, sizeof (payload)); 387 req.emr_cmd = MC_CMD_SET_ID_LED; 388 req.emr_in_buf = payload; 389 req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN; 390 req.emr_out_buf = payload; 391 req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN; 392 393#if EFSYS_OPT_PHY_LED_CONTROL 394 switch (epp->ep_phy_led_mode) { 395 case EFX_PHY_LED_DEFAULT: 396 led_mode = MC_CMD_LED_DEFAULT; 397 break; 398 case EFX_PHY_LED_OFF: 399 led_mode = MC_CMD_LED_OFF; 400 break; 401 case EFX_PHY_LED_ON: 402 led_mode = MC_CMD_LED_ON; 403 break; 404 default: 405 EFSYS_ASSERT(0); 406 led_mode = MC_CMD_LED_DEFAULT; 407 } 408 409 MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode); 410#else 411 MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT); 412#endif /* EFSYS_OPT_PHY_LED_CONTROL */ 413 414 efx_mcdi_execute(enp, &req); 415 416 if (req.emr_rc != 0) { 417 rc = req.emr_rc; 418 goto fail2; 419 } 420out: 421 return (0); 422 423fail2: 424 EFSYS_PROBE(fail2); 425fail1: 426 EFSYS_PROBE1(fail1, int, rc); 427 428 return (rc); 429} 430 431 __checkReturn int 432hunt_phy_verify( 433 __in efx_nic_t *enp) 434{ 435 /* TBD: consider common Siena/Hunt function: essentially identical */ 436 437 efx_mcdi_req_t req; 438 uint8_t payload[MAX(MC_CMD_GET_PHY_STATE_IN_LEN, 439 MC_CMD_GET_PHY_STATE_OUT_LEN)]; 440 uint32_t state; 441 int rc; 442 443 (void) memset(payload, 0, sizeof (payload)); 444 req.emr_cmd = MC_CMD_GET_PHY_STATE; 445 req.emr_in_buf = payload; 446 req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN; 447 req.emr_out_buf = payload; 448 req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN; 449 450 efx_mcdi_execute(enp, &req); 451 452 if (req.emr_rc != 0) { 453 rc = req.emr_rc; 454 goto fail1; 455 } 456 457 if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) { 458 rc = EMSGSIZE; 459 goto fail2; 460 } 461 462 state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE); 463 if (state != MC_CMD_PHY_STATE_OK) { 464 if (state != MC_CMD_PHY_STATE_ZOMBIE) 465 EFSYS_PROBE1(mc_pcol_error, int, state); 466 rc = ENOTACTIVE; 467 goto fail3; 468 } 469 470 return (0); 471 472fail3: 473 EFSYS_PROBE(fail3); 474fail2: 475 EFSYS_PROBE(fail2); 476fail1: 477 EFSYS_PROBE1(fail1, int, rc); 478 479 return (rc); 480} 481 482 __checkReturn int 483hunt_phy_oui_get( 484 __in efx_nic_t *enp, 485 __out uint32_t *ouip) 486{ 487 _NOTE(ARGUNUSED(enp, ouip)) 488 489 return (ENOTSUP); 490} 491 492#if EFSYS_OPT_PHY_STATS 493 494 __checkReturn int 495hunt_phy_stats_update( 496 __in efx_nic_t *enp, 497 __in efsys_mem_t *esmp, 498 __out_ecount(EFX_PHY_NSTATS) uint32_t *stat) 499{ 500 /* TBD: no stats support in firmware yet */ 501 _NOTE(ARGUNUSED(enp, esmp)) 502 memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat)); 503 504 return (0); 505} 506 507#endif /* EFSYS_OPT_PHY_STATS */ 508 509#if EFSYS_OPT_PHY_PROPS 510 511#if EFSYS_OPT_NAMES 512 513extern const char * 514hunt_phy_prop_name( 515 __in efx_nic_t *enp, 516 __in unsigned int id) 517{ 518 _NOTE(ARGUNUSED(enp, id)) 519 520 return (NULL); 521} 522 523#endif /* EFSYS_OPT_NAMES */ 524 525extern __checkReturn int 526hunt_phy_prop_get( 527 __in efx_nic_t *enp, 528 __in unsigned int id, 529 __in uint32_t flags, 530 __out uint32_t *valp) 531{ 532 _NOTE(ARGUNUSED(enp, id, flags, valp)) 533 534 return (ENOTSUP); 535} 536 537extern __checkReturn int 538hunt_phy_prop_set( 539 __in efx_nic_t *enp, 540 __in unsigned int id, 541 __in uint32_t val) 542{ 543 _NOTE(ARGUNUSED(enp, id, val)) 544 545 return (ENOTSUP); 546} 547 548#endif /* EFSYS_OPT_PHY_PROPS */ 549 550#if EFSYS_OPT_BIST 551 552 __checkReturn int 553hunt_bist_enable_offline( 554 __in efx_nic_t *enp) 555{ 556 int rc; 557 558 if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0) 559 goto fail1; 560 561 return (0); 562 563fail1: 564 EFSYS_PROBE1(fail1, int, rc); 565 566 return (rc); 567} 568 569 __checkReturn int 570hunt_bist_start( 571 __in efx_nic_t *enp, 572 __in efx_bist_type_t type) 573{ 574 int rc; 575 576 if ((rc = efx_mcdi_bist_start(enp, type)) != 0) 577 goto fail1; 578 579 return (0); 580 581fail1: 582 EFSYS_PROBE1(fail1, int, rc); 583 584 return (rc); 585} 586 587 __checkReturn int 588hunt_bist_poll( 589 __in efx_nic_t *enp, 590 __in efx_bist_type_t type, 591 __out efx_bist_result_t *resultp, 592 __out_opt __drv_when(count > 0, __notnull) 593 uint32_t *value_maskp, 594 __out_ecount_opt(count) __drv_when(count > 0, __notnull) 595 unsigned long *valuesp, 596 __in size_t count) 597{ 598 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 599 efx_mcdi_req_t req; 600 uint8_t payload[MAX(MC_CMD_POLL_BIST_IN_LEN, 601 MCDI_CTL_SDU_LEN_MAX)]; 602 uint32_t value_mask = 0; 603 uint32_t result; 604 int rc; 605 606 (void) memset(payload, 0, sizeof (payload)); 607 req.emr_cmd = MC_CMD_POLL_BIST; 608 req.emr_in_buf = payload; 609 req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN; 610 req.emr_out_buf = payload; 611 req.emr_out_length = MCDI_CTL_SDU_LEN_MAX; 612 613 efx_mcdi_execute(enp, &req); 614 615 if (req.emr_rc != 0) { 616 rc = req.emr_rc; 617 goto fail1; 618 } 619 620 if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) { 621 rc = EMSGSIZE; 622 goto fail2; 623 } 624 625 if (count > 0) 626 (void) memset(valuesp, '\0', count * sizeof (unsigned long)); 627 628 result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT); 629 630 if (result == MC_CMD_POLL_BIST_FAILED && 631 req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN && 632 count > EFX_BIST_MEM_ECC_FATAL) { 633 if (valuesp != NULL) { 634 valuesp[EFX_BIST_MEM_TEST] = 635 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST); 636 valuesp[EFX_BIST_MEM_ADDR] = 637 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR); 638 valuesp[EFX_BIST_MEM_BUS] = 639 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS); 640 valuesp[EFX_BIST_MEM_EXPECT] = 641 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT); 642 valuesp[EFX_BIST_MEM_ACTUAL] = 643 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL); 644 valuesp[EFX_BIST_MEM_ECC] = 645 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC); 646 valuesp[EFX_BIST_MEM_ECC_PARITY] = 647 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY); 648 valuesp[EFX_BIST_MEM_ECC_FATAL] = 649 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL); 650 } 651 value_mask |= (1 << EFX_BIST_MEM_TEST) | 652 (1 << EFX_BIST_MEM_ADDR) | 653 (1 << EFX_BIST_MEM_BUS) | 654 (1 << EFX_BIST_MEM_EXPECT) | 655 (1 << EFX_BIST_MEM_ACTUAL) | 656 (1 << EFX_BIST_MEM_ECC) | 657 (1 << EFX_BIST_MEM_ECC_PARITY) | 658 (1 << EFX_BIST_MEM_ECC_FATAL); 659 } else if (result == MC_CMD_POLL_BIST_FAILED && 660 encp->enc_phy_type == EFX_PHY_XFI_FARMI && 661 req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN && 662 count > EFX_BIST_FAULT_CODE) { 663 if (valuesp != NULL) 664 valuesp[EFX_BIST_FAULT_CODE] = 665 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST); 666 value_mask |= 1 << EFX_BIST_FAULT_CODE; 667 } 668 669 if (value_maskp != NULL) 670 *value_maskp = value_mask; 671 672 EFSYS_ASSERT(resultp != NULL); 673 if (result == MC_CMD_POLL_BIST_RUNNING) 674 *resultp = EFX_BIST_RESULT_RUNNING; 675 else if (result == MC_CMD_POLL_BIST_PASSED) 676 *resultp = EFX_BIST_RESULT_PASSED; 677 else 678 *resultp = EFX_BIST_RESULT_FAILED; 679 680 return (0); 681 682fail2: 683 EFSYS_PROBE(fail2); 684fail1: 685 EFSYS_PROBE1(fail1, int, rc); 686 687 return (rc); 688} 689 690 void 691hunt_bist_stop( 692 __in efx_nic_t *enp, 693 __in efx_bist_type_t type) 694{ 695 /* There is no way to stop BIST on Huntinton. */ 696 _NOTE(ARGUNUSED(enp, type)) 697} 698 699#endif /* EFSYS_OPT_BIST */ 700 701#endif /* EFSYS_OPT_HUNTINGTON */ 702