1 /*- 2 * Copyright (c) 2012-2016 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 #include "efx.h" 33 #include "efx_impl.h" 34 35 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 36 37 static void 38 mcdi_phy_decode_cap( 39 __in uint32_t mcdi_cap, 40 __out uint32_t *maskp) 41 { 42 uint32_t mask; 43 44 #define CHECK_CAP(_cap) \ 45 EFX_STATIC_ASSERT(EFX_PHY_CAP_##_cap == MC_CMD_PHY_CAP_##_cap##_LBN) 46 47 CHECK_CAP(10HDX); 48 CHECK_CAP(10FDX); 49 CHECK_CAP(100HDX); 50 CHECK_CAP(100FDX); 51 CHECK_CAP(1000HDX); 52 CHECK_CAP(1000FDX); 53 CHECK_CAP(10000FDX); 54 CHECK_CAP(25000FDX); 55 CHECK_CAP(40000FDX); 56 CHECK_CAP(50000FDX); 57 CHECK_CAP(100000FDX); 58 CHECK_CAP(PAUSE); 59 CHECK_CAP(ASYM); 60 CHECK_CAP(AN); 61 CHECK_CAP(DDM); 62 CHECK_CAP(BASER_FEC); 63 CHECK_CAP(BASER_FEC_REQUESTED); 64 CHECK_CAP(RS_FEC); 65 CHECK_CAP(RS_FEC_REQUESTED); 66 CHECK_CAP(25G_BASER_FEC); 67 CHECK_CAP(25G_BASER_FEC_REQUESTED); 68 #undef CHECK_CAP 69 70 mask = 0; 71 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN)) 72 mask |= (1 << EFX_PHY_CAP_10HDX); 73 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN)) 74 mask |= (1 << EFX_PHY_CAP_10FDX); 75 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN)) 76 mask |= (1 << EFX_PHY_CAP_100HDX); 77 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN)) 78 mask |= (1 << EFX_PHY_CAP_100FDX); 79 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN)) 80 mask |= (1 << EFX_PHY_CAP_1000HDX); 81 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN)) 82 mask |= (1 << EFX_PHY_CAP_1000FDX); 83 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN)) 84 mask |= (1 << EFX_PHY_CAP_10000FDX); 85 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25000FDX_LBN)) 86 mask |= (1 << EFX_PHY_CAP_25000FDX); 87 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_40000FDX_LBN)) 88 mask |= (1 << EFX_PHY_CAP_40000FDX); 89 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_50000FDX_LBN)) 90 mask |= (1 << EFX_PHY_CAP_50000FDX); 91 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100000FDX_LBN)) 92 mask |= (1 << EFX_PHY_CAP_100000FDX); 93 94 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN)) 95 mask |= (1 << EFX_PHY_CAP_PAUSE); 96 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN)) 97 mask |= (1 << EFX_PHY_CAP_ASYM); 98 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN)) 99 mask |= (1 << EFX_PHY_CAP_AN); 100 101 /* FEC caps (supported on Medford2 and later) */ 102 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_LBN)) 103 mask |= (1 << EFX_PHY_CAP_BASER_FEC); 104 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_BASER_FEC_REQUESTED_LBN)) 105 mask |= (1 << EFX_PHY_CAP_BASER_FEC_REQUESTED); 106 107 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_LBN)) 108 mask |= (1 << EFX_PHY_CAP_RS_FEC); 109 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_RS_FEC_REQUESTED_LBN)) 110 mask |= (1 << EFX_PHY_CAP_RS_FEC_REQUESTED); 111 112 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_LBN)) 113 mask |= (1 << EFX_PHY_CAP_25G_BASER_FEC); 114 if (mcdi_cap & (1 << MC_CMD_PHY_CAP_25G_BASER_FEC_REQUESTED_LBN)) 115 mask |= (1 << EFX_PHY_CAP_25G_BASER_FEC_REQUESTED); 116 117 *maskp = mask; 118 } 119 120 static void 121 mcdi_phy_decode_link_mode( 122 __in efx_nic_t *enp, 123 __in uint32_t link_flags, 124 __in unsigned int speed, 125 __in unsigned int fcntl, 126 __in uint32_t fec, 127 __out efx_link_mode_t *link_modep, 128 __out unsigned int *fcntlp, 129 __out efx_phy_fec_type_t *fecp) 130 { 131 boolean_t fd = !!(link_flags & 132 (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN)); 133 boolean_t up = !!(link_flags & 134 (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN)); 135 136 _NOTE(ARGUNUSED(enp)) 137 138 if (!up) 139 *link_modep = EFX_LINK_DOWN; 140 else if (speed == 100000 && fd) 141 *link_modep = EFX_LINK_100000FDX; 142 else if (speed == 50000 && fd) 143 *link_modep = EFX_LINK_50000FDX; 144 else if (speed == 40000 && fd) 145 *link_modep = EFX_LINK_40000FDX; 146 else if (speed == 25000 && fd) 147 *link_modep = EFX_LINK_25000FDX; 148 else if (speed == 10000 && fd) 149 *link_modep = EFX_LINK_10000FDX; 150 else if (speed == 1000) 151 *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX; 152 else if (speed == 100) 153 *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX; 154 else if (speed == 10) 155 *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX; 156 else 157 *link_modep = EFX_LINK_UNKNOWN; 158 159 if (fcntl == MC_CMD_FCNTL_OFF) 160 *fcntlp = 0; 161 else if (fcntl == MC_CMD_FCNTL_RESPOND) 162 *fcntlp = EFX_FCNTL_RESPOND; 163 else if (fcntl == MC_CMD_FCNTL_GENERATE) 164 *fcntlp = EFX_FCNTL_GENERATE; 165 else if (fcntl == MC_CMD_FCNTL_BIDIR) 166 *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE; 167 else { 168 EFSYS_PROBE1(mc_pcol_error, int, fcntl); 169 *fcntlp = 0; 170 } 171 172 switch (fec) { 173 case MC_CMD_FEC_NONE: 174 *fecp = EFX_PHY_FEC_NONE; 175 break; 176 case MC_CMD_FEC_BASER: 177 *fecp = EFX_PHY_FEC_BASER; 178 break; 179 case MC_CMD_FEC_RS: 180 *fecp = EFX_PHY_FEC_RS; 181 break; 182 default: 183 EFSYS_PROBE1(mc_pcol_error, int, fec); 184 *fecp = EFX_PHY_FEC_NONE; 185 break; 186 } 187 } 188 189 void 190 ef10_phy_link_ev( 191 __in efx_nic_t *enp, 192 __in efx_qword_t *eqp, 193 __out efx_link_mode_t *link_modep) 194 { 195 efx_port_t *epp = &(enp->en_port); 196 unsigned int link_flags; 197 unsigned int speed; 198 unsigned int fcntl; 199 efx_phy_fec_type_t fec = MC_CMD_FEC_NONE; 200 efx_link_mode_t link_mode; 201 uint32_t lp_cap_mask; 202 203 /* 204 * Convert the LINKCHANGE speed enumeration into mbit/s, in the 205 * same way as GET_LINK encodes the speed 206 */ 207 switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) { 208 case MCDI_EVENT_LINKCHANGE_SPEED_100M: 209 speed = 100; 210 break; 211 case MCDI_EVENT_LINKCHANGE_SPEED_1G: 212 speed = 1000; 213 break; 214 case MCDI_EVENT_LINKCHANGE_SPEED_10G: 215 speed = 10000; 216 break; 217 case MCDI_EVENT_LINKCHANGE_SPEED_25G: 218 speed = 25000; 219 break; 220 case MCDI_EVENT_LINKCHANGE_SPEED_40G: 221 speed = 40000; 222 break; 223 case MCDI_EVENT_LINKCHANGE_SPEED_50G: 224 speed = 50000; 225 break; 226 case MCDI_EVENT_LINKCHANGE_SPEED_100G: 227 speed = 100000; 228 break; 229 default: 230 speed = 0; 231 break; 232 } 233 234 link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS); 235 mcdi_phy_decode_link_mode(enp, link_flags, speed, 236 MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL), 237 MC_CMD_FEC_NONE, &link_mode, 238 &fcntl, &fec); 239 mcdi_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP), 240 &lp_cap_mask); 241 242 /* 243 * It's safe to update ep_lp_cap_mask without the driver's port lock 244 * because presumably any concurrently running efx_port_poll() is 245 * only going to arrive at the same value. 246 * 247 * ep_fcntl has two meanings. It's either the link common fcntl 248 * (if the PHY supports AN), or it's the forced link state. If 249 * the former, it's safe to update the value for the same reason as 250 * for ep_lp_cap_mask. If the latter, then just ignore the value, 251 * because we can race with efx_mac_fcntl_set(). 252 */ 253 epp->ep_lp_cap_mask = lp_cap_mask; 254 epp->ep_fcntl = fcntl; 255 256 *link_modep = link_mode; 257 } 258 259 __checkReturn efx_rc_t 260 ef10_phy_power( 261 __in efx_nic_t *enp, 262 __in boolean_t power) 263 { 264 efx_rc_t rc; 265 266 if (!power) 267 return (0); 268 269 /* Check if the PHY is a zombie */ 270 if ((rc = ef10_phy_verify(enp)) != 0) 271 goto fail1; 272 273 enp->en_reset_flags |= EFX_RESET_PHY; 274 275 return (0); 276 277 fail1: 278 EFSYS_PROBE1(fail1, efx_rc_t, rc); 279 280 return (rc); 281 } 282 283 __checkReturn efx_rc_t 284 ef10_phy_get_link( 285 __in efx_nic_t *enp, 286 __out ef10_link_state_t *elsp) 287 { 288 efx_mcdi_req_t req; 289 uint32_t fec; 290 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_LINK_IN_LEN, 291 MC_CMD_GET_LINK_OUT_V2_LEN); 292 efx_rc_t rc; 293 294 req.emr_cmd = MC_CMD_GET_LINK; 295 req.emr_in_buf = payload; 296 req.emr_in_length = MC_CMD_GET_LINK_IN_LEN; 297 req.emr_out_buf = payload; 298 req.emr_out_length = MC_CMD_GET_LINK_OUT_V2_LEN; 299 300 efx_mcdi_execute(enp, &req); 301 302 if (req.emr_rc != 0) { 303 rc = req.emr_rc; 304 goto fail1; 305 } 306 307 if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) { 308 rc = EMSGSIZE; 309 goto fail2; 310 } 311 312 mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP), 313 &elsp->epls.epls_adv_cap_mask); 314 mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP), 315 &elsp->epls.epls_lp_cap_mask); 316 317 if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_V2_LEN) 318 fec = MC_CMD_FEC_NONE; 319 else 320 fec = MCDI_OUT_DWORD(req, GET_LINK_OUT_V2_FEC_TYPE); 321 322 mcdi_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS), 323 MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED), 324 MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL), 325 fec, &elsp->epls.epls_link_mode, 326 &elsp->epls.epls_fcntl, &elsp->epls.epls_fec); 327 328 if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_V2_LEN) { 329 elsp->epls.epls_ld_cap_mask = 0; 330 } else { 331 mcdi_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_V2_LD_CAP), 332 &elsp->epls.epls_ld_cap_mask); 333 } 334 335 #if EFSYS_OPT_LOOPBACK 336 /* 337 * MC_CMD_LOOPBACK and EFX_LOOPBACK names are equivalent, so use the 338 * MCDI value directly. Agreement is checked in efx_loopback_mask(). 339 */ 340 elsp->els_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE); 341 #endif /* EFSYS_OPT_LOOPBACK */ 342 343 elsp->els_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0; 344 345 return (0); 346 347 fail2: 348 EFSYS_PROBE(fail2); 349 fail1: 350 EFSYS_PROBE1(fail1, efx_rc_t, rc); 351 352 return (rc); 353 } 354 355 __checkReturn efx_rc_t 356 ef10_phy_reconfigure( 357 __in efx_nic_t *enp) 358 { 359 efx_port_t *epp = &(enp->en_port); 360 efx_mcdi_req_t req; 361 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_SET_LINK_IN_LEN, 362 MC_CMD_SET_LINK_OUT_LEN); 363 uint32_t cap_mask; 364 #if EFSYS_OPT_PHY_LED_CONTROL 365 unsigned int led_mode; 366 #endif 367 unsigned int speed; 368 boolean_t supported; 369 efx_rc_t rc; 370 371 if ((rc = efx_mcdi_link_control_supported(enp, &supported)) != 0) 372 goto fail1; 373 if (supported == B_FALSE) 374 goto out; 375 376 req.emr_cmd = MC_CMD_SET_LINK; 377 req.emr_in_buf = payload; 378 req.emr_in_length = MC_CMD_SET_LINK_IN_LEN; 379 req.emr_out_buf = payload; 380 req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN; 381 382 cap_mask = epp->ep_adv_cap_mask; 383 MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP, 384 PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1, 385 PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1, 386 PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1, 387 PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1, 388 PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1, 389 PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1, 390 PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1, 391 PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1, 392 PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1, 393 PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1); 394 /* Too many fields for POPULATE macros, so insert this afterwards */ 395 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, 396 PHY_CAP_25000FDX, (cap_mask >> EFX_PHY_CAP_25000FDX) & 0x1); 397 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, 398 PHY_CAP_40000FDX, (cap_mask >> EFX_PHY_CAP_40000FDX) & 0x1); 399 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, 400 PHY_CAP_50000FDX, (cap_mask >> EFX_PHY_CAP_50000FDX) & 0x1); 401 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, 402 PHY_CAP_100000FDX, (cap_mask >> EFX_PHY_CAP_100000FDX) & 0x1); 403 404 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, 405 PHY_CAP_BASER_FEC, (cap_mask >> EFX_PHY_CAP_BASER_FEC) & 0x1); 406 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, 407 PHY_CAP_BASER_FEC_REQUESTED, 408 (cap_mask >> EFX_PHY_CAP_BASER_FEC_REQUESTED) & 0x1); 409 410 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, 411 PHY_CAP_RS_FEC, (cap_mask >> EFX_PHY_CAP_RS_FEC) & 0x1); 412 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, 413 PHY_CAP_RS_FEC_REQUESTED, 414 (cap_mask >> EFX_PHY_CAP_RS_FEC_REQUESTED) & 0x1); 415 416 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, 417 PHY_CAP_25G_BASER_FEC, 418 (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC) & 0x1); 419 MCDI_IN_SET_DWORD_FIELD(req, SET_LINK_IN_CAP, 420 PHY_CAP_25G_BASER_FEC_REQUESTED, 421 (cap_mask >> EFX_PHY_CAP_25G_BASER_FEC_REQUESTED) & 0x1); 422 423 #if EFSYS_OPT_LOOPBACK 424 MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, 425 epp->ep_loopback_type); 426 switch (epp->ep_loopback_link_mode) { 427 case EFX_LINK_100FDX: 428 speed = 100; 429 break; 430 case EFX_LINK_1000FDX: 431 speed = 1000; 432 break; 433 case EFX_LINK_10000FDX: 434 speed = 10000; 435 break; 436 case EFX_LINK_25000FDX: 437 speed = 25000; 438 break; 439 case EFX_LINK_40000FDX: 440 speed = 40000; 441 break; 442 case EFX_LINK_50000FDX: 443 speed = 50000; 444 break; 445 case EFX_LINK_100000FDX: 446 speed = 100000; 447 break; 448 default: 449 speed = 0; 450 } 451 #else 452 MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE); 453 speed = 0; 454 #endif /* EFSYS_OPT_LOOPBACK */ 455 MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed); 456 457 #if EFSYS_OPT_PHY_FLAGS 458 MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags); 459 #else 460 MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0); 461 #endif /* EFSYS_OPT_PHY_FLAGS */ 462 463 efx_mcdi_execute(enp, &req); 464 465 if (req.emr_rc != 0) { 466 rc = req.emr_rc; 467 goto fail2; 468 } 469 470 /* And set the blink mode */ 471 (void) memset(payload, 0, sizeof (payload)); 472 req.emr_cmd = MC_CMD_SET_ID_LED; 473 req.emr_in_buf = payload; 474 req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN; 475 req.emr_out_buf = payload; 476 req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN; 477 478 #if EFSYS_OPT_PHY_LED_CONTROL 479 switch (epp->ep_phy_led_mode) { 480 case EFX_PHY_LED_DEFAULT: 481 led_mode = MC_CMD_LED_DEFAULT; 482 break; 483 case EFX_PHY_LED_OFF: 484 led_mode = MC_CMD_LED_OFF; 485 break; 486 case EFX_PHY_LED_ON: 487 led_mode = MC_CMD_LED_ON; 488 break; 489 default: 490 EFSYS_ASSERT(0); 491 led_mode = MC_CMD_LED_DEFAULT; 492 } 493 494 MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode); 495 #else 496 MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT); 497 #endif /* EFSYS_OPT_PHY_LED_CONTROL */ 498 499 efx_mcdi_execute(enp, &req); 500 501 if (req.emr_rc != 0) { 502 rc = req.emr_rc; 503 goto fail3; 504 } 505 out: 506 return (0); 507 508 fail3: 509 EFSYS_PROBE(fail3); 510 fail2: 511 EFSYS_PROBE(fail2); 512 fail1: 513 EFSYS_PROBE1(fail1, efx_rc_t, rc); 514 515 return (rc); 516 } 517 518 __checkReturn efx_rc_t 519 ef10_phy_verify( 520 __in efx_nic_t *enp) 521 { 522 efx_mcdi_req_t req; 523 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_STATE_IN_LEN, 524 MC_CMD_GET_PHY_STATE_OUT_LEN); 525 uint32_t state; 526 efx_rc_t rc; 527 528 req.emr_cmd = MC_CMD_GET_PHY_STATE; 529 req.emr_in_buf = payload; 530 req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN; 531 req.emr_out_buf = payload; 532 req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN; 533 534 efx_mcdi_execute(enp, &req); 535 536 if (req.emr_rc != 0) { 537 rc = req.emr_rc; 538 goto fail1; 539 } 540 541 if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) { 542 rc = EMSGSIZE; 543 goto fail2; 544 } 545 546 state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE); 547 if (state != MC_CMD_PHY_STATE_OK) { 548 if (state != MC_CMD_PHY_STATE_ZOMBIE) 549 EFSYS_PROBE1(mc_pcol_error, int, state); 550 rc = ENOTACTIVE; 551 goto fail3; 552 } 553 554 return (0); 555 556 fail3: 557 EFSYS_PROBE(fail3); 558 fail2: 559 EFSYS_PROBE(fail2); 560 fail1: 561 EFSYS_PROBE1(fail1, efx_rc_t, rc); 562 563 return (rc); 564 } 565 566 __checkReturn efx_rc_t 567 ef10_phy_oui_get( 568 __in efx_nic_t *enp, 569 __out uint32_t *ouip) 570 { 571 _NOTE(ARGUNUSED(enp, ouip)) 572 573 return (ENOTSUP); 574 } 575 576 __checkReturn efx_rc_t 577 ef10_phy_link_state_get( 578 __in efx_nic_t *enp, 579 __out efx_phy_link_state_t *eplsp) 580 { 581 efx_rc_t rc; 582 ef10_link_state_t els; 583 584 /* Obtain the active link state */ 585 if ((rc = ef10_phy_get_link(enp, &els)) != 0) 586 goto fail1; 587 588 *eplsp = els.epls; 589 590 return (0); 591 592 fail1: 593 EFSYS_PROBE1(fail1, efx_rc_t, rc); 594 595 return (rc); 596 } 597 598 #if EFSYS_OPT_PHY_STATS 599 600 __checkReturn efx_rc_t 601 ef10_phy_stats_update( 602 __in efx_nic_t *enp, 603 __in efsys_mem_t *esmp, 604 __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat) 605 { 606 /* TBD: no stats support in firmware yet */ 607 _NOTE(ARGUNUSED(enp, esmp)) 608 memset(stat, 0, EFX_PHY_NSTATS * sizeof (*stat)); 609 610 return (0); 611 } 612 613 #endif /* EFSYS_OPT_PHY_STATS */ 614 615 #if EFSYS_OPT_BIST 616 617 __checkReturn efx_rc_t 618 ef10_bist_enable_offline( 619 __in efx_nic_t *enp) 620 { 621 efx_rc_t rc; 622 623 if ((rc = efx_mcdi_bist_enable_offline(enp)) != 0) 624 goto fail1; 625 626 return (0); 627 628 fail1: 629 EFSYS_PROBE1(fail1, efx_rc_t, rc); 630 631 return (rc); 632 } 633 634 __checkReturn efx_rc_t 635 ef10_bist_start( 636 __in efx_nic_t *enp, 637 __in efx_bist_type_t type) 638 { 639 efx_rc_t rc; 640 641 if ((rc = efx_mcdi_bist_start(enp, type)) != 0) 642 goto fail1; 643 644 return (0); 645 646 fail1: 647 EFSYS_PROBE1(fail1, efx_rc_t, rc); 648 649 return (rc); 650 } 651 652 __checkReturn efx_rc_t 653 ef10_bist_poll( 654 __in efx_nic_t *enp, 655 __in efx_bist_type_t type, 656 __out efx_bist_result_t *resultp, 657 __out_opt __drv_when(count > 0, __notnull) 658 uint32_t *value_maskp, 659 __out_ecount_opt(count) __drv_when(count > 0, __notnull) 660 unsigned long *valuesp, 661 __in size_t count) 662 { 663 /* 664 * MCDI_CTL_SDU_LEN_MAX_V1 is large enough cover all BIST results, 665 * whilst not wasting stack. 666 */ 667 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_POLL_BIST_IN_LEN, 668 MCDI_CTL_SDU_LEN_MAX_V1); 669 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 670 efx_mcdi_req_t req; 671 uint32_t value_mask = 0; 672 uint32_t result; 673 efx_rc_t rc; 674 675 EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_LEN <= 676 MCDI_CTL_SDU_LEN_MAX_V1); 677 EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_SFT9001_LEN <= 678 MCDI_CTL_SDU_LEN_MAX_V1); 679 EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_MRSFP_LEN <= 680 MCDI_CTL_SDU_LEN_MAX_V1); 681 EFX_STATIC_ASSERT(MC_CMD_POLL_BIST_OUT_MEM_LEN <= 682 MCDI_CTL_SDU_LEN_MAX_V1); 683 684 _NOTE(ARGUNUSED(type)) 685 686 req.emr_cmd = MC_CMD_POLL_BIST; 687 req.emr_in_buf = payload; 688 req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN; 689 req.emr_out_buf = payload; 690 req.emr_out_length = MCDI_CTL_SDU_LEN_MAX_V1; 691 692 efx_mcdi_execute(enp, &req); 693 694 if (req.emr_rc != 0) { 695 rc = req.emr_rc; 696 goto fail1; 697 } 698 699 if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) { 700 rc = EMSGSIZE; 701 goto fail2; 702 } 703 704 if (count > 0) 705 (void) memset(valuesp, '\0', count * sizeof (unsigned long)); 706 707 result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT); 708 709 if (result == MC_CMD_POLL_BIST_FAILED && 710 req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MEM_LEN && 711 count > EFX_BIST_MEM_ECC_FATAL) { 712 if (valuesp != NULL) { 713 valuesp[EFX_BIST_MEM_TEST] = 714 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_TEST); 715 valuesp[EFX_BIST_MEM_ADDR] = 716 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ADDR); 717 valuesp[EFX_BIST_MEM_BUS] = 718 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_BUS); 719 valuesp[EFX_BIST_MEM_EXPECT] = 720 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_EXPECT); 721 valuesp[EFX_BIST_MEM_ACTUAL] = 722 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ACTUAL); 723 valuesp[EFX_BIST_MEM_ECC] = 724 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC); 725 valuesp[EFX_BIST_MEM_ECC_PARITY] = 726 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_PARITY); 727 valuesp[EFX_BIST_MEM_ECC_FATAL] = 728 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MEM_ECC_FATAL); 729 } 730 value_mask |= (1 << EFX_BIST_MEM_TEST) | 731 (1 << EFX_BIST_MEM_ADDR) | 732 (1 << EFX_BIST_MEM_BUS) | 733 (1 << EFX_BIST_MEM_EXPECT) | 734 (1 << EFX_BIST_MEM_ACTUAL) | 735 (1 << EFX_BIST_MEM_ECC) | 736 (1 << EFX_BIST_MEM_ECC_PARITY) | 737 (1 << EFX_BIST_MEM_ECC_FATAL); 738 } else if (result == MC_CMD_POLL_BIST_FAILED && 739 encp->enc_phy_type == EFX_PHY_XFI_FARMI && 740 req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN && 741 count > EFX_BIST_FAULT_CODE) { 742 if (valuesp != NULL) 743 valuesp[EFX_BIST_FAULT_CODE] = 744 MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST); 745 value_mask |= 1 << EFX_BIST_FAULT_CODE; 746 } 747 748 if (value_maskp != NULL) 749 *value_maskp = value_mask; 750 751 EFSYS_ASSERT(resultp != NULL); 752 if (result == MC_CMD_POLL_BIST_RUNNING) 753 *resultp = EFX_BIST_RESULT_RUNNING; 754 else if (result == MC_CMD_POLL_BIST_PASSED) 755 *resultp = EFX_BIST_RESULT_PASSED; 756 else 757 *resultp = EFX_BIST_RESULT_FAILED; 758 759 return (0); 760 761 fail2: 762 EFSYS_PROBE(fail2); 763 fail1: 764 EFSYS_PROBE1(fail1, efx_rc_t, rc); 765 766 return (rc); 767 } 768 769 void 770 ef10_bist_stop( 771 __in efx_nic_t *enp, 772 __in efx_bist_type_t type) 773 { 774 /* There is no way to stop BIST on EF10. */ 775 _NOTE(ARGUNUSED(enp, type)) 776 } 777 778 #endif /* EFSYS_OPT_BIST */ 779 780 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 781