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