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