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