1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 const char *reason; 1183 unsigned int flags; 1184 unsigned int index; 1185 unsigned int ofst; 1186 int retry; 1187 efx_rc_t rc; 1188 1189 /* 1190 * Before we attempt to chat to the MC, we should verify that the MC 1191 * isn't in its assertion handler, either due to a previous reboot, 1192 * or because we're reinitializing due to an eec_exception(). 1193 * 1194 * Use GET_ASSERTS to read any assertion state that may be present. 1195 * Retry this command twice. Once because a boot-time assertion failure 1196 * might cause the 1st MCDI request to fail. And once again because 1197 * we might race with efx_mcdi_exit_assertion_handler() running on 1198 * partner port(s) on the same NIC. 1199 */ 1200 retry = 2; 1201 do { 1202 (void) memset(payload, 0, sizeof (payload)); 1203 req.emr_cmd = MC_CMD_GET_ASSERTS; 1204 req.emr_in_buf = payload; 1205 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN; 1206 req.emr_out_buf = payload; 1207 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN; 1208 1209 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1); 1210 efx_mcdi_execute_quiet(enp, &req); 1211 1212 } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0); 1213 1214 if (req.emr_rc != 0) { 1215 if (req.emr_rc == EACCES) { 1216 /* Unprivileged functions cannot clear assertions. */ 1217 goto out; 1218 } 1219 rc = req.emr_rc; 1220 goto fail1; 1221 } 1222 1223 if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) { 1224 rc = EMSGSIZE; 1225 goto fail2; 1226 } 1227 1228 /* Print out any assertion state recorded */ 1229 flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS); 1230 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) 1231 return (0); 1232 1233 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL) 1234 ? "system-level assertion" 1235 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL) 1236 ? "thread-level assertion" 1237 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED) 1238 ? "watchdog reset" 1239 : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP) 1240 ? "illegal address trap" 1241 : "unknown assertion"; 1242 EFSYS_PROBE3(mcpu_assertion, 1243 const char *, reason, unsigned int, 1244 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS), 1245 unsigned int, 1246 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS)); 1247 1248 /* Print out the registers (r1 ... r31) */ 1249 ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST; 1250 for (index = 1; 1251 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM; 1252 index++) { 1253 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int, 1254 EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst), 1255 EFX_DWORD_0)); 1256 ofst += sizeof (efx_dword_t); 1257 } 1258 EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN); 1259 1260 out: 1261 return (0); 1262 1263 fail2: 1264 EFSYS_PROBE(fail2); 1265 fail1: 1266 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1267 1268 return (rc); 1269 } 1270 1271 /* 1272 * Internal routines for for specific MCDI requests. 1273 */ 1274 1275 __checkReturn efx_rc_t 1276 efx_mcdi_drv_attach( 1277 __in efx_nic_t *enp, 1278 __in boolean_t attach) 1279 { 1280 efx_mcdi_req_t req; 1281 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_DRV_ATTACH_IN_LEN, 1282 MC_CMD_DRV_ATTACH_EXT_OUT_LEN); 1283 efx_rc_t rc; 1284 1285 req.emr_cmd = MC_CMD_DRV_ATTACH; 1286 req.emr_in_buf = payload; 1287 req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN; 1288 req.emr_out_buf = payload; 1289 req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN; 1290 1291 /* 1292 * Typically, client drivers use DONT_CARE for the datapath firmware 1293 * type to ensure that the driver can attach to an unprivileged 1294 * function. The datapath firmware type to use is controlled by the 1295 * 'sfboot' utility. 1296 * If a client driver wishes to attach with a specific datapath firmware 1297 * type, that can be passed in second argument of efx_nic_probe API. One 1298 * such example is the ESXi native driver that attempts attaching with 1299 * FULL_FEATURED datapath firmware type first and fall backs to 1300 * DONT_CARE datapath firmware type if MC_CMD_DRV_ATTACH fails. 1301 */ 1302 MCDI_IN_POPULATE_DWORD_2(req, DRV_ATTACH_IN_NEW_STATE, 1303 DRV_ATTACH_IN_ATTACH, attach ? 1 : 0, 1304 DRV_ATTACH_IN_SUBVARIANT_AWARE, EFSYS_OPT_FW_SUBVARIANT_AWARE); 1305 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1); 1306 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, enp->efv); 1307 1308 efx_mcdi_execute(enp, &req); 1309 1310 if (req.emr_rc != 0) { 1311 rc = req.emr_rc; 1312 goto fail1; 1313 } 1314 1315 if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) { 1316 rc = EMSGSIZE; 1317 goto fail2; 1318 } 1319 1320 return (0); 1321 1322 fail2: 1323 EFSYS_PROBE(fail2); 1324 fail1: 1325 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1326 1327 return (rc); 1328 } 1329 1330 __checkReturn efx_rc_t 1331 efx_mcdi_get_board_cfg( 1332 __in efx_nic_t *enp, 1333 __out_opt uint32_t *board_typep, 1334 __out_opt efx_dword_t *capabilitiesp, 1335 __out_ecount_opt(6) uint8_t mac_addrp[6]) 1336 { 1337 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 1338 efx_mcdi_req_t req; 1339 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_BOARD_CFG_IN_LEN, 1340 MC_CMD_GET_BOARD_CFG_OUT_LENMIN); 1341 efx_rc_t rc; 1342 1343 req.emr_cmd = MC_CMD_GET_BOARD_CFG; 1344 req.emr_in_buf = payload; 1345 req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN; 1346 req.emr_out_buf = payload; 1347 req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN; 1348 1349 efx_mcdi_execute(enp, &req); 1350 1351 if (req.emr_rc != 0) { 1352 rc = req.emr_rc; 1353 goto fail1; 1354 } 1355 1356 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) { 1357 rc = EMSGSIZE; 1358 goto fail2; 1359 } 1360 1361 if (mac_addrp != NULL) { 1362 uint8_t *addrp; 1363 1364 if (emip->emi_port == 1) { 1365 addrp = MCDI_OUT2(req, uint8_t, 1366 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0); 1367 } else if (emip->emi_port == 2) { 1368 addrp = MCDI_OUT2(req, uint8_t, 1369 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1); 1370 } else { 1371 rc = EINVAL; 1372 goto fail3; 1373 } 1374 1375 EFX_MAC_ADDR_COPY(mac_addrp, addrp); 1376 } 1377 1378 if (capabilitiesp != NULL) { 1379 if (emip->emi_port == 1) { 1380 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, 1381 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0); 1382 } else if (emip->emi_port == 2) { 1383 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, 1384 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1); 1385 } else { 1386 rc = EINVAL; 1387 goto fail4; 1388 } 1389 } 1390 1391 if (board_typep != NULL) { 1392 *board_typep = MCDI_OUT_DWORD(req, 1393 GET_BOARD_CFG_OUT_BOARD_TYPE); 1394 } 1395 1396 return (0); 1397 1398 fail4: 1399 EFSYS_PROBE(fail4); 1400 fail3: 1401 EFSYS_PROBE(fail3); 1402 fail2: 1403 EFSYS_PROBE(fail2); 1404 fail1: 1405 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1406 1407 return (rc); 1408 } 1409 1410 __checkReturn efx_rc_t 1411 efx_mcdi_get_resource_limits( 1412 __in efx_nic_t *enp, 1413 __out_opt uint32_t *nevqp, 1414 __out_opt uint32_t *nrxqp, 1415 __out_opt uint32_t *ntxqp) 1416 { 1417 efx_mcdi_req_t req; 1418 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_RESOURCE_LIMITS_IN_LEN, 1419 MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN); 1420 efx_rc_t rc; 1421 1422 req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS; 1423 req.emr_in_buf = payload; 1424 req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN; 1425 req.emr_out_buf = payload; 1426 req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN; 1427 1428 efx_mcdi_execute(enp, &req); 1429 1430 if (req.emr_rc != 0) { 1431 rc = req.emr_rc; 1432 goto fail1; 1433 } 1434 1435 if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) { 1436 rc = EMSGSIZE; 1437 goto fail2; 1438 } 1439 1440 if (nevqp != NULL) 1441 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ); 1442 if (nrxqp != NULL) 1443 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ); 1444 if (ntxqp != NULL) 1445 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ); 1446 1447 return (0); 1448 1449 fail2: 1450 EFSYS_PROBE(fail2); 1451 fail1: 1452 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1453 1454 return (rc); 1455 } 1456 1457 __checkReturn efx_rc_t 1458 efx_mcdi_get_phy_cfg( 1459 __in efx_nic_t *enp) 1460 { 1461 efx_port_t *epp = &(enp->en_port); 1462 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 1463 efx_mcdi_req_t req; 1464 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_CFG_IN_LEN, 1465 MC_CMD_GET_PHY_CFG_OUT_LEN); 1466 #if EFSYS_OPT_NAMES 1467 const char *namep; 1468 size_t namelen; 1469 #endif 1470 uint32_t phy_media_type; 1471 efx_rc_t rc; 1472 1473 req.emr_cmd = MC_CMD_GET_PHY_CFG; 1474 req.emr_in_buf = payload; 1475 req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN; 1476 req.emr_out_buf = payload; 1477 req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN; 1478 1479 efx_mcdi_execute(enp, &req); 1480 1481 if (req.emr_rc != 0) { 1482 rc = req.emr_rc; 1483 goto fail1; 1484 } 1485 1486 if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) { 1487 rc = EMSGSIZE; 1488 goto fail2; 1489 } 1490 1491 encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE); 1492 #if EFSYS_OPT_NAMES 1493 namep = MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME); 1494 namelen = MIN(sizeof (encp->enc_phy_name) - 1, 1495 strnlen(namep, MC_CMD_GET_PHY_CFG_OUT_NAME_LEN)); 1496 (void) memset(encp->enc_phy_name, 0, 1497 sizeof (encp->enc_phy_name)); 1498 memcpy(encp->enc_phy_name, namep, namelen); 1499 #endif /* EFSYS_OPT_NAMES */ 1500 (void) memset(encp->enc_phy_revision, 0, 1501 sizeof (encp->enc_phy_revision)); 1502 memcpy(encp->enc_phy_revision, 1503 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION), 1504 MIN(sizeof (encp->enc_phy_revision) - 1, 1505 MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN)); 1506 #if EFSYS_OPT_PHY_LED_CONTROL 1507 encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) | 1508 (1 << EFX_PHY_LED_OFF) | 1509 (1 << EFX_PHY_LED_ON)); 1510 #endif /* EFSYS_OPT_PHY_LED_CONTROL */ 1511 1512 /* Get the media type of the fixed port, if recognised. */ 1513 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI); 1514 EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4); 1515 EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4); 1516 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP); 1517 EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS); 1518 EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T); 1519 EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS); 1520 phy_media_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE); 1521 epp->ep_fixed_port_type = (efx_phy_media_type_t) phy_media_type; 1522 if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES) 1523 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID; 1524 1525 epp->ep_phy_cap_mask = 1526 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP); 1527 #if EFSYS_OPT_PHY_FLAGS 1528 encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS); 1529 #endif /* EFSYS_OPT_PHY_FLAGS */ 1530 1531 encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT); 1532 1533 /* Populate internal state */ 1534 encp->enc_mcdi_mdio_channel = 1535 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL); 1536 1537 #if EFSYS_OPT_PHY_STATS 1538 encp->enc_mcdi_phy_stat_mask = 1539 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK); 1540 #endif /* EFSYS_OPT_PHY_STATS */ 1541 1542 #if EFSYS_OPT_BIST 1543 encp->enc_bist_mask = 0; 1544 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1545 GET_PHY_CFG_OUT_BIST_CABLE_SHORT)) 1546 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT); 1547 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1548 GET_PHY_CFG_OUT_BIST_CABLE_LONG)) 1549 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG); 1550 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1551 GET_PHY_CFG_OUT_BIST)) 1552 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL); 1553 #endif /* EFSYS_OPT_BIST */ 1554 1555 return (0); 1556 1557 fail2: 1558 EFSYS_PROBE(fail2); 1559 fail1: 1560 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1561 1562 return (rc); 1563 } 1564 1565 __checkReturn efx_rc_t 1566 efx_mcdi_firmware_update_supported( 1567 __in efx_nic_t *enp, 1568 __out boolean_t *supportedp) 1569 { 1570 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1571 efx_rc_t rc; 1572 1573 if (emcop != NULL) { 1574 if ((rc = emcop->emco_feature_supported(enp, 1575 EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0) 1576 goto fail1; 1577 } else { 1578 /* Earlier devices always supported updates */ 1579 *supportedp = B_TRUE; 1580 } 1581 1582 return (0); 1583 1584 fail1: 1585 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1586 1587 return (rc); 1588 } 1589 1590 __checkReturn efx_rc_t 1591 efx_mcdi_macaddr_change_supported( 1592 __in efx_nic_t *enp, 1593 __out boolean_t *supportedp) 1594 { 1595 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1596 efx_rc_t rc; 1597 1598 if (emcop != NULL) { 1599 if ((rc = emcop->emco_feature_supported(enp, 1600 EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0) 1601 goto fail1; 1602 } else { 1603 /* Earlier devices always supported MAC changes */ 1604 *supportedp = B_TRUE; 1605 } 1606 1607 return (0); 1608 1609 fail1: 1610 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1611 1612 return (rc); 1613 } 1614 1615 __checkReturn efx_rc_t 1616 efx_mcdi_link_control_supported( 1617 __in efx_nic_t *enp, 1618 __out boolean_t *supportedp) 1619 { 1620 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1621 efx_rc_t rc; 1622 1623 if (emcop != NULL) { 1624 if ((rc = emcop->emco_feature_supported(enp, 1625 EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0) 1626 goto fail1; 1627 } else { 1628 /* Earlier devices always supported link control */ 1629 *supportedp = B_TRUE; 1630 } 1631 1632 return (0); 1633 1634 fail1: 1635 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1636 1637 return (rc); 1638 } 1639 1640 __checkReturn efx_rc_t 1641 efx_mcdi_mac_spoofing_supported( 1642 __in efx_nic_t *enp, 1643 __out boolean_t *supportedp) 1644 { 1645 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1646 efx_rc_t rc; 1647 1648 if (emcop != NULL) { 1649 if ((rc = emcop->emco_feature_supported(enp, 1650 EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0) 1651 goto fail1; 1652 } else { 1653 /* Earlier devices always supported MAC spoofing */ 1654 *supportedp = B_TRUE; 1655 } 1656 1657 return (0); 1658 1659 fail1: 1660 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1661 1662 return (rc); 1663 } 1664 1665 #if EFSYS_OPT_BIST 1666 1667 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 1668 /* 1669 * Enter bist offline mode. This is a fw mode which puts the NIC into a state 1670 * where memory BIST tests can be run and not much else can interfere or happen. 1671 * A reboot is required to exit this mode. 1672 */ 1673 __checkReturn efx_rc_t 1674 efx_mcdi_bist_enable_offline( 1675 __in efx_nic_t *enp) 1676 { 1677 efx_mcdi_req_t req; 1678 efx_rc_t rc; 1679 1680 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0); 1681 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0); 1682 1683 req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST; 1684 req.emr_in_buf = NULL; 1685 req.emr_in_length = 0; 1686 req.emr_out_buf = NULL; 1687 req.emr_out_length = 0; 1688 1689 efx_mcdi_execute(enp, &req); 1690 1691 if (req.emr_rc != 0) { 1692 rc = req.emr_rc; 1693 goto fail1; 1694 } 1695 1696 return (0); 1697 1698 fail1: 1699 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1700 1701 return (rc); 1702 } 1703 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 1704 1705 __checkReturn efx_rc_t 1706 efx_mcdi_bist_start( 1707 __in efx_nic_t *enp, 1708 __in efx_bist_type_t type) 1709 { 1710 efx_mcdi_req_t req; 1711 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_START_BIST_IN_LEN, 1712 MC_CMD_START_BIST_OUT_LEN); 1713 efx_rc_t rc; 1714 1715 req.emr_cmd = MC_CMD_START_BIST; 1716 req.emr_in_buf = payload; 1717 req.emr_in_length = MC_CMD_START_BIST_IN_LEN; 1718 req.emr_out_buf = payload; 1719 req.emr_out_length = MC_CMD_START_BIST_OUT_LEN; 1720 1721 switch (type) { 1722 case EFX_BIST_TYPE_PHY_NORMAL: 1723 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST); 1724 break; 1725 case EFX_BIST_TYPE_PHY_CABLE_SHORT: 1726 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1727 MC_CMD_PHY_BIST_CABLE_SHORT); 1728 break; 1729 case EFX_BIST_TYPE_PHY_CABLE_LONG: 1730 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1731 MC_CMD_PHY_BIST_CABLE_LONG); 1732 break; 1733 case EFX_BIST_TYPE_MC_MEM: 1734 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1735 MC_CMD_MC_MEM_BIST); 1736 break; 1737 case EFX_BIST_TYPE_SAT_MEM: 1738 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1739 MC_CMD_PORT_MEM_BIST); 1740 break; 1741 case EFX_BIST_TYPE_REG: 1742 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1743 MC_CMD_REG_BIST); 1744 break; 1745 default: 1746 EFSYS_ASSERT(0); 1747 } 1748 1749 efx_mcdi_execute(enp, &req); 1750 1751 if (req.emr_rc != 0) { 1752 rc = req.emr_rc; 1753 goto fail1; 1754 } 1755 1756 return (0); 1757 1758 fail1: 1759 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1760 1761 return (rc); 1762 } 1763 1764 #endif /* EFSYS_OPT_BIST */ 1765 1766 /* Enable logging of some events (e.g. link state changes) */ 1767 __checkReturn efx_rc_t 1768 efx_mcdi_log_ctrl( 1769 __in efx_nic_t *enp) 1770 { 1771 efx_mcdi_req_t req; 1772 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_LOG_CTRL_IN_LEN, 1773 MC_CMD_LOG_CTRL_OUT_LEN); 1774 efx_rc_t rc; 1775 1776 req.emr_cmd = MC_CMD_LOG_CTRL; 1777 req.emr_in_buf = payload; 1778 req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN; 1779 req.emr_out_buf = payload; 1780 req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN; 1781 1782 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST, 1783 MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ); 1784 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0); 1785 1786 efx_mcdi_execute(enp, &req); 1787 1788 if (req.emr_rc != 0) { 1789 rc = req.emr_rc; 1790 goto fail1; 1791 } 1792 1793 return (0); 1794 1795 fail1: 1796 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1797 1798 return (rc); 1799 } 1800 1801 #if EFSYS_OPT_MAC_STATS 1802 1803 typedef enum efx_stats_action_e { 1804 EFX_STATS_CLEAR, 1805 EFX_STATS_UPLOAD, 1806 EFX_STATS_ENABLE_NOEVENTS, 1807 EFX_STATS_ENABLE_EVENTS, 1808 EFX_STATS_DISABLE, 1809 } efx_stats_action_t; 1810 1811 static __checkReturn efx_rc_t 1812 efx_mcdi_mac_stats( 1813 __in efx_nic_t *enp, 1814 __in_opt efsys_mem_t *esmp, 1815 __in efx_stats_action_t action, 1816 __in uint16_t period_ms) 1817 { 1818 efx_mcdi_req_t req; 1819 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAC_STATS_IN_LEN, 1820 MC_CMD_MAC_STATS_V2_OUT_DMA_LEN); 1821 int clear = (action == EFX_STATS_CLEAR); 1822 int upload = (action == EFX_STATS_UPLOAD); 1823 int enable = (action == EFX_STATS_ENABLE_NOEVENTS); 1824 int events = (action == EFX_STATS_ENABLE_EVENTS); 1825 int disable = (action == EFX_STATS_DISABLE); 1826 efx_rc_t rc; 1827 1828 req.emr_cmd = MC_CMD_MAC_STATS; 1829 req.emr_in_buf = payload; 1830 req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN; 1831 req.emr_out_buf = payload; 1832 req.emr_out_length = MC_CMD_MAC_STATS_V2_OUT_DMA_LEN; 1833 1834 MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD, 1835 MAC_STATS_IN_DMA, upload, 1836 MAC_STATS_IN_CLEAR, clear, 1837 MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable, 1838 MAC_STATS_IN_PERIODIC_ENABLE, enable | events, 1839 MAC_STATS_IN_PERIODIC_NOEVENT, !events, 1840 MAC_STATS_IN_PERIOD_MS, (enable | events) ? period_ms : 0); 1841 1842 if (enable || events || upload) { 1843 const efx_nic_cfg_t *encp = &enp->en_nic_cfg; 1844 uint32_t bytes; 1845 1846 /* Periodic stats or stats upload require a DMA buffer */ 1847 if (esmp == NULL) { 1848 rc = EINVAL; 1849 goto fail1; 1850 } 1851 1852 if (encp->enc_mac_stats_nstats < MC_CMD_MAC_NSTATS) { 1853 /* MAC stats count too small for legacy MAC stats */ 1854 rc = ENOSPC; 1855 goto fail2; 1856 } 1857 1858 bytes = encp->enc_mac_stats_nstats * sizeof (efx_qword_t); 1859 1860 if (EFSYS_MEM_SIZE(esmp) < bytes) { 1861 /* DMA buffer too small */ 1862 rc = ENOSPC; 1863 goto fail3; 1864 } 1865 1866 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO, 1867 EFSYS_MEM_ADDR(esmp) & 0xffffffff); 1868 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI, 1869 EFSYS_MEM_ADDR(esmp) >> 32); 1870 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes); 1871 } 1872 1873 /* 1874 * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats, 1875 * as this may fail (and leave periodic DMA enabled) if the 1876 * vadapter has already been deleted. 1877 */ 1878 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID, 1879 (disable ? EVB_PORT_ID_NULL : enp->en_vport_id)); 1880 1881 efx_mcdi_execute(enp, &req); 1882 1883 if (req.emr_rc != 0) { 1884 /* EF10: Expect ENOENT if no DMA queues are initialised */ 1885 if ((req.emr_rc != ENOENT) || 1886 (enp->en_rx_qcount + enp->en_tx_qcount != 0)) { 1887 rc = req.emr_rc; 1888 goto fail4; 1889 } 1890 } 1891 1892 return (0); 1893 1894 fail4: 1895 EFSYS_PROBE(fail4); 1896 fail3: 1897 EFSYS_PROBE(fail3); 1898 fail2: 1899 EFSYS_PROBE(fail2); 1900 fail1: 1901 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1902 1903 return (rc); 1904 } 1905 1906 __checkReturn efx_rc_t 1907 efx_mcdi_mac_stats_clear( 1908 __in efx_nic_t *enp) 1909 { 1910 efx_rc_t rc; 1911 1912 if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR, 0)) != 0) 1913 goto fail1; 1914 1915 return (0); 1916 1917 fail1: 1918 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1919 1920 return (rc); 1921 } 1922 1923 __checkReturn efx_rc_t 1924 efx_mcdi_mac_stats_upload( 1925 __in efx_nic_t *enp, 1926 __in efsys_mem_t *esmp) 1927 { 1928 efx_rc_t rc; 1929 1930 /* 1931 * The MC DMAs aggregate statistics for our convenience, so we can 1932 * avoid having to pull the statistics buffer into the cache to 1933 * maintain cumulative statistics. 1934 */ 1935 if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD, 0)) != 0) 1936 goto fail1; 1937 1938 return (0); 1939 1940 fail1: 1941 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1942 1943 return (rc); 1944 } 1945 1946 __checkReturn efx_rc_t 1947 efx_mcdi_mac_stats_periodic( 1948 __in efx_nic_t *enp, 1949 __in efsys_mem_t *esmp, 1950 __in uint16_t period_ms, 1951 __in boolean_t events) 1952 { 1953 efx_rc_t rc; 1954 1955 /* 1956 * The MC DMAs aggregate statistics for our convenience, so we can 1957 * avoid having to pull the statistics buffer into the cache to 1958 * maintain cumulative statistics. 1959 * Huntington uses a fixed 1sec period. 1960 * Medford uses a fixed 1sec period before v6.2.1.1033 firmware. 1961 */ 1962 if (period_ms == 0) 1963 rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE, 0); 1964 else if (events) 1965 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS, 1966 period_ms); 1967 else 1968 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS, 1969 period_ms); 1970 1971 if (rc != 0) 1972 goto fail1; 1973 1974 return (0); 1975 1976 fail1: 1977 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1978 1979 return (rc); 1980 } 1981 1982 #endif /* EFSYS_OPT_MAC_STATS */ 1983 1984 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 1985 1986 /* 1987 * This function returns the pf and vf number of a function. If it is a pf the 1988 * vf number is 0xffff. The vf number is the index of the vf on that 1989 * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0), 1990 * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff). 1991 */ 1992 __checkReturn efx_rc_t 1993 efx_mcdi_get_function_info( 1994 __in efx_nic_t *enp, 1995 __out uint32_t *pfp, 1996 __out_opt uint32_t *vfp) 1997 { 1998 efx_mcdi_req_t req; 1999 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_FUNCTION_INFO_IN_LEN, 2000 MC_CMD_GET_FUNCTION_INFO_OUT_LEN); 2001 efx_rc_t rc; 2002 2003 req.emr_cmd = MC_CMD_GET_FUNCTION_INFO; 2004 req.emr_in_buf = payload; 2005 req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN; 2006 req.emr_out_buf = payload; 2007 req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN; 2008 2009 efx_mcdi_execute(enp, &req); 2010 2011 if (req.emr_rc != 0) { 2012 rc = req.emr_rc; 2013 goto fail1; 2014 } 2015 2016 if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) { 2017 rc = EMSGSIZE; 2018 goto fail2; 2019 } 2020 2021 *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF); 2022 if (vfp != NULL) 2023 *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF); 2024 2025 return (0); 2026 2027 fail2: 2028 EFSYS_PROBE(fail2); 2029 fail1: 2030 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2031 2032 return (rc); 2033 } 2034 2035 __checkReturn efx_rc_t 2036 efx_mcdi_privilege_mask( 2037 __in efx_nic_t *enp, 2038 __in uint32_t pf, 2039 __in uint32_t vf, 2040 __out uint32_t *maskp) 2041 { 2042 efx_mcdi_req_t req; 2043 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_PRIVILEGE_MASK_IN_LEN, 2044 MC_CMD_PRIVILEGE_MASK_OUT_LEN); 2045 efx_rc_t rc; 2046 2047 req.emr_cmd = MC_CMD_PRIVILEGE_MASK; 2048 req.emr_in_buf = payload; 2049 req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN; 2050 req.emr_out_buf = payload; 2051 req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN; 2052 2053 MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION, 2054 PRIVILEGE_MASK_IN_FUNCTION_PF, pf, 2055 PRIVILEGE_MASK_IN_FUNCTION_VF, vf); 2056 2057 efx_mcdi_execute(enp, &req); 2058 2059 if (req.emr_rc != 0) { 2060 rc = req.emr_rc; 2061 goto fail1; 2062 } 2063 2064 if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) { 2065 rc = EMSGSIZE; 2066 goto fail2; 2067 } 2068 2069 *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK); 2070 2071 return (0); 2072 2073 fail2: 2074 EFSYS_PROBE(fail2); 2075 fail1: 2076 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2077 2078 return (rc); 2079 } 2080 2081 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 2082 2083 __checkReturn efx_rc_t 2084 efx_mcdi_set_workaround( 2085 __in efx_nic_t *enp, 2086 __in uint32_t type, 2087 __in boolean_t enabled, 2088 __out_opt uint32_t *flagsp) 2089 { 2090 efx_mcdi_req_t req; 2091 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_WORKAROUND_IN_LEN, 2092 MC_CMD_WORKAROUND_EXT_OUT_LEN); 2093 efx_rc_t rc; 2094 2095 req.emr_cmd = MC_CMD_WORKAROUND; 2096 req.emr_in_buf = payload; 2097 req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN; 2098 req.emr_out_buf = payload; 2099 req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN; 2100 2101 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type); 2102 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0); 2103 2104 efx_mcdi_execute_quiet(enp, &req); 2105 2106 if (req.emr_rc != 0) { 2107 rc = req.emr_rc; 2108 goto fail1; 2109 } 2110 2111 if (flagsp != NULL) { 2112 if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN) 2113 *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS); 2114 else 2115 *flagsp = 0; 2116 } 2117 2118 return (0); 2119 2120 fail1: 2121 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2122 2123 return (rc); 2124 } 2125 2126 __checkReturn efx_rc_t 2127 efx_mcdi_get_workarounds( 2128 __in efx_nic_t *enp, 2129 __out_opt uint32_t *implementedp, 2130 __out_opt uint32_t *enabledp) 2131 { 2132 efx_mcdi_req_t req; 2133 EFX_MCDI_DECLARE_BUF(payload, 0, MC_CMD_GET_WORKAROUNDS_OUT_LEN); 2134 efx_rc_t rc; 2135 2136 req.emr_cmd = MC_CMD_GET_WORKAROUNDS; 2137 req.emr_in_buf = NULL; 2138 req.emr_in_length = 0; 2139 req.emr_out_buf = payload; 2140 req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN; 2141 2142 efx_mcdi_execute(enp, &req); 2143 2144 if (req.emr_rc != 0) { 2145 rc = req.emr_rc; 2146 goto fail1; 2147 } 2148 2149 if (implementedp != NULL) { 2150 *implementedp = 2151 MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED); 2152 } 2153 2154 if (enabledp != NULL) { 2155 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED); 2156 } 2157 2158 return (0); 2159 2160 fail1: 2161 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2162 2163 return (rc); 2164 } 2165 2166 /* 2167 * Size of media information page in accordance with SFF-8472 and SFF-8436. 2168 * It is used in MCDI interface as well. 2169 */ 2170 #define EFX_PHY_MEDIA_INFO_PAGE_SIZE 0x80 2171 2172 /* 2173 * Transceiver identifiers from SFF-8024 Table 4-1. 2174 */ 2175 #define EFX_SFF_TRANSCEIVER_ID_SFP 0x03 /* SFP/SFP+/SFP28 */ 2176 #define EFX_SFF_TRANSCEIVER_ID_QSFP 0x0c /* QSFP */ 2177 #define EFX_SFF_TRANSCEIVER_ID_QSFP_PLUS 0x0d /* QSFP+ or later */ 2178 #define EFX_SFF_TRANSCEIVER_ID_QSFP28 0x11 /* QSFP28 or later */ 2179 2180 static __checkReturn efx_rc_t 2181 efx_mcdi_get_phy_media_info( 2182 __in efx_nic_t *enp, 2183 __in uint32_t mcdi_page, 2184 __in uint8_t offset, 2185 __in uint8_t len, 2186 __out_bcount(len) uint8_t *data) 2187 { 2188 efx_mcdi_req_t req; 2189 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN, 2190 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN( 2191 EFX_PHY_MEDIA_INFO_PAGE_SIZE)); 2192 efx_rc_t rc; 2193 2194 EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2195 2196 req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO; 2197 req.emr_in_buf = payload; 2198 req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN; 2199 req.emr_out_buf = payload; 2200 req.emr_out_length = 2201 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2202 2203 MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page); 2204 2205 efx_mcdi_execute(enp, &req); 2206 2207 if (req.emr_rc != 0) { 2208 rc = req.emr_rc; 2209 goto fail1; 2210 } 2211 2212 if (req.emr_out_length_used != 2213 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) { 2214 rc = EMSGSIZE; 2215 goto fail2; 2216 } 2217 2218 if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) != 2219 EFX_PHY_MEDIA_INFO_PAGE_SIZE) { 2220 rc = EIO; 2221 goto fail3; 2222 } 2223 2224 memcpy(data, 2225 MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset, 2226 len); 2227 2228 return (0); 2229 2230 fail3: 2231 EFSYS_PROBE(fail3); 2232 fail2: 2233 EFSYS_PROBE(fail2); 2234 fail1: 2235 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2236 2237 return (rc); 2238 } 2239 2240 __checkReturn efx_rc_t 2241 efx_mcdi_phy_module_get_info( 2242 __in efx_nic_t *enp, 2243 __in uint8_t dev_addr, 2244 __in size_t offset, 2245 __in size_t len, 2246 __out_bcount(len) uint8_t *data) 2247 { 2248 efx_port_t *epp = &(enp->en_port); 2249 efx_rc_t rc; 2250 uint32_t mcdi_lower_page; 2251 uint32_t mcdi_upper_page; 2252 uint8_t id; 2253 2254 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 2255 2256 /* 2257 * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages. 2258 * Offset plus length interface allows to access page 0 only. 2259 * I.e. non-zero upper pages are not accessible. 2260 * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6 2261 * QSFP+ Memory Map for details on how information is structured 2262 * and accessible. 2263 */ 2264 switch (epp->ep_fixed_port_type) { 2265 case EFX_PHY_MEDIA_SFP_PLUS: 2266 case EFX_PHY_MEDIA_QSFP_PLUS: 2267 /* Port type supports modules */ 2268 break; 2269 default: 2270 rc = ENOTSUP; 2271 goto fail1; 2272 } 2273 2274 /* 2275 * For all supported port types, MCDI page 0 offset 0 holds the 2276 * transceiver identifier. Probe to determine the data layout. 2277 * Definitions from SFF-8024 Table 4-1. 2278 */ 2279 rc = efx_mcdi_get_phy_media_info(enp, 0, 0, sizeof (id), &id); 2280 if (rc != 0) 2281 goto fail2; 2282 2283 switch (id) { 2284 case EFX_SFF_TRANSCEIVER_ID_SFP: 2285 /* 2286 * In accordance with SFF-8472 Diagnostic Monitoring 2287 * Interface for Optical Transceivers section 4 Memory 2288 * Organization two 2-wire addresses are defined. 2289 */ 2290 switch (dev_addr) { 2291 /* Base information */ 2292 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE: 2293 /* 2294 * MCDI page 0 should be used to access lower 2295 * page 0 (0x00 - 0x7f) at the device address 0xA0. 2296 */ 2297 mcdi_lower_page = 0; 2298 /* 2299 * MCDI page 1 should be used to access upper 2300 * page 0 (0x80 - 0xff) at the device address 0xA0. 2301 */ 2302 mcdi_upper_page = 1; 2303 break; 2304 /* Diagnostics */ 2305 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM: 2306 /* 2307 * MCDI page 2 should be used to access lower 2308 * page 0 (0x00 - 0x7f) at the device address 0xA2. 2309 */ 2310 mcdi_lower_page = 2; 2311 /* 2312 * MCDI page 3 should be used to access upper 2313 * page 0 (0x80 - 0xff) at the device address 0xA2. 2314 */ 2315 mcdi_upper_page = 3; 2316 break; 2317 default: 2318 rc = ENOTSUP; 2319 goto fail3; 2320 } 2321 break; 2322 case EFX_SFF_TRANSCEIVER_ID_QSFP: 2323 case EFX_SFF_TRANSCEIVER_ID_QSFP_PLUS: 2324 case EFX_SFF_TRANSCEIVER_ID_QSFP28: 2325 switch (dev_addr) { 2326 case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP: 2327 /* 2328 * MCDI page -1 should be used to access lower page 0 2329 * (0x00 - 0x7f). 2330 */ 2331 mcdi_lower_page = (uint32_t)-1; 2332 /* 2333 * MCDI page 0 should be used to access upper page 0 2334 * (0x80h - 0xff). 2335 */ 2336 mcdi_upper_page = 0; 2337 break; 2338 default: 2339 rc = ENOTSUP; 2340 goto fail3; 2341 } 2342 break; 2343 default: 2344 rc = ENOTSUP; 2345 goto fail3; 2346 } 2347 2348 EFX_STATIC_ASSERT(EFX_PHY_MEDIA_INFO_PAGE_SIZE <= 0xFF); 2349 2350 if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) { 2351 size_t read_len = 2352 MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset); 2353 2354 rc = efx_mcdi_get_phy_media_info(enp, 2355 mcdi_lower_page, (uint8_t)offset, (uint8_t)read_len, data); 2356 if (rc != 0) 2357 goto fail4; 2358 2359 data += read_len; 2360 len -= read_len; 2361 2362 offset = 0; 2363 } else { 2364 offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE; 2365 } 2366 2367 if (len > 0) { 2368 EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2369 EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2370 2371 rc = efx_mcdi_get_phy_media_info(enp, 2372 mcdi_upper_page, (uint8_t)offset, (uint8_t)len, data); 2373 if (rc != 0) 2374 goto fail5; 2375 } 2376 2377 return (0); 2378 2379 fail5: 2380 EFSYS_PROBE(fail5); 2381 fail4: 2382 EFSYS_PROBE(fail4); 2383 fail3: 2384 EFSYS_PROBE(fail3); 2385 fail2: 2386 EFSYS_PROBE(fail2); 2387 fail1: 2388 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2389 2390 return (rc); 2391 } 2392 2393 #endif /* EFSYS_OPT_MCDI */ 2394