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