1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2008-2016 Solarflare Communications Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright notice, 11 * this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * The views and conclusions contained in the software and documentation are 29 * those of the authors and should not be interpreted as representing official 30 * policies, either expressed or implied, of the FreeBSD Project. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include "efx.h" 37 #include "efx_impl.h" 38 39 #if EFSYS_OPT_MCDI 40 41 /* 42 * There are three versions of the MCDI interface: 43 * - MCDIv0: Siena BootROM. Transport uses MCDIv1 headers. 44 * - MCDIv1: Siena firmware and Huntington BootROM. 45 * - MCDIv2: EF10 firmware (Huntington/Medford) and Medford BootROM. 46 * Transport uses MCDIv2 headers. 47 * 48 * MCDIv2 Header NOT_EPOCH flag 49 * ---------------------------- 50 * A new epoch begins at initial startup or after an MC reboot, and defines when 51 * the MC should reject stale MCDI requests. 52 * 53 * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all 54 * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1. 55 * 56 * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a 57 * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0. 58 */ 59 60 #if EFSYS_OPT_SIENA 61 62 static const efx_mcdi_ops_t __efx_mcdi_siena_ops = { 63 siena_mcdi_init, /* emco_init */ 64 siena_mcdi_send_request, /* emco_send_request */ 65 siena_mcdi_poll_reboot, /* emco_poll_reboot */ 66 siena_mcdi_poll_response, /* emco_poll_response */ 67 siena_mcdi_read_response, /* emco_read_response */ 68 siena_mcdi_fini, /* emco_fini */ 69 siena_mcdi_feature_supported, /* emco_feature_supported */ 70 siena_mcdi_get_timeout, /* emco_get_timeout */ 71 }; 72 73 #endif /* EFSYS_OPT_SIENA */ 74 75 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 76 77 static const efx_mcdi_ops_t __efx_mcdi_ef10_ops = { 78 ef10_mcdi_init, /* emco_init */ 79 ef10_mcdi_send_request, /* emco_send_request */ 80 ef10_mcdi_poll_reboot, /* emco_poll_reboot */ 81 ef10_mcdi_poll_response, /* emco_poll_response */ 82 ef10_mcdi_read_response, /* emco_read_response */ 83 ef10_mcdi_fini, /* emco_fini */ 84 ef10_mcdi_feature_supported, /* emco_feature_supported */ 85 ef10_mcdi_get_timeout, /* emco_get_timeout */ 86 }; 87 88 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 89 90 __checkReturn efx_rc_t 91 efx_mcdi_init( 92 __in efx_nic_t *enp, 93 __in const efx_mcdi_transport_t *emtp) 94 { 95 const efx_mcdi_ops_t *emcop; 96 efx_rc_t rc; 97 98 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 99 EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); 100 101 switch (enp->en_family) { 102 #if EFSYS_OPT_SIENA 103 case EFX_FAMILY_SIENA: 104 emcop = &__efx_mcdi_siena_ops; 105 break; 106 #endif /* EFSYS_OPT_SIENA */ 107 108 #if EFSYS_OPT_HUNTINGTON 109 case EFX_FAMILY_HUNTINGTON: 110 emcop = &__efx_mcdi_ef10_ops; 111 break; 112 #endif /* EFSYS_OPT_HUNTINGTON */ 113 114 #if EFSYS_OPT_MEDFORD 115 case EFX_FAMILY_MEDFORD: 116 emcop = &__efx_mcdi_ef10_ops; 117 break; 118 #endif /* EFSYS_OPT_MEDFORD */ 119 120 #if EFSYS_OPT_MEDFORD2 121 case EFX_FAMILY_MEDFORD2: 122 emcop = &__efx_mcdi_ef10_ops; 123 break; 124 #endif /* EFSYS_OPT_MEDFORD2 */ 125 126 default: 127 EFSYS_ASSERT(0); 128 rc = ENOTSUP; 129 goto fail1; 130 } 131 132 if (enp->en_features & EFX_FEATURE_MCDI_DMA) { 133 /* MCDI requires a DMA buffer in host memory */ 134 if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) { 135 rc = EINVAL; 136 goto fail2; 137 } 138 } 139 enp->en_mcdi.em_emtp = emtp; 140 141 if (emcop != NULL && emcop->emco_init != NULL) { 142 if ((rc = emcop->emco_init(enp, emtp)) != 0) 143 goto fail3; 144 } 145 146 enp->en_mcdi.em_emcop = emcop; 147 enp->en_mod_flags |= EFX_MOD_MCDI; 148 149 return (0); 150 151 fail3: 152 EFSYS_PROBE(fail3); 153 fail2: 154 EFSYS_PROBE(fail2); 155 fail1: 156 EFSYS_PROBE1(fail1, efx_rc_t, rc); 157 158 enp->en_mcdi.em_emcop = NULL; 159 enp->en_mcdi.em_emtp = NULL; 160 enp->en_mod_flags &= ~EFX_MOD_MCDI; 161 162 return (rc); 163 } 164 165 void 166 efx_mcdi_fini( 167 __in efx_nic_t *enp) 168 { 169 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 170 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 171 172 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 173 EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI); 174 175 if (emcop != NULL && emcop->emco_fini != NULL) 176 emcop->emco_fini(enp); 177 178 emip->emi_port = 0; 179 emip->emi_aborted = 0; 180 181 enp->en_mcdi.em_emcop = NULL; 182 enp->en_mod_flags &= ~EFX_MOD_MCDI; 183 } 184 185 void 186 efx_mcdi_new_epoch( 187 __in efx_nic_t *enp) 188 { 189 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 190 efsys_lock_state_t state; 191 192 /* Start a new epoch (allow fresh MCDI requests to succeed) */ 193 EFSYS_LOCK(enp->en_eslp, state); 194 emip->emi_new_epoch = B_TRUE; 195 EFSYS_UNLOCK(enp->en_eslp, state); 196 } 197 198 static void 199 efx_mcdi_send_request( 200 __in efx_nic_t *enp, 201 __in void *hdrp, 202 __in size_t hdr_len, 203 __in void *sdup, 204 __in size_t sdu_len) 205 { 206 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 207 208 emcop->emco_send_request(enp, hdrp, hdr_len, sdup, sdu_len); 209 } 210 211 static efx_rc_t 212 efx_mcdi_poll_reboot( 213 __in efx_nic_t *enp) 214 { 215 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 216 efx_rc_t rc; 217 218 rc = emcop->emco_poll_reboot(enp); 219 return (rc); 220 } 221 222 static boolean_t 223 efx_mcdi_poll_response( 224 __in efx_nic_t *enp) 225 { 226 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 227 boolean_t available; 228 229 available = emcop->emco_poll_response(enp); 230 return (available); 231 } 232 233 static void 234 efx_mcdi_read_response( 235 __in efx_nic_t *enp, 236 __out void *bufferp, 237 __in size_t offset, 238 __in size_t length) 239 { 240 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 241 242 emcop->emco_read_response(enp, bufferp, offset, length); 243 } 244 245 void 246 efx_mcdi_request_start( 247 __in efx_nic_t *enp, 248 __in efx_mcdi_req_t *emrp, 249 __in boolean_t ev_cpl) 250 { 251 #if EFSYS_OPT_MCDI_LOGGING 252 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 253 #endif 254 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 255 efx_dword_t hdr[2]; 256 size_t hdr_len; 257 unsigned int max_version; 258 unsigned int seq; 259 unsigned int xflags; 260 boolean_t new_epoch; 261 efsys_lock_state_t state; 262 263 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 264 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 265 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 266 267 /* 268 * efx_mcdi_request_start() is naturally serialised against both 269 * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(), 270 * by virtue of there only being one outstanding MCDI request. 271 * Unfortunately, upper layers may also call efx_mcdi_request_abort() 272 * at any time, to timeout a pending mcdi request, That request may 273 * then subsequently complete, meaning efx_mcdi_ev_cpl() or 274 * efx_mcdi_ev_death() may end up running in parallel with 275 * efx_mcdi_request_start(). This race is handled by ensuring that 276 * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the 277 * en_eslp lock. 278 */ 279 EFSYS_LOCK(enp->en_eslp, state); 280 EFSYS_ASSERT(emip->emi_pending_req == NULL); 281 emip->emi_pending_req = emrp; 282 emip->emi_ev_cpl = ev_cpl; 283 emip->emi_poll_cnt = 0; 284 seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ); 285 new_epoch = emip->emi_new_epoch; 286 max_version = emip->emi_max_version; 287 EFSYS_UNLOCK(enp->en_eslp, state); 288 289 xflags = 0; 290 if (ev_cpl) 291 xflags |= MCDI_HEADER_XFLAGS_EVREQ; 292 293 /* 294 * Huntington firmware supports MCDIv2, but the Huntington BootROM only 295 * supports MCDIv1. Use MCDIv1 headers for MCDIv1 commands where 296 * possible to support this. 297 */ 298 if ((max_version >= 2) && 299 ((emrp->emr_cmd > MC_CMD_CMD_SPACE_ESCAPE_7) || 300 (emrp->emr_in_length > MCDI_CTL_SDU_LEN_MAX_V1) || 301 (emrp->emr_out_length > MCDI_CTL_SDU_LEN_MAX_V1))) { 302 /* Construct MCDI v2 header */ 303 hdr_len = sizeof (hdr); 304 EFX_POPULATE_DWORD_8(hdr[0], 305 MCDI_HEADER_CODE, MC_CMD_V2_EXTN, 306 MCDI_HEADER_RESYNC, 1, 307 MCDI_HEADER_DATALEN, 0, 308 MCDI_HEADER_SEQ, seq, 309 MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, 310 MCDI_HEADER_ERROR, 0, 311 MCDI_HEADER_RESPONSE, 0, 312 MCDI_HEADER_XFLAGS, xflags); 313 314 EFX_POPULATE_DWORD_2(hdr[1], 315 MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd, 316 MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length); 317 } else { 318 /* Construct MCDI v1 header */ 319 hdr_len = sizeof (hdr[0]); 320 EFX_POPULATE_DWORD_8(hdr[0], 321 MCDI_HEADER_CODE, emrp->emr_cmd, 322 MCDI_HEADER_RESYNC, 1, 323 MCDI_HEADER_DATALEN, emrp->emr_in_length, 324 MCDI_HEADER_SEQ, seq, 325 MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, 326 MCDI_HEADER_ERROR, 0, 327 MCDI_HEADER_RESPONSE, 0, 328 MCDI_HEADER_XFLAGS, xflags); 329 } 330 331 #if EFSYS_OPT_MCDI_LOGGING 332 if (emtp->emt_logger != NULL) { 333 emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST, 334 &hdr, hdr_len, 335 emrp->emr_in_buf, emrp->emr_in_length); 336 } 337 #endif /* EFSYS_OPT_MCDI_LOGGING */ 338 339 efx_mcdi_send_request(enp, &hdr[0], hdr_len, 340 emrp->emr_in_buf, emrp->emr_in_length); 341 } 342 343 static void 344 efx_mcdi_read_response_header( 345 __in efx_nic_t *enp, 346 __inout efx_mcdi_req_t *emrp) 347 { 348 #if EFSYS_OPT_MCDI_LOGGING 349 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 350 #endif /* EFSYS_OPT_MCDI_LOGGING */ 351 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 352 efx_dword_t hdr[2]; 353 unsigned int hdr_len; 354 unsigned int data_len; 355 unsigned int seq; 356 unsigned int cmd; 357 unsigned int error; 358 efx_rc_t rc; 359 360 EFSYS_ASSERT(emrp != NULL); 361 362 efx_mcdi_read_response(enp, &hdr[0], 0, sizeof (hdr[0])); 363 hdr_len = sizeof (hdr[0]); 364 365 cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE); 366 seq = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ); 367 error = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR); 368 369 if (cmd != MC_CMD_V2_EXTN) { 370 data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN); 371 } else { 372 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1])); 373 hdr_len += sizeof (hdr[1]); 374 375 cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD); 376 data_len = 377 EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN); 378 } 379 380 if (error && (data_len == 0)) { 381 /* The MC has rebooted since the request was sent. */ 382 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US); 383 efx_mcdi_poll_reboot(enp); 384 rc = EIO; 385 goto fail1; 386 } 387 if ((cmd != emrp->emr_cmd) || 388 (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) { 389 /* Response is for a different request */ 390 rc = EIO; 391 goto fail2; 392 } 393 if (error) { 394 efx_dword_t err[2]; 395 unsigned int err_len = MIN(data_len, sizeof (err)); 396 int err_code = MC_CMD_ERR_EPROTO; 397 int err_arg = 0; 398 399 /* Read error code (and arg num for MCDI v2 commands) */ 400 efx_mcdi_read_response(enp, &err, hdr_len, err_len); 401 402 if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t))) 403 err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0); 404 #ifdef WITH_MCDI_V2 405 if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t))) 406 err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0); 407 #endif 408 emrp->emr_err_code = err_code; 409 emrp->emr_err_arg = err_arg; 410 411 #if EFSYS_OPT_MCDI_PROXY_AUTH 412 if ((err_code == MC_CMD_ERR_PROXY_PENDING) && 413 (err_len == sizeof (err))) { 414 /* 415 * The MCDI request would normally fail with EPERM, but 416 * firmware has forwarded it to an authorization agent 417 * attached to a privileged PF. 418 * 419 * Save the authorization request handle. The client 420 * must wait for a PROXY_RESPONSE event, or timeout. 421 */ 422 emrp->emr_proxy_handle = err_arg; 423 } 424 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ 425 426 #if EFSYS_OPT_MCDI_LOGGING 427 if (emtp->emt_logger != NULL) { 428 emtp->emt_logger(emtp->emt_context, 429 EFX_LOG_MCDI_RESPONSE, 430 &hdr, hdr_len, 431 &err, err_len); 432 } 433 #endif /* EFSYS_OPT_MCDI_LOGGING */ 434 435 if (!emrp->emr_quiet) { 436 EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd, 437 int, err_code, int, err_arg); 438 } 439 440 rc = efx_mcdi_request_errcode(err_code); 441 goto fail3; 442 } 443 444 emrp->emr_rc = 0; 445 emrp->emr_out_length_used = data_len; 446 #if EFSYS_OPT_MCDI_PROXY_AUTH 447 emrp->emr_proxy_handle = 0; 448 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ 449 return; 450 451 fail3: 452 fail2: 453 fail1: 454 emrp->emr_rc = rc; 455 emrp->emr_out_length_used = 0; 456 } 457 458 static void 459 efx_mcdi_finish_response( 460 __in efx_nic_t *enp, 461 __in efx_mcdi_req_t *emrp) 462 { 463 #if EFSYS_OPT_MCDI_LOGGING 464 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 465 #endif /* EFSYS_OPT_MCDI_LOGGING */ 466 efx_dword_t hdr[2]; 467 unsigned int hdr_len; 468 size_t bytes; 469 470 if (emrp->emr_out_buf == NULL) 471 return; 472 473 /* Read the command header to detect MCDI response format */ 474 hdr_len = sizeof (hdr[0]); 475 efx_mcdi_read_response(enp, &hdr[0], 0, hdr_len); 476 if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) { 477 /* 478 * Read the actual payload length. The length given in the event 479 * is only correct for responses with the V1 format. 480 */ 481 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1])); 482 hdr_len += sizeof (hdr[1]); 483 484 emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1], 485 MC_CMD_V2_EXTN_IN_ACTUAL_LEN); 486 } 487 488 /* Copy payload out into caller supplied buffer */ 489 bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length); 490 efx_mcdi_read_response(enp, emrp->emr_out_buf, hdr_len, bytes); 491 492 #if EFSYS_OPT_MCDI_LOGGING 493 if (emtp->emt_logger != NULL) { 494 emtp->emt_logger(emtp->emt_context, 495 EFX_LOG_MCDI_RESPONSE, 496 &hdr, hdr_len, 497 emrp->emr_out_buf, bytes); 498 } 499 #endif /* EFSYS_OPT_MCDI_LOGGING */ 500 } 501 502 __checkReturn boolean_t 503 efx_mcdi_request_poll( 504 __in efx_nic_t *enp) 505 { 506 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 507 efx_mcdi_req_t *emrp; 508 efsys_lock_state_t state; 509 efx_rc_t rc; 510 511 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 512 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 513 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 514 515 /* Serialise against post-watchdog efx_mcdi_ev* */ 516 EFSYS_LOCK(enp->en_eslp, state); 517 518 EFSYS_ASSERT(emip->emi_pending_req != NULL); 519 EFSYS_ASSERT(!emip->emi_ev_cpl); 520 emrp = emip->emi_pending_req; 521 522 /* Check if hardware is unavailable */ 523 if (efx_nic_hw_unavailable(enp)) { 524 EFSYS_UNLOCK(enp->en_eslp, state); 525 return (B_FALSE); 526 } 527 528 /* Check for reboot atomically w.r.t efx_mcdi_request_start */ 529 if (emip->emi_poll_cnt++ == 0) { 530 if ((rc = efx_mcdi_poll_reboot(enp)) != 0) { 531 emip->emi_pending_req = NULL; 532 EFSYS_UNLOCK(enp->en_eslp, state); 533 534 /* Reboot/Assertion */ 535 if (rc == EIO || rc == EINTR) 536 efx_mcdi_raise_exception(enp, emrp, rc); 537 538 goto fail1; 539 } 540 } 541 542 /* Check if a response is available */ 543 if (efx_mcdi_poll_response(enp) == B_FALSE) { 544 EFSYS_UNLOCK(enp->en_eslp, state); 545 return (B_FALSE); 546 } 547 548 /* Read the response header */ 549 efx_mcdi_read_response_header(enp, emrp); 550 551 /* Request complete */ 552 emip->emi_pending_req = NULL; 553 554 /* Ensure stale MCDI requests fail after an MC reboot. */ 555 emip->emi_new_epoch = B_FALSE; 556 557 EFSYS_UNLOCK(enp->en_eslp, state); 558 559 if ((rc = emrp->emr_rc) != 0) 560 goto fail2; 561 562 efx_mcdi_finish_response(enp, emrp); 563 return (B_TRUE); 564 565 fail2: 566 if (!emrp->emr_quiet) 567 EFSYS_PROBE(fail2); 568 fail1: 569 if (!emrp->emr_quiet) 570 EFSYS_PROBE1(fail1, efx_rc_t, rc); 571 572 return (B_TRUE); 573 } 574 575 __checkReturn boolean_t 576 efx_mcdi_request_abort( 577 __in efx_nic_t *enp) 578 { 579 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 580 efx_mcdi_req_t *emrp; 581 boolean_t aborted; 582 efsys_lock_state_t state; 583 584 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 585 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 586 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 587 588 /* 589 * efx_mcdi_ev_* may have already completed this event, and be 590 * spinning/blocked on the upper layer lock. So it *is* legitimate 591 * to for emi_pending_req to be NULL. If there is a pending event 592 * completed request, then provide a "credit" to allow 593 * efx_mcdi_ev_cpl() to accept a single spurious completion. 594 */ 595 EFSYS_LOCK(enp->en_eslp, state); 596 emrp = emip->emi_pending_req; 597 aborted = (emrp != NULL); 598 if (aborted) { 599 emip->emi_pending_req = NULL; 600 601 /* Error the request */ 602 emrp->emr_out_length_used = 0; 603 emrp->emr_rc = ETIMEDOUT; 604 605 /* Provide a credit for seqno/emr_pending_req mismatches */ 606 if (emip->emi_ev_cpl) 607 ++emip->emi_aborted; 608 609 /* 610 * The upper layer has called us, so we don't 611 * need to complete the request. 612 */ 613 } 614 EFSYS_UNLOCK(enp->en_eslp, state); 615 616 return (aborted); 617 } 618 619 void 620 efx_mcdi_get_timeout( 621 __in efx_nic_t *enp, 622 __in efx_mcdi_req_t *emrp, 623 __out uint32_t *timeoutp) 624 { 625 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 626 627 emcop->emco_get_timeout(enp, emrp, timeoutp); 628 } 629 630 __checkReturn efx_rc_t 631 efx_mcdi_request_errcode( 632 __in unsigned int err) 633 { 634 635 switch (err) { 636 /* MCDI v1 */ 637 case MC_CMD_ERR_EPERM: 638 return (EACCES); 639 case MC_CMD_ERR_ENOENT: 640 return (ENOENT); 641 case MC_CMD_ERR_EINTR: 642 return (EINTR); 643 case MC_CMD_ERR_EACCES: 644 return (EACCES); 645 case MC_CMD_ERR_EBUSY: 646 return (EBUSY); 647 case MC_CMD_ERR_EINVAL: 648 return (EINVAL); 649 case MC_CMD_ERR_EDEADLK: 650 return (EDEADLK); 651 case MC_CMD_ERR_ENOSYS: 652 return (ENOTSUP); 653 case MC_CMD_ERR_ETIME: 654 return (ETIMEDOUT); 655 case MC_CMD_ERR_ENOTSUP: 656 return (ENOTSUP); 657 case MC_CMD_ERR_EALREADY: 658 return (EALREADY); 659 660 /* MCDI v2 */ 661 case MC_CMD_ERR_EEXIST: 662 return (EEXIST); 663 #ifdef MC_CMD_ERR_EAGAIN 664 case MC_CMD_ERR_EAGAIN: 665 return (EAGAIN); 666 #endif 667 #ifdef MC_CMD_ERR_ENOSPC 668 case MC_CMD_ERR_ENOSPC: 669 return (ENOSPC); 670 #endif 671 case MC_CMD_ERR_ERANGE: 672 return (ERANGE); 673 674 case MC_CMD_ERR_ALLOC_FAIL: 675 return (ENOMEM); 676 case MC_CMD_ERR_NO_VADAPTOR: 677 return (ENOENT); 678 case MC_CMD_ERR_NO_EVB_PORT: 679 return (ENOENT); 680 case MC_CMD_ERR_NO_VSWITCH: 681 return (ENODEV); 682 case MC_CMD_ERR_VLAN_LIMIT: 683 return (EINVAL); 684 case MC_CMD_ERR_BAD_PCI_FUNC: 685 return (ENODEV); 686 case MC_CMD_ERR_BAD_VLAN_MODE: 687 return (EINVAL); 688 case MC_CMD_ERR_BAD_VSWITCH_TYPE: 689 return (EINVAL); 690 case MC_CMD_ERR_BAD_VPORT_TYPE: 691 return (EINVAL); 692 case MC_CMD_ERR_MAC_EXIST: 693 return (EEXIST); 694 695 case MC_CMD_ERR_PROXY_PENDING: 696 return (EAGAIN); 697 698 default: 699 EFSYS_PROBE1(mc_pcol_error, int, err); 700 return (EIO); 701 } 702 } 703 704 void 705 efx_mcdi_raise_exception( 706 __in efx_nic_t *enp, 707 __in_opt efx_mcdi_req_t *emrp, 708 __in int rc) 709 { 710 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 711 efx_mcdi_exception_t exception; 712 713 /* Reboot or Assertion failure only */ 714 EFSYS_ASSERT(rc == EIO || rc == EINTR); 715 716 /* 717 * If MC_CMD_REBOOT causes a reboot (dependent on parameters), 718 * then the EIO is not worthy of an exception. 719 */ 720 if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO) 721 return; 722 723 exception = (rc == EIO) 724 ? EFX_MCDI_EXCEPTION_MC_REBOOT 725 : EFX_MCDI_EXCEPTION_MC_BADASSERT; 726 727 emtp->emt_exception(emtp->emt_context, exception); 728 } 729 730 void 731 efx_mcdi_execute( 732 __in efx_nic_t *enp, 733 __inout efx_mcdi_req_t *emrp) 734 { 735 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 736 737 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 738 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 739 740 emrp->emr_quiet = B_FALSE; 741 emtp->emt_execute(emtp->emt_context, emrp); 742 } 743 744 void 745 efx_mcdi_execute_quiet( 746 __in efx_nic_t *enp, 747 __inout efx_mcdi_req_t *emrp) 748 { 749 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 750 751 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 752 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 753 754 emrp->emr_quiet = B_TRUE; 755 emtp->emt_execute(emtp->emt_context, emrp); 756 } 757 758 void 759 efx_mcdi_ev_cpl( 760 __in efx_nic_t *enp, 761 __in unsigned int seq, 762 __in unsigned int outlen, 763 __in int errcode) 764 { 765 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 766 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 767 efx_mcdi_req_t *emrp; 768 efsys_lock_state_t state; 769 770 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 771 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 772 773 /* 774 * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start() 775 * when we're completing an aborted request. 776 */ 777 EFSYS_LOCK(enp->en_eslp, state); 778 if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl || 779 (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) { 780 EFSYS_ASSERT(emip->emi_aborted > 0); 781 if (emip->emi_aborted > 0) 782 --emip->emi_aborted; 783 EFSYS_UNLOCK(enp->en_eslp, state); 784 return; 785 } 786 787 emrp = emip->emi_pending_req; 788 emip->emi_pending_req = NULL; 789 EFSYS_UNLOCK(enp->en_eslp, state); 790 791 if (emip->emi_max_version >= 2) { 792 /* MCDIv2 response details do not fit into an event. */ 793 efx_mcdi_read_response_header(enp, emrp); 794 } else { 795 if (errcode != 0) { 796 if (!emrp->emr_quiet) { 797 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd, 798 int, errcode); 799 } 800 emrp->emr_out_length_used = 0; 801 emrp->emr_rc = efx_mcdi_request_errcode(errcode); 802 } else { 803 emrp->emr_out_length_used = outlen; 804 emrp->emr_rc = 0; 805 } 806 } 807 if (emrp->emr_rc == 0) 808 efx_mcdi_finish_response(enp, emrp); 809 810 emtp->emt_ev_cpl(emtp->emt_context); 811 } 812 813 #if EFSYS_OPT_MCDI_PROXY_AUTH 814 815 __checkReturn efx_rc_t 816 efx_mcdi_get_proxy_handle( 817 __in efx_nic_t *enp, 818 __in efx_mcdi_req_t *emrp, 819 __out uint32_t *handlep) 820 { 821 efx_rc_t rc; 822 823 _NOTE(ARGUNUSED(enp)) 824 825 /* 826 * Return proxy handle from MCDI request that returned with error 827 * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching 828 * PROXY_RESPONSE event. 829 */ 830 if ((emrp == NULL) || (handlep == NULL)) { 831 rc = EINVAL; 832 goto fail1; 833 } 834 if ((emrp->emr_rc != 0) && 835 (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) { 836 *handlep = emrp->emr_proxy_handle; 837 rc = 0; 838 } else { 839 *handlep = 0; 840 rc = ENOENT; 841 } 842 return (rc); 843 844 fail1: 845 EFSYS_PROBE1(fail1, efx_rc_t, rc); 846 return (rc); 847 } 848 849 void 850 efx_mcdi_ev_proxy_response( 851 __in efx_nic_t *enp, 852 __in unsigned int handle, 853 __in unsigned int status) 854 { 855 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 856 efx_rc_t rc; 857 858 /* 859 * Handle results of an authorization request for a privileged MCDI 860 * command. If authorization was granted then we must re-issue the 861 * original MCDI request. If authorization failed or timed out, 862 * then the original MCDI request should be completed with the 863 * result code from this event. 864 */ 865 rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status); 866 867 emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc); 868 } 869 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ 870 871 void 872 efx_mcdi_ev_death( 873 __in efx_nic_t *enp, 874 __in int rc) 875 { 876 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 877 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 878 efx_mcdi_req_t *emrp = NULL; 879 boolean_t ev_cpl; 880 efsys_lock_state_t state; 881 882 /* 883 * The MCDI request (if there is one) has been terminated, either 884 * by a BADASSERT or REBOOT event. 885 * 886 * If there is an outstanding event-completed MCDI operation, then we 887 * will never receive the completion event (because both MCDI 888 * completions and BADASSERT events are sent to the same evq). So 889 * complete this MCDI op. 890 * 891 * This function might run in parallel with efx_mcdi_request_poll() 892 * for poll completed mcdi requests, and also with 893 * efx_mcdi_request_start() for post-watchdog completions. 894 */ 895 EFSYS_LOCK(enp->en_eslp, state); 896 emrp = emip->emi_pending_req; 897 ev_cpl = emip->emi_ev_cpl; 898 if (emrp != NULL && emip->emi_ev_cpl) { 899 emip->emi_pending_req = NULL; 900 901 emrp->emr_out_length_used = 0; 902 emrp->emr_rc = rc; 903 ++emip->emi_aborted; 904 } 905 906 /* 907 * Since we're running in parallel with a request, consume the 908 * status word before dropping the lock. 909 */ 910 if (rc == EIO || rc == EINTR) { 911 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US); 912 (void) efx_mcdi_poll_reboot(enp); 913 emip->emi_new_epoch = B_TRUE; 914 } 915 916 EFSYS_UNLOCK(enp->en_eslp, state); 917 918 efx_mcdi_raise_exception(enp, emrp, rc); 919 920 if (emrp != NULL && ev_cpl) 921 emtp->emt_ev_cpl(emtp->emt_context); 922 } 923 924 __checkReturn efx_rc_t 925 efx_mcdi_version( 926 __in efx_nic_t *enp, 927 __out_ecount_opt(4) uint16_t versionp[4], 928 __out_opt uint32_t *buildp, 929 __out_opt efx_mcdi_boot_t *statusp) 930 { 931 efx_mcdi_req_t req; 932 EFX_MCDI_DECLARE_BUF(payload, 933 MAX(MC_CMD_GET_VERSION_IN_LEN, MC_CMD_GET_BOOT_STATUS_IN_LEN), 934 MAX(MC_CMD_GET_VERSION_OUT_LEN, 935 MC_CMD_GET_BOOT_STATUS_OUT_LEN)); 936 efx_word_t *ver_words; 937 uint16_t version[4]; 938 uint32_t build; 939 efx_mcdi_boot_t status; 940 efx_rc_t rc; 941 942 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 943 944 req.emr_cmd = MC_CMD_GET_VERSION; 945 req.emr_in_buf = payload; 946 req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN; 947 req.emr_out_buf = payload; 948 req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN; 949 950 efx_mcdi_execute(enp, &req); 951 952 if (req.emr_rc != 0) { 953 rc = req.emr_rc; 954 goto fail1; 955 } 956 957 /* bootrom support */ 958 if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) { 959 version[0] = version[1] = version[2] = version[3] = 0; 960 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 961 962 goto version; 963 } 964 965 if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) { 966 rc = EMSGSIZE; 967 goto fail2; 968 } 969 970 ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION); 971 version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0); 972 version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0); 973 version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0); 974 version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0); 975 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 976 977 version: 978 /* The bootrom doesn't understand BOOT_STATUS */ 979 if (MC_FW_VERSION_IS_BOOTLOADER(build)) { 980 status = EFX_MCDI_BOOT_ROM; 981 goto out; 982 } 983 984 (void) memset(payload, 0, sizeof (payload)); 985 req.emr_cmd = MC_CMD_GET_BOOT_STATUS; 986 req.emr_in_buf = payload; 987 req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN; 988 req.emr_out_buf = payload; 989 req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN; 990 991 efx_mcdi_execute_quiet(enp, &req); 992 993 if (req.emr_rc == EACCES) { 994 /* Unprivileged functions cannot access BOOT_STATUS */ 995 status = EFX_MCDI_BOOT_PRIMARY; 996 version[0] = version[1] = version[2] = version[3] = 0; 997 build = 0; 998 goto out; 999 } 1000 1001 if (req.emr_rc != 0) { 1002 rc = req.emr_rc; 1003 goto fail3; 1004 } 1005 1006 if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) { 1007 rc = EMSGSIZE; 1008 goto fail4; 1009 } 1010 1011 if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS, 1012 GET_BOOT_STATUS_OUT_FLAGS_PRIMARY)) 1013 status = EFX_MCDI_BOOT_PRIMARY; 1014 else 1015 status = EFX_MCDI_BOOT_SECONDARY; 1016 1017 out: 1018 if (versionp != NULL) 1019 memcpy(versionp, version, sizeof (version)); 1020 if (buildp != NULL) 1021 *buildp = build; 1022 if (statusp != NULL) 1023 *statusp = status; 1024 1025 return (0); 1026 1027 fail4: 1028 EFSYS_PROBE(fail4); 1029 fail3: 1030 EFSYS_PROBE(fail3); 1031 fail2: 1032 EFSYS_PROBE(fail2); 1033 fail1: 1034 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1035 1036 return (rc); 1037 } 1038 1039 __checkReturn efx_rc_t 1040 efx_mcdi_get_capabilities( 1041 __in efx_nic_t *enp, 1042 __out_opt uint32_t *flagsp, 1043 __out_opt uint16_t *rx_dpcpu_fw_idp, 1044 __out_opt uint16_t *tx_dpcpu_fw_idp, 1045 __out_opt uint32_t *flags2p, 1046 __out_opt uint32_t *tso2ncp) 1047 { 1048 efx_mcdi_req_t req; 1049 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_CAPABILITIES_IN_LEN, 1050 MC_CMD_GET_CAPABILITIES_V2_OUT_LEN); 1051 boolean_t v2_capable; 1052 efx_rc_t rc; 1053 1054 req.emr_cmd = MC_CMD_GET_CAPABILITIES; 1055 req.emr_in_buf = payload; 1056 req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN; 1057 req.emr_out_buf = payload; 1058 req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_OUT_LEN; 1059 1060 efx_mcdi_execute_quiet(enp, &req); 1061 1062 if (req.emr_rc != 0) { 1063 rc = req.emr_rc; 1064 goto fail1; 1065 } 1066 1067 if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) { 1068 rc = EMSGSIZE; 1069 goto fail2; 1070 } 1071 1072 if (flagsp != NULL) 1073 *flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1); 1074 1075 if (rx_dpcpu_fw_idp != NULL) 1076 *rx_dpcpu_fw_idp = MCDI_OUT_WORD(req, 1077 GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID); 1078 1079 if (tx_dpcpu_fw_idp != NULL) 1080 *tx_dpcpu_fw_idp = MCDI_OUT_WORD(req, 1081 GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID); 1082 1083 if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN) 1084 v2_capable = B_FALSE; 1085 else 1086 v2_capable = B_TRUE; 1087 1088 if (flags2p != NULL) { 1089 *flags2p = (v2_capable) ? 1090 MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2) : 1091 0; 1092 } 1093 1094 if (tso2ncp != NULL) { 1095 *tso2ncp = (v2_capable) ? 1096 MCDI_OUT_WORD(req, 1097 GET_CAPABILITIES_V2_OUT_TX_TSO_V2_N_CONTEXTS) : 1098 0; 1099 } 1100 1101 return (0); 1102 1103 fail2: 1104 EFSYS_PROBE(fail2); 1105 fail1: 1106 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1107 1108 return (rc); 1109 } 1110 1111 static __checkReturn efx_rc_t 1112 efx_mcdi_do_reboot( 1113 __in efx_nic_t *enp, 1114 __in boolean_t after_assertion) 1115 { 1116 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_REBOOT_IN_LEN, 1117 MC_CMD_REBOOT_OUT_LEN); 1118 efx_mcdi_req_t req; 1119 efx_rc_t rc; 1120 1121 /* 1122 * We could require the caller to have caused en_mod_flags=0 to 1123 * call this function. This doesn't help the other port though, 1124 * who's about to get the MC ripped out from underneath them. 1125 * Since they have to cope with the subsequent fallout of MCDI 1126 * failures, we should as well. 1127 */ 1128 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 1129 1130 req.emr_cmd = MC_CMD_REBOOT; 1131 req.emr_in_buf = payload; 1132 req.emr_in_length = MC_CMD_REBOOT_IN_LEN; 1133 req.emr_out_buf = payload; 1134 req.emr_out_length = MC_CMD_REBOOT_OUT_LEN; 1135 1136 MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS, 1137 (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0)); 1138 1139 efx_mcdi_execute_quiet(enp, &req); 1140 1141 if (req.emr_rc == EACCES) { 1142 /* Unprivileged functions cannot reboot the MC. */ 1143 goto out; 1144 } 1145 1146 /* A successful reboot request returns EIO. */ 1147 if (req.emr_rc != 0 && req.emr_rc != EIO) { 1148 rc = req.emr_rc; 1149 goto fail1; 1150 } 1151 1152 out: 1153 return (0); 1154 1155 fail1: 1156 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1157 1158 return (rc); 1159 } 1160 1161 __checkReturn efx_rc_t 1162 efx_mcdi_reboot( 1163 __in efx_nic_t *enp) 1164 { 1165 return (efx_mcdi_do_reboot(enp, B_FALSE)); 1166 } 1167 1168 __checkReturn efx_rc_t 1169 efx_mcdi_exit_assertion_handler( 1170 __in efx_nic_t *enp) 1171 { 1172 return (efx_mcdi_do_reboot(enp, B_TRUE)); 1173 } 1174 1175 __checkReturn efx_rc_t 1176 efx_mcdi_read_assertion( 1177 __in efx_nic_t *enp) 1178 { 1179 efx_mcdi_req_t req; 1180 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_ASSERTS_IN_LEN, 1181 MC_CMD_GET_ASSERTS_OUT_LEN); 1182 #ifdef KDTRACE_HOOKS 1183 const char *reason; 1184 #else 1185 const char *reason __unused; 1186 #endif 1187 unsigned int flags; 1188 unsigned int index; 1189 unsigned int ofst; 1190 int retry; 1191 efx_rc_t rc; 1192 1193 /* 1194 * Before we attempt to chat to the MC, we should verify that the MC 1195 * isn't in its assertion handler, either due to a previous reboot, 1196 * or because we're reinitializing due to an eec_exception(). 1197 * 1198 * Use GET_ASSERTS to read any assertion state that may be present. 1199 * Retry this command twice. Once because a boot-time assertion failure 1200 * might cause the 1st MCDI request to fail. And once again because 1201 * we might race with efx_mcdi_exit_assertion_handler() running on 1202 * partner port(s) on the same NIC. 1203 */ 1204 retry = 2; 1205 do { 1206 (void) memset(payload, 0, sizeof (payload)); 1207 req.emr_cmd = MC_CMD_GET_ASSERTS; 1208 req.emr_in_buf = payload; 1209 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN; 1210 req.emr_out_buf = payload; 1211 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN; 1212 1213 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1); 1214 efx_mcdi_execute_quiet(enp, &req); 1215 1216 } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0); 1217 1218 if (req.emr_rc != 0) { 1219 if (req.emr_rc == EACCES) { 1220 /* Unprivileged functions cannot clear assertions. */ 1221 goto out; 1222 } 1223 rc = req.emr_rc; 1224 goto fail1; 1225 } 1226 1227 if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) { 1228 rc = EMSGSIZE; 1229 goto fail2; 1230 } 1231 1232 /* Print out any assertion state recorded */ 1233 flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS); 1234 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) 1235 return (0); 1236 1237 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL) 1238 ? "system-level assertion" 1239 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL) 1240 ? "thread-level assertion" 1241 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED) 1242 ? "watchdog reset" 1243 : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP) 1244 ? "illegal address trap" 1245 : "unknown assertion"; 1246 EFSYS_PROBE3(mcpu_assertion, 1247 const char *, reason, unsigned int, 1248 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS), 1249 unsigned int, 1250 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS)); 1251 1252 /* Print out the registers (r1 ... r31) */ 1253 ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST; 1254 for (index = 1; 1255 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM; 1256 index++) { 1257 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int, 1258 EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst), 1259 EFX_DWORD_0)); 1260 ofst += sizeof (efx_dword_t); 1261 } 1262 EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN); 1263 1264 out: 1265 return (0); 1266 1267 fail2: 1268 EFSYS_PROBE(fail2); 1269 fail1: 1270 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1271 1272 return (rc); 1273 } 1274 1275 /* 1276 * Internal routines for specific MCDI requests. 1277 */ 1278 1279 __checkReturn efx_rc_t 1280 efx_mcdi_drv_attach( 1281 __in efx_nic_t *enp, 1282 __in boolean_t attach) 1283 { 1284 efx_mcdi_req_t req; 1285 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_DRV_ATTACH_IN_LEN, 1286 MC_CMD_DRV_ATTACH_EXT_OUT_LEN); 1287 efx_rc_t rc; 1288 1289 req.emr_cmd = MC_CMD_DRV_ATTACH; 1290 req.emr_in_buf = payload; 1291 req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN; 1292 req.emr_out_buf = payload; 1293 req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN; 1294 1295 /* 1296 * Typically, client drivers use DONT_CARE for the datapath firmware 1297 * type to ensure that the driver can attach to an unprivileged 1298 * function. The datapath firmware type to use is controlled by the 1299 * 'sfboot' utility. 1300 * If a client driver wishes to attach with a specific datapath firmware 1301 * type, that can be passed in second argument of efx_nic_probe API. One 1302 * such example is the ESXi native driver that attempts attaching with 1303 * FULL_FEATURED datapath firmware type first and fall backs to 1304 * DONT_CARE datapath firmware type if MC_CMD_DRV_ATTACH fails. 1305 */ 1306 MCDI_IN_POPULATE_DWORD_2(req, DRV_ATTACH_IN_NEW_STATE, 1307 DRV_ATTACH_IN_ATTACH, attach ? 1 : 0, 1308 DRV_ATTACH_IN_SUBVARIANT_AWARE, EFSYS_OPT_FW_SUBVARIANT_AWARE); 1309 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1); 1310 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, enp->efv); 1311 1312 efx_mcdi_execute(enp, &req); 1313 1314 if (req.emr_rc != 0) { 1315 rc = req.emr_rc; 1316 goto fail1; 1317 } 1318 1319 if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) { 1320 rc = EMSGSIZE; 1321 goto fail2; 1322 } 1323 1324 return (0); 1325 1326 fail2: 1327 EFSYS_PROBE(fail2); 1328 fail1: 1329 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1330 1331 return (rc); 1332 } 1333 1334 __checkReturn efx_rc_t 1335 efx_mcdi_get_board_cfg( 1336 __in efx_nic_t *enp, 1337 __out_opt uint32_t *board_typep, 1338 __out_opt efx_dword_t *capabilitiesp, 1339 __out_ecount_opt(6) uint8_t mac_addrp[6]) 1340 { 1341 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 1342 efx_mcdi_req_t req; 1343 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_BOARD_CFG_IN_LEN, 1344 MC_CMD_GET_BOARD_CFG_OUT_LENMIN); 1345 efx_rc_t rc; 1346 1347 req.emr_cmd = MC_CMD_GET_BOARD_CFG; 1348 req.emr_in_buf = payload; 1349 req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN; 1350 req.emr_out_buf = payload; 1351 req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN; 1352 1353 efx_mcdi_execute(enp, &req); 1354 1355 if (req.emr_rc != 0) { 1356 rc = req.emr_rc; 1357 goto fail1; 1358 } 1359 1360 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) { 1361 rc = EMSGSIZE; 1362 goto fail2; 1363 } 1364 1365 if (mac_addrp != NULL) { 1366 uint8_t *addrp; 1367 1368 if (emip->emi_port == 1) { 1369 addrp = MCDI_OUT2(req, uint8_t, 1370 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0); 1371 } else if (emip->emi_port == 2) { 1372 addrp = MCDI_OUT2(req, uint8_t, 1373 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1); 1374 } else { 1375 rc = EINVAL; 1376 goto fail3; 1377 } 1378 1379 EFX_MAC_ADDR_COPY(mac_addrp, addrp); 1380 } 1381 1382 if (capabilitiesp != NULL) { 1383 if (emip->emi_port == 1) { 1384 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, 1385 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0); 1386 } else if (emip->emi_port == 2) { 1387 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, 1388 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1); 1389 } else { 1390 rc = EINVAL; 1391 goto fail4; 1392 } 1393 } 1394 1395 if (board_typep != NULL) { 1396 *board_typep = MCDI_OUT_DWORD(req, 1397 GET_BOARD_CFG_OUT_BOARD_TYPE); 1398 } 1399 1400 return (0); 1401 1402 fail4: 1403 EFSYS_PROBE(fail4); 1404 fail3: 1405 EFSYS_PROBE(fail3); 1406 fail2: 1407 EFSYS_PROBE(fail2); 1408 fail1: 1409 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1410 1411 return (rc); 1412 } 1413 1414 __checkReturn efx_rc_t 1415 efx_mcdi_get_resource_limits( 1416 __in efx_nic_t *enp, 1417 __out_opt uint32_t *nevqp, 1418 __out_opt uint32_t *nrxqp, 1419 __out_opt uint32_t *ntxqp) 1420 { 1421 efx_mcdi_req_t req; 1422 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_RESOURCE_LIMITS_IN_LEN, 1423 MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN); 1424 efx_rc_t rc; 1425 1426 req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS; 1427 req.emr_in_buf = payload; 1428 req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN; 1429 req.emr_out_buf = payload; 1430 req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN; 1431 1432 efx_mcdi_execute(enp, &req); 1433 1434 if (req.emr_rc != 0) { 1435 rc = req.emr_rc; 1436 goto fail1; 1437 } 1438 1439 if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) { 1440 rc = EMSGSIZE; 1441 goto fail2; 1442 } 1443 1444 if (nevqp != NULL) 1445 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ); 1446 if (nrxqp != NULL) 1447 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ); 1448 if (ntxqp != NULL) 1449 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ); 1450 1451 return (0); 1452 1453 fail2: 1454 EFSYS_PROBE(fail2); 1455 fail1: 1456 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1457 1458 return (rc); 1459 } 1460 1461 __checkReturn efx_rc_t 1462 efx_mcdi_get_phy_cfg( 1463 __in efx_nic_t *enp) 1464 { 1465 efx_port_t *epp = &(enp->en_port); 1466 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 1467 efx_mcdi_req_t req; 1468 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_CFG_IN_LEN, 1469 MC_CMD_GET_PHY_CFG_OUT_LEN); 1470 #if EFSYS_OPT_NAMES 1471 const char *namep; 1472 size_t namelen; 1473 #endif 1474 uint32_t phy_media_type; 1475 efx_rc_t rc; 1476 1477 req.emr_cmd = MC_CMD_GET_PHY_CFG; 1478 req.emr_in_buf = payload; 1479 req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN; 1480 req.emr_out_buf = payload; 1481 req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN; 1482 1483 efx_mcdi_execute(enp, &req); 1484 1485 if (req.emr_rc != 0) { 1486 rc = req.emr_rc; 1487 goto fail1; 1488 } 1489 1490 if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) { 1491 rc = EMSGSIZE; 1492 goto fail2; 1493 } 1494 1495 encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE); 1496 #if EFSYS_OPT_NAMES 1497 namep = MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME); 1498 namelen = MIN(sizeof (encp->enc_phy_name) - 1, 1499 strnlen(namep, MC_CMD_GET_PHY_CFG_OUT_NAME_LEN)); 1500 (void) memset(encp->enc_phy_name, 0, 1501 sizeof (encp->enc_phy_name)); 1502 memcpy(encp->enc_phy_name, namep, namelen); 1503 #endif /* EFSYS_OPT_NAMES */ 1504 (void) memset(encp->enc_phy_revision, 0, 1505 sizeof (encp->enc_phy_revision)); 1506 memcpy(encp->enc_phy_revision, 1507 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION), 1508 MIN(sizeof (encp->enc_phy_revision) - 1, 1509 MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN)); 1510 #if EFSYS_OPT_PHY_LED_CONTROL 1511 encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) | 1512 (1 << EFX_PHY_LED_OFF) | 1513 (1 << EFX_PHY_LED_ON)); 1514 #endif /* EFSYS_OPT_PHY_LED_CONTROL */ 1515 1516 /* Get the media type of the fixed port, if recognised. */ 1517 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI); 1518 EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4); 1519 EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4); 1520 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP); 1521 EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS); 1522 EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T); 1523 EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS); 1524 phy_media_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE); 1525 epp->ep_fixed_port_type = (efx_phy_media_type_t) phy_media_type; 1526 if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES) 1527 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID; 1528 1529 epp->ep_phy_cap_mask = 1530 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP); 1531 #if EFSYS_OPT_PHY_FLAGS 1532 encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS); 1533 #endif /* EFSYS_OPT_PHY_FLAGS */ 1534 1535 encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT); 1536 1537 /* Populate internal state */ 1538 encp->enc_mcdi_mdio_channel = 1539 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL); 1540 1541 #if EFSYS_OPT_PHY_STATS 1542 encp->enc_mcdi_phy_stat_mask = 1543 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK); 1544 #endif /* EFSYS_OPT_PHY_STATS */ 1545 1546 #if EFSYS_OPT_BIST 1547 encp->enc_bist_mask = 0; 1548 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1549 GET_PHY_CFG_OUT_BIST_CABLE_SHORT)) 1550 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT); 1551 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1552 GET_PHY_CFG_OUT_BIST_CABLE_LONG)) 1553 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG); 1554 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1555 GET_PHY_CFG_OUT_BIST)) 1556 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL); 1557 #endif /* EFSYS_OPT_BIST */ 1558 1559 return (0); 1560 1561 fail2: 1562 EFSYS_PROBE(fail2); 1563 fail1: 1564 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1565 1566 return (rc); 1567 } 1568 1569 __checkReturn efx_rc_t 1570 efx_mcdi_firmware_update_supported( 1571 __in efx_nic_t *enp, 1572 __out boolean_t *supportedp) 1573 { 1574 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1575 efx_rc_t rc; 1576 1577 if (emcop != NULL) { 1578 if ((rc = emcop->emco_feature_supported(enp, 1579 EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0) 1580 goto fail1; 1581 } else { 1582 /* Earlier devices always supported updates */ 1583 *supportedp = B_TRUE; 1584 } 1585 1586 return (0); 1587 1588 fail1: 1589 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1590 1591 return (rc); 1592 } 1593 1594 __checkReturn efx_rc_t 1595 efx_mcdi_macaddr_change_supported( 1596 __in efx_nic_t *enp, 1597 __out boolean_t *supportedp) 1598 { 1599 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1600 efx_rc_t rc; 1601 1602 if (emcop != NULL) { 1603 if ((rc = emcop->emco_feature_supported(enp, 1604 EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0) 1605 goto fail1; 1606 } else { 1607 /* Earlier devices always supported MAC changes */ 1608 *supportedp = B_TRUE; 1609 } 1610 1611 return (0); 1612 1613 fail1: 1614 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1615 1616 return (rc); 1617 } 1618 1619 __checkReturn efx_rc_t 1620 efx_mcdi_link_control_supported( 1621 __in efx_nic_t *enp, 1622 __out boolean_t *supportedp) 1623 { 1624 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1625 efx_rc_t rc; 1626 1627 if (emcop != NULL) { 1628 if ((rc = emcop->emco_feature_supported(enp, 1629 EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0) 1630 goto fail1; 1631 } else { 1632 /* Earlier devices always supported link control */ 1633 *supportedp = B_TRUE; 1634 } 1635 1636 return (0); 1637 1638 fail1: 1639 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1640 1641 return (rc); 1642 } 1643 1644 __checkReturn efx_rc_t 1645 efx_mcdi_mac_spoofing_supported( 1646 __in efx_nic_t *enp, 1647 __out boolean_t *supportedp) 1648 { 1649 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1650 efx_rc_t rc; 1651 1652 if (emcop != NULL) { 1653 if ((rc = emcop->emco_feature_supported(enp, 1654 EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0) 1655 goto fail1; 1656 } else { 1657 /* Earlier devices always supported MAC spoofing */ 1658 *supportedp = B_TRUE; 1659 } 1660 1661 return (0); 1662 1663 fail1: 1664 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1665 1666 return (rc); 1667 } 1668 1669 #if EFSYS_OPT_BIST 1670 1671 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 1672 /* 1673 * Enter bist offline mode. This is a fw mode which puts the NIC into a state 1674 * where memory BIST tests can be run and not much else can interfere or happen. 1675 * A reboot is required to exit this mode. 1676 */ 1677 __checkReturn efx_rc_t 1678 efx_mcdi_bist_enable_offline( 1679 __in efx_nic_t *enp) 1680 { 1681 efx_mcdi_req_t req; 1682 efx_rc_t rc; 1683 1684 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0); 1685 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0); 1686 1687 req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST; 1688 req.emr_in_buf = NULL; 1689 req.emr_in_length = 0; 1690 req.emr_out_buf = NULL; 1691 req.emr_out_length = 0; 1692 1693 efx_mcdi_execute(enp, &req); 1694 1695 if (req.emr_rc != 0) { 1696 rc = req.emr_rc; 1697 goto fail1; 1698 } 1699 1700 return (0); 1701 1702 fail1: 1703 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1704 1705 return (rc); 1706 } 1707 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 1708 1709 __checkReturn efx_rc_t 1710 efx_mcdi_bist_start( 1711 __in efx_nic_t *enp, 1712 __in efx_bist_type_t type) 1713 { 1714 efx_mcdi_req_t req; 1715 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_START_BIST_IN_LEN, 1716 MC_CMD_START_BIST_OUT_LEN); 1717 efx_rc_t rc; 1718 1719 req.emr_cmd = MC_CMD_START_BIST; 1720 req.emr_in_buf = payload; 1721 req.emr_in_length = MC_CMD_START_BIST_IN_LEN; 1722 req.emr_out_buf = payload; 1723 req.emr_out_length = MC_CMD_START_BIST_OUT_LEN; 1724 1725 switch (type) { 1726 case EFX_BIST_TYPE_PHY_NORMAL: 1727 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST); 1728 break; 1729 case EFX_BIST_TYPE_PHY_CABLE_SHORT: 1730 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1731 MC_CMD_PHY_BIST_CABLE_SHORT); 1732 break; 1733 case EFX_BIST_TYPE_PHY_CABLE_LONG: 1734 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1735 MC_CMD_PHY_BIST_CABLE_LONG); 1736 break; 1737 case EFX_BIST_TYPE_MC_MEM: 1738 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1739 MC_CMD_MC_MEM_BIST); 1740 break; 1741 case EFX_BIST_TYPE_SAT_MEM: 1742 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1743 MC_CMD_PORT_MEM_BIST); 1744 break; 1745 case EFX_BIST_TYPE_REG: 1746 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1747 MC_CMD_REG_BIST); 1748 break; 1749 default: 1750 EFSYS_ASSERT(0); 1751 } 1752 1753 efx_mcdi_execute(enp, &req); 1754 1755 if (req.emr_rc != 0) { 1756 rc = req.emr_rc; 1757 goto fail1; 1758 } 1759 1760 return (0); 1761 1762 fail1: 1763 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1764 1765 return (rc); 1766 } 1767 1768 #endif /* EFSYS_OPT_BIST */ 1769 1770 /* Enable logging of some events (e.g. link state changes) */ 1771 __checkReturn efx_rc_t 1772 efx_mcdi_log_ctrl( 1773 __in efx_nic_t *enp) 1774 { 1775 efx_mcdi_req_t req; 1776 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_LOG_CTRL_IN_LEN, 1777 MC_CMD_LOG_CTRL_OUT_LEN); 1778 efx_rc_t rc; 1779 1780 req.emr_cmd = MC_CMD_LOG_CTRL; 1781 req.emr_in_buf = payload; 1782 req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN; 1783 req.emr_out_buf = payload; 1784 req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN; 1785 1786 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST, 1787 MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ); 1788 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0); 1789 1790 efx_mcdi_execute(enp, &req); 1791 1792 if (req.emr_rc != 0) { 1793 rc = req.emr_rc; 1794 goto fail1; 1795 } 1796 1797 return (0); 1798 1799 fail1: 1800 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1801 1802 return (rc); 1803 } 1804 1805 #if EFSYS_OPT_MAC_STATS 1806 1807 typedef enum efx_stats_action_e { 1808 EFX_STATS_CLEAR, 1809 EFX_STATS_UPLOAD, 1810 EFX_STATS_ENABLE_NOEVENTS, 1811 EFX_STATS_ENABLE_EVENTS, 1812 EFX_STATS_DISABLE, 1813 } efx_stats_action_t; 1814 1815 static __checkReturn efx_rc_t 1816 efx_mcdi_mac_stats( 1817 __in efx_nic_t *enp, 1818 __in_opt efsys_mem_t *esmp, 1819 __in efx_stats_action_t action, 1820 __in uint16_t period_ms) 1821 { 1822 efx_mcdi_req_t req; 1823 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAC_STATS_IN_LEN, 1824 MC_CMD_MAC_STATS_V2_OUT_DMA_LEN); 1825 int clear = (action == EFX_STATS_CLEAR); 1826 int upload = (action == EFX_STATS_UPLOAD); 1827 int enable = (action == EFX_STATS_ENABLE_NOEVENTS); 1828 int events = (action == EFX_STATS_ENABLE_EVENTS); 1829 int disable = (action == EFX_STATS_DISABLE); 1830 efx_rc_t rc; 1831 1832 req.emr_cmd = MC_CMD_MAC_STATS; 1833 req.emr_in_buf = payload; 1834 req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN; 1835 req.emr_out_buf = payload; 1836 req.emr_out_length = MC_CMD_MAC_STATS_V2_OUT_DMA_LEN; 1837 1838 MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD, 1839 MAC_STATS_IN_DMA, upload, 1840 MAC_STATS_IN_CLEAR, clear, 1841 MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable, 1842 MAC_STATS_IN_PERIODIC_ENABLE, enable | events, 1843 MAC_STATS_IN_PERIODIC_NOEVENT, !events, 1844 MAC_STATS_IN_PERIOD_MS, (enable | events) ? period_ms : 0); 1845 1846 if (enable || events || upload) { 1847 const efx_nic_cfg_t *encp = &enp->en_nic_cfg; 1848 uint32_t bytes; 1849 1850 /* Periodic stats or stats upload require a DMA buffer */ 1851 if (esmp == NULL) { 1852 rc = EINVAL; 1853 goto fail1; 1854 } 1855 1856 if (encp->enc_mac_stats_nstats < MC_CMD_MAC_NSTATS) { 1857 /* MAC stats count too small for legacy MAC stats */ 1858 rc = ENOSPC; 1859 goto fail2; 1860 } 1861 1862 bytes = encp->enc_mac_stats_nstats * sizeof (efx_qword_t); 1863 1864 if (EFSYS_MEM_SIZE(esmp) < bytes) { 1865 /* DMA buffer too small */ 1866 rc = ENOSPC; 1867 goto fail3; 1868 } 1869 1870 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO, 1871 EFSYS_MEM_ADDR(esmp) & 0xffffffff); 1872 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI, 1873 EFSYS_MEM_ADDR(esmp) >> 32); 1874 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes); 1875 } 1876 1877 /* 1878 * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats, 1879 * as this may fail (and leave periodic DMA enabled) if the 1880 * vadapter has already been deleted. 1881 */ 1882 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID, 1883 (disable ? EVB_PORT_ID_NULL : enp->en_vport_id)); 1884 1885 efx_mcdi_execute(enp, &req); 1886 1887 if (req.emr_rc != 0) { 1888 /* EF10: Expect ENOENT if no DMA queues are initialised */ 1889 if ((req.emr_rc != ENOENT) || 1890 (enp->en_rx_qcount + enp->en_tx_qcount != 0)) { 1891 rc = req.emr_rc; 1892 goto fail4; 1893 } 1894 } 1895 1896 return (0); 1897 1898 fail4: 1899 EFSYS_PROBE(fail4); 1900 fail3: 1901 EFSYS_PROBE(fail3); 1902 fail2: 1903 EFSYS_PROBE(fail2); 1904 fail1: 1905 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1906 1907 return (rc); 1908 } 1909 1910 __checkReturn efx_rc_t 1911 efx_mcdi_mac_stats_clear( 1912 __in efx_nic_t *enp) 1913 { 1914 efx_rc_t rc; 1915 1916 if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR, 0)) != 0) 1917 goto fail1; 1918 1919 return (0); 1920 1921 fail1: 1922 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1923 1924 return (rc); 1925 } 1926 1927 __checkReturn efx_rc_t 1928 efx_mcdi_mac_stats_upload( 1929 __in efx_nic_t *enp, 1930 __in efsys_mem_t *esmp) 1931 { 1932 efx_rc_t rc; 1933 1934 /* 1935 * The MC DMAs aggregate statistics for our convenience, so we can 1936 * avoid having to pull the statistics buffer into the cache to 1937 * maintain cumulative statistics. 1938 */ 1939 if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD, 0)) != 0) 1940 goto fail1; 1941 1942 return (0); 1943 1944 fail1: 1945 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1946 1947 return (rc); 1948 } 1949 1950 __checkReturn efx_rc_t 1951 efx_mcdi_mac_stats_periodic( 1952 __in efx_nic_t *enp, 1953 __in efsys_mem_t *esmp, 1954 __in uint16_t period_ms, 1955 __in boolean_t events) 1956 { 1957 efx_rc_t rc; 1958 1959 /* 1960 * The MC DMAs aggregate statistics for our convenience, so we can 1961 * avoid having to pull the statistics buffer into the cache to 1962 * maintain cumulative statistics. 1963 * Huntington uses a fixed 1sec period. 1964 * Medford uses a fixed 1sec period before v6.2.1.1033 firmware. 1965 */ 1966 if (period_ms == 0) 1967 rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE, 0); 1968 else if (events) 1969 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS, 1970 period_ms); 1971 else 1972 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS, 1973 period_ms); 1974 1975 if (rc != 0) 1976 goto fail1; 1977 1978 return (0); 1979 1980 fail1: 1981 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1982 1983 return (rc); 1984 } 1985 1986 #endif /* EFSYS_OPT_MAC_STATS */ 1987 1988 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 1989 1990 /* 1991 * This function returns the pf and vf number of a function. If it is a pf the 1992 * vf number is 0xffff. The vf number is the index of the vf on that 1993 * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0), 1994 * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff). 1995 */ 1996 __checkReturn efx_rc_t 1997 efx_mcdi_get_function_info( 1998 __in efx_nic_t *enp, 1999 __out uint32_t *pfp, 2000 __out_opt uint32_t *vfp) 2001 { 2002 efx_mcdi_req_t req; 2003 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_FUNCTION_INFO_IN_LEN, 2004 MC_CMD_GET_FUNCTION_INFO_OUT_LEN); 2005 efx_rc_t rc; 2006 2007 req.emr_cmd = MC_CMD_GET_FUNCTION_INFO; 2008 req.emr_in_buf = payload; 2009 req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN; 2010 req.emr_out_buf = payload; 2011 req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN; 2012 2013 efx_mcdi_execute(enp, &req); 2014 2015 if (req.emr_rc != 0) { 2016 rc = req.emr_rc; 2017 goto fail1; 2018 } 2019 2020 if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) { 2021 rc = EMSGSIZE; 2022 goto fail2; 2023 } 2024 2025 *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF); 2026 if (vfp != NULL) 2027 *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF); 2028 2029 return (0); 2030 2031 fail2: 2032 EFSYS_PROBE(fail2); 2033 fail1: 2034 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2035 2036 return (rc); 2037 } 2038 2039 __checkReturn efx_rc_t 2040 efx_mcdi_privilege_mask( 2041 __in efx_nic_t *enp, 2042 __in uint32_t pf, 2043 __in uint32_t vf, 2044 __out uint32_t *maskp) 2045 { 2046 efx_mcdi_req_t req; 2047 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_PRIVILEGE_MASK_IN_LEN, 2048 MC_CMD_PRIVILEGE_MASK_OUT_LEN); 2049 efx_rc_t rc; 2050 2051 req.emr_cmd = MC_CMD_PRIVILEGE_MASK; 2052 req.emr_in_buf = payload; 2053 req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN; 2054 req.emr_out_buf = payload; 2055 req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN; 2056 2057 MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION, 2058 PRIVILEGE_MASK_IN_FUNCTION_PF, pf, 2059 PRIVILEGE_MASK_IN_FUNCTION_VF, vf); 2060 2061 efx_mcdi_execute(enp, &req); 2062 2063 if (req.emr_rc != 0) { 2064 rc = req.emr_rc; 2065 goto fail1; 2066 } 2067 2068 if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) { 2069 rc = EMSGSIZE; 2070 goto fail2; 2071 } 2072 2073 *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK); 2074 2075 return (0); 2076 2077 fail2: 2078 EFSYS_PROBE(fail2); 2079 fail1: 2080 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2081 2082 return (rc); 2083 } 2084 2085 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 2086 2087 __checkReturn efx_rc_t 2088 efx_mcdi_set_workaround( 2089 __in efx_nic_t *enp, 2090 __in uint32_t type, 2091 __in boolean_t enabled, 2092 __out_opt uint32_t *flagsp) 2093 { 2094 efx_mcdi_req_t req; 2095 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_WORKAROUND_IN_LEN, 2096 MC_CMD_WORKAROUND_EXT_OUT_LEN); 2097 efx_rc_t rc; 2098 2099 req.emr_cmd = MC_CMD_WORKAROUND; 2100 req.emr_in_buf = payload; 2101 req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN; 2102 req.emr_out_buf = payload; 2103 req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN; 2104 2105 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type); 2106 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0); 2107 2108 efx_mcdi_execute_quiet(enp, &req); 2109 2110 if (req.emr_rc != 0) { 2111 rc = req.emr_rc; 2112 goto fail1; 2113 } 2114 2115 if (flagsp != NULL) { 2116 if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN) 2117 *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS); 2118 else 2119 *flagsp = 0; 2120 } 2121 2122 return (0); 2123 2124 fail1: 2125 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2126 2127 return (rc); 2128 } 2129 2130 __checkReturn efx_rc_t 2131 efx_mcdi_get_workarounds( 2132 __in efx_nic_t *enp, 2133 __out_opt uint32_t *implementedp, 2134 __out_opt uint32_t *enabledp) 2135 { 2136 efx_mcdi_req_t req; 2137 EFX_MCDI_DECLARE_BUF(payload, 0, MC_CMD_GET_WORKAROUNDS_OUT_LEN); 2138 efx_rc_t rc; 2139 2140 req.emr_cmd = MC_CMD_GET_WORKAROUNDS; 2141 req.emr_in_buf = NULL; 2142 req.emr_in_length = 0; 2143 req.emr_out_buf = payload; 2144 req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN; 2145 2146 efx_mcdi_execute(enp, &req); 2147 2148 if (req.emr_rc != 0) { 2149 rc = req.emr_rc; 2150 goto fail1; 2151 } 2152 2153 if (implementedp != NULL) { 2154 *implementedp = 2155 MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED); 2156 } 2157 2158 if (enabledp != NULL) { 2159 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED); 2160 } 2161 2162 return (0); 2163 2164 fail1: 2165 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2166 2167 return (rc); 2168 } 2169 2170 /* 2171 * Size of media information page in accordance with SFF-8472 and SFF-8436. 2172 * It is used in MCDI interface as well. 2173 */ 2174 #define EFX_PHY_MEDIA_INFO_PAGE_SIZE 0x80 2175 2176 /* 2177 * Transceiver identifiers from SFF-8024 Table 4-1. 2178 */ 2179 #define EFX_SFF_TRANSCEIVER_ID_SFP 0x03 /* SFP/SFP+/SFP28 */ 2180 #define EFX_SFF_TRANSCEIVER_ID_QSFP 0x0c /* QSFP */ 2181 #define EFX_SFF_TRANSCEIVER_ID_QSFP_PLUS 0x0d /* QSFP+ or later */ 2182 #define EFX_SFF_TRANSCEIVER_ID_QSFP28 0x11 /* QSFP28 or later */ 2183 2184 static __checkReturn efx_rc_t 2185 efx_mcdi_get_phy_media_info( 2186 __in efx_nic_t *enp, 2187 __in uint32_t mcdi_page, 2188 __in uint8_t offset, 2189 __in uint8_t len, 2190 __out_bcount(len) uint8_t *data) 2191 { 2192 efx_mcdi_req_t req; 2193 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN, 2194 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN( 2195 EFX_PHY_MEDIA_INFO_PAGE_SIZE)); 2196 efx_rc_t rc; 2197 2198 EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2199 2200 req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO; 2201 req.emr_in_buf = payload; 2202 req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN; 2203 req.emr_out_buf = payload; 2204 req.emr_out_length = 2205 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2206 2207 MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page); 2208 2209 efx_mcdi_execute(enp, &req); 2210 2211 if (req.emr_rc != 0) { 2212 rc = req.emr_rc; 2213 goto fail1; 2214 } 2215 2216 if (req.emr_out_length_used != 2217 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) { 2218 rc = EMSGSIZE; 2219 goto fail2; 2220 } 2221 2222 if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) != 2223 EFX_PHY_MEDIA_INFO_PAGE_SIZE) { 2224 rc = EIO; 2225 goto fail3; 2226 } 2227 2228 memcpy(data, 2229 MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset, 2230 len); 2231 2232 return (0); 2233 2234 fail3: 2235 EFSYS_PROBE(fail3); 2236 fail2: 2237 EFSYS_PROBE(fail2); 2238 fail1: 2239 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2240 2241 return (rc); 2242 } 2243 2244 __checkReturn efx_rc_t 2245 efx_mcdi_phy_module_get_info( 2246 __in efx_nic_t *enp, 2247 __in uint8_t dev_addr, 2248 __in size_t offset, 2249 __in size_t len, 2250 __out_bcount(len) uint8_t *data) 2251 { 2252 efx_port_t *epp = &(enp->en_port); 2253 efx_rc_t rc; 2254 uint32_t mcdi_lower_page; 2255 uint32_t mcdi_upper_page; 2256 uint8_t id; 2257 2258 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 2259 2260 /* 2261 * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages. 2262 * Offset plus length interface allows to access page 0 only. 2263 * I.e. non-zero upper pages are not accessible. 2264 * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6 2265 * QSFP+ Memory Map for details on how information is structured 2266 * and accessible. 2267 */ 2268 switch (epp->ep_fixed_port_type) { 2269 case EFX_PHY_MEDIA_SFP_PLUS: 2270 case EFX_PHY_MEDIA_QSFP_PLUS: 2271 /* Port type supports modules */ 2272 break; 2273 default: 2274 rc = ENOTSUP; 2275 goto fail1; 2276 } 2277 2278 /* 2279 * For all supported port types, MCDI page 0 offset 0 holds the 2280 * transceiver identifier. Probe to determine the data layout. 2281 * Definitions from SFF-8024 Table 4-1. 2282 */ 2283 rc = efx_mcdi_get_phy_media_info(enp, 0, 0, sizeof (id), &id); 2284 if (rc != 0) 2285 goto fail2; 2286 2287 switch (id) { 2288 case EFX_SFF_TRANSCEIVER_ID_SFP: 2289 /* 2290 * In accordance with SFF-8472 Diagnostic Monitoring 2291 * Interface for Optical Transceivers section 4 Memory 2292 * Organization two 2-wire addresses are defined. 2293 */ 2294 switch (dev_addr) { 2295 /* Base information */ 2296 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE: 2297 /* 2298 * MCDI page 0 should be used to access lower 2299 * page 0 (0x00 - 0x7f) at the device address 0xA0. 2300 */ 2301 mcdi_lower_page = 0; 2302 /* 2303 * MCDI page 1 should be used to access upper 2304 * page 0 (0x80 - 0xff) at the device address 0xA0. 2305 */ 2306 mcdi_upper_page = 1; 2307 break; 2308 /* Diagnostics */ 2309 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM: 2310 /* 2311 * MCDI page 2 should be used to access lower 2312 * page 0 (0x00 - 0x7f) at the device address 0xA2. 2313 */ 2314 mcdi_lower_page = 2; 2315 /* 2316 * MCDI page 3 should be used to access upper 2317 * page 0 (0x80 - 0xff) at the device address 0xA2. 2318 */ 2319 mcdi_upper_page = 3; 2320 break; 2321 default: 2322 rc = ENOTSUP; 2323 goto fail3; 2324 } 2325 break; 2326 case EFX_SFF_TRANSCEIVER_ID_QSFP: 2327 case EFX_SFF_TRANSCEIVER_ID_QSFP_PLUS: 2328 case EFX_SFF_TRANSCEIVER_ID_QSFP28: 2329 switch (dev_addr) { 2330 case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP: 2331 /* 2332 * MCDI page -1 should be used to access lower page 0 2333 * (0x00 - 0x7f). 2334 */ 2335 mcdi_lower_page = (uint32_t)-1; 2336 /* 2337 * MCDI page 0 should be used to access upper page 0 2338 * (0x80h - 0xff). 2339 */ 2340 mcdi_upper_page = 0; 2341 break; 2342 default: 2343 rc = ENOTSUP; 2344 goto fail3; 2345 } 2346 break; 2347 default: 2348 rc = ENOTSUP; 2349 goto fail3; 2350 } 2351 2352 EFX_STATIC_ASSERT(EFX_PHY_MEDIA_INFO_PAGE_SIZE <= 0xFF); 2353 2354 if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) { 2355 size_t read_len = 2356 MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset); 2357 2358 rc = efx_mcdi_get_phy_media_info(enp, 2359 mcdi_lower_page, (uint8_t)offset, (uint8_t)read_len, data); 2360 if (rc != 0) 2361 goto fail4; 2362 2363 data += read_len; 2364 len -= read_len; 2365 2366 offset = 0; 2367 } else { 2368 offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE; 2369 } 2370 2371 if (len > 0) { 2372 EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2373 EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2374 2375 rc = efx_mcdi_get_phy_media_info(enp, 2376 mcdi_upper_page, (uint8_t)offset, (uint8_t)len, data); 2377 if (rc != 0) 2378 goto fail5; 2379 } 2380 2381 return (0); 2382 2383 fail5: 2384 EFSYS_PROBE(fail5); 2385 fail4: 2386 EFSYS_PROBE(fail4); 2387 fail3: 2388 EFSYS_PROBE(fail3); 2389 fail2: 2390 EFSYS_PROBE(fail2); 2391 fail1: 2392 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2393 2394 return (rc); 2395 } 2396 2397 #endif /* EFSYS_OPT_MCDI */ 2398