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