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 /* 818 * Return proxy handle from MCDI request that returned with error 819 * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching 820 * PROXY_RESPONSE event. 821 */ 822 if ((emrp == NULL) || (handlep == NULL)) { 823 rc = EINVAL; 824 goto fail1; 825 } 826 if ((emrp->emr_rc != 0) && 827 (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) { 828 *handlep = emrp->emr_proxy_handle; 829 rc = 0; 830 } else { 831 *handlep = 0; 832 rc = ENOENT; 833 } 834 return (rc); 835 836 fail1: 837 EFSYS_PROBE1(fail1, efx_rc_t, rc); 838 return (rc); 839 } 840 841 void 842 efx_mcdi_ev_proxy_response( 843 __in efx_nic_t *enp, 844 __in unsigned int handle, 845 __in unsigned int status) 846 { 847 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 848 efx_rc_t rc; 849 850 /* 851 * Handle results of an authorization request for a privileged MCDI 852 * command. If authorization was granted then we must re-issue the 853 * original MCDI request. If authorization failed or timed out, 854 * then the original MCDI request should be completed with the 855 * result code from this event. 856 */ 857 rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status); 858 859 emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc); 860 } 861 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ 862 863 void 864 efx_mcdi_ev_death( 865 __in efx_nic_t *enp, 866 __in int rc) 867 { 868 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 869 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 870 efx_mcdi_req_t *emrp = NULL; 871 boolean_t ev_cpl; 872 efsys_lock_state_t state; 873 874 /* 875 * The MCDI request (if there is one) has been terminated, either 876 * by a BADASSERT or REBOOT event. 877 * 878 * If there is an outstanding event-completed MCDI operation, then we 879 * will never receive the completion event (because both MCDI 880 * completions and BADASSERT events are sent to the same evq). So 881 * complete this MCDI op. 882 * 883 * This function might run in parallel with efx_mcdi_request_poll() 884 * for poll completed mcdi requests, and also with 885 * efx_mcdi_request_start() for post-watchdog completions. 886 */ 887 EFSYS_LOCK(enp->en_eslp, state); 888 emrp = emip->emi_pending_req; 889 ev_cpl = emip->emi_ev_cpl; 890 if (emrp != NULL && emip->emi_ev_cpl) { 891 emip->emi_pending_req = NULL; 892 893 emrp->emr_out_length_used = 0; 894 emrp->emr_rc = rc; 895 ++emip->emi_aborted; 896 } 897 898 /* 899 * Since we're running in parallel with a request, consume the 900 * status word before dropping the lock. 901 */ 902 if (rc == EIO || rc == EINTR) { 903 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US); 904 (void) efx_mcdi_poll_reboot(enp); 905 emip->emi_new_epoch = B_TRUE; 906 } 907 908 EFSYS_UNLOCK(enp->en_eslp, state); 909 910 efx_mcdi_raise_exception(enp, emrp, rc); 911 912 if (emrp != NULL && ev_cpl) 913 emtp->emt_ev_cpl(emtp->emt_context); 914 } 915 916 __checkReturn efx_rc_t 917 efx_mcdi_version( 918 __in efx_nic_t *enp, 919 __out_ecount_opt(4) uint16_t versionp[4], 920 __out_opt uint32_t *buildp, 921 __out_opt efx_mcdi_boot_t *statusp) 922 { 923 efx_mcdi_req_t req; 924 uint8_t payload[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN, 925 MC_CMD_GET_VERSION_OUT_LEN), 926 MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN, 927 MC_CMD_GET_BOOT_STATUS_OUT_LEN))]; 928 efx_word_t *ver_words; 929 uint16_t version[4]; 930 uint32_t build; 931 efx_mcdi_boot_t status; 932 efx_rc_t rc; 933 934 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 935 936 (void) memset(payload, 0, sizeof (payload)); 937 req.emr_cmd = MC_CMD_GET_VERSION; 938 req.emr_in_buf = payload; 939 req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN; 940 req.emr_out_buf = payload; 941 req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN; 942 943 efx_mcdi_execute(enp, &req); 944 945 if (req.emr_rc != 0) { 946 rc = req.emr_rc; 947 goto fail1; 948 } 949 950 /* bootrom support */ 951 if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) { 952 version[0] = version[1] = version[2] = version[3] = 0; 953 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 954 955 goto version; 956 } 957 958 if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) { 959 rc = EMSGSIZE; 960 goto fail2; 961 } 962 963 ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION); 964 version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0); 965 version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0); 966 version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0); 967 version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0); 968 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 969 970 version: 971 /* The bootrom doesn't understand BOOT_STATUS */ 972 if (MC_FW_VERSION_IS_BOOTLOADER(build)) { 973 status = EFX_MCDI_BOOT_ROM; 974 goto out; 975 } 976 977 (void) memset(payload, 0, sizeof (payload)); 978 req.emr_cmd = MC_CMD_GET_BOOT_STATUS; 979 req.emr_in_buf = payload; 980 req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN; 981 req.emr_out_buf = payload; 982 req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN; 983 984 efx_mcdi_execute_quiet(enp, &req); 985 986 if (req.emr_rc == EACCES) { 987 /* Unprivileged functions cannot access BOOT_STATUS */ 988 status = EFX_MCDI_BOOT_PRIMARY; 989 version[0] = version[1] = version[2] = version[3] = 0; 990 build = 0; 991 goto out; 992 } 993 994 if (req.emr_rc != 0) { 995 rc = req.emr_rc; 996 goto fail3; 997 } 998 999 if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) { 1000 rc = EMSGSIZE; 1001 goto fail4; 1002 } 1003 1004 if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS, 1005 GET_BOOT_STATUS_OUT_FLAGS_PRIMARY)) 1006 status = EFX_MCDI_BOOT_PRIMARY; 1007 else 1008 status = EFX_MCDI_BOOT_SECONDARY; 1009 1010 out: 1011 if (versionp != NULL) 1012 memcpy(versionp, version, sizeof (version)); 1013 if (buildp != NULL) 1014 *buildp = build; 1015 if (statusp != NULL) 1016 *statusp = status; 1017 1018 return (0); 1019 1020 fail4: 1021 EFSYS_PROBE(fail4); 1022 fail3: 1023 EFSYS_PROBE(fail3); 1024 fail2: 1025 EFSYS_PROBE(fail2); 1026 fail1: 1027 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1028 1029 return (rc); 1030 } 1031 1032 __checkReturn efx_rc_t 1033 efx_mcdi_get_capabilities( 1034 __in efx_nic_t *enp, 1035 __out_opt uint32_t *flagsp, 1036 __out_opt uint16_t *rx_dpcpu_fw_idp, 1037 __out_opt uint16_t *tx_dpcpu_fw_idp, 1038 __out_opt uint32_t *flags2p, 1039 __out_opt uint32_t *tso2ncp) 1040 { 1041 efx_mcdi_req_t req; 1042 uint8_t payload[MAX(MC_CMD_GET_CAPABILITIES_IN_LEN, 1043 MC_CMD_GET_CAPABILITIES_V2_OUT_LEN)]; 1044 boolean_t v2_capable; 1045 efx_rc_t rc; 1046 1047 (void) memset(payload, 0, sizeof (payload)); 1048 req.emr_cmd = MC_CMD_GET_CAPABILITIES; 1049 req.emr_in_buf = payload; 1050 req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN; 1051 req.emr_out_buf = payload; 1052 req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_OUT_LEN; 1053 1054 efx_mcdi_execute_quiet(enp, &req); 1055 1056 if (req.emr_rc != 0) { 1057 rc = req.emr_rc; 1058 goto fail1; 1059 } 1060 1061 if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) { 1062 rc = EMSGSIZE; 1063 goto fail2; 1064 } 1065 1066 if (flagsp != NULL) 1067 *flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1); 1068 1069 if (rx_dpcpu_fw_idp != NULL) 1070 *rx_dpcpu_fw_idp = MCDI_OUT_WORD(req, 1071 GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID); 1072 1073 if (tx_dpcpu_fw_idp != NULL) 1074 *tx_dpcpu_fw_idp = MCDI_OUT_WORD(req, 1075 GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID); 1076 1077 if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN) 1078 v2_capable = B_FALSE; 1079 else 1080 v2_capable = B_TRUE; 1081 1082 if (flags2p != NULL) { 1083 *flags2p = (v2_capable) ? 1084 MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2) : 1085 0; 1086 } 1087 1088 if (tso2ncp != NULL) { 1089 *tso2ncp = (v2_capable) ? 1090 MCDI_OUT_WORD(req, 1091 GET_CAPABILITIES_V2_OUT_TX_TSO_V2_N_CONTEXTS) : 1092 0; 1093 } 1094 1095 return (0); 1096 1097 fail2: 1098 EFSYS_PROBE(fail2); 1099 fail1: 1100 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1101 1102 return (rc); 1103 } 1104 1105 static __checkReturn efx_rc_t 1106 efx_mcdi_do_reboot( 1107 __in efx_nic_t *enp, 1108 __in boolean_t after_assertion) 1109 { 1110 uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)]; 1111 efx_mcdi_req_t req; 1112 efx_rc_t rc; 1113 1114 /* 1115 * We could require the caller to have caused en_mod_flags=0 to 1116 * call this function. This doesn't help the other port though, 1117 * who's about to get the MC ripped out from underneath them. 1118 * Since they have to cope with the subsequent fallout of MCDI 1119 * failures, we should as well. 1120 */ 1121 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 1122 1123 (void) memset(payload, 0, sizeof (payload)); 1124 req.emr_cmd = MC_CMD_REBOOT; 1125 req.emr_in_buf = payload; 1126 req.emr_in_length = MC_CMD_REBOOT_IN_LEN; 1127 req.emr_out_buf = payload; 1128 req.emr_out_length = MC_CMD_REBOOT_OUT_LEN; 1129 1130 MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS, 1131 (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0)); 1132 1133 efx_mcdi_execute_quiet(enp, &req); 1134 1135 if (req.emr_rc == EACCES) { 1136 /* Unprivileged functions cannot reboot the MC. */ 1137 goto out; 1138 } 1139 1140 /* A successful reboot request returns EIO. */ 1141 if (req.emr_rc != 0 && req.emr_rc != EIO) { 1142 rc = req.emr_rc; 1143 goto fail1; 1144 } 1145 1146 out: 1147 return (0); 1148 1149 fail1: 1150 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1151 1152 return (rc); 1153 } 1154 1155 __checkReturn efx_rc_t 1156 efx_mcdi_reboot( 1157 __in efx_nic_t *enp) 1158 { 1159 return (efx_mcdi_do_reboot(enp, B_FALSE)); 1160 } 1161 1162 __checkReturn efx_rc_t 1163 efx_mcdi_exit_assertion_handler( 1164 __in efx_nic_t *enp) 1165 { 1166 return (efx_mcdi_do_reboot(enp, B_TRUE)); 1167 } 1168 1169 __checkReturn efx_rc_t 1170 efx_mcdi_read_assertion( 1171 __in efx_nic_t *enp) 1172 { 1173 efx_mcdi_req_t req; 1174 uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN, 1175 MC_CMD_GET_ASSERTS_OUT_LEN)]; 1176 const char *reason; 1177 unsigned int flags; 1178 unsigned int index; 1179 unsigned int ofst; 1180 int retry; 1181 efx_rc_t rc; 1182 1183 /* 1184 * Before we attempt to chat to the MC, we should verify that the MC 1185 * isn't in its assertion handler, either due to a previous reboot, 1186 * or because we're reinitializing due to an eec_exception(). 1187 * 1188 * Use GET_ASSERTS to read any assertion state that may be present. 1189 * Retry this command twice. Once because a boot-time assertion failure 1190 * might cause the 1st MCDI request to fail. And once again because 1191 * we might race with efx_mcdi_exit_assertion_handler() running on 1192 * partner port(s) on the same NIC. 1193 */ 1194 retry = 2; 1195 do { 1196 (void) memset(payload, 0, sizeof (payload)); 1197 req.emr_cmd = MC_CMD_GET_ASSERTS; 1198 req.emr_in_buf = payload; 1199 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN; 1200 req.emr_out_buf = payload; 1201 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN; 1202 1203 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1); 1204 efx_mcdi_execute_quiet(enp, &req); 1205 1206 } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0); 1207 1208 if (req.emr_rc != 0) { 1209 if (req.emr_rc == EACCES) { 1210 /* Unprivileged functions cannot clear assertions. */ 1211 goto out; 1212 } 1213 rc = req.emr_rc; 1214 goto fail1; 1215 } 1216 1217 if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) { 1218 rc = EMSGSIZE; 1219 goto fail2; 1220 } 1221 1222 /* Print out any assertion state recorded */ 1223 flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS); 1224 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) 1225 return (0); 1226 1227 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL) 1228 ? "system-level assertion" 1229 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL) 1230 ? "thread-level assertion" 1231 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED) 1232 ? "watchdog reset" 1233 : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP) 1234 ? "illegal address trap" 1235 : "unknown assertion"; 1236 EFSYS_PROBE3(mcpu_assertion, 1237 const char *, reason, unsigned int, 1238 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS), 1239 unsigned int, 1240 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS)); 1241 1242 /* Print out the registers (r1 ... r31) */ 1243 ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST; 1244 for (index = 1; 1245 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM; 1246 index++) { 1247 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int, 1248 EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst), 1249 EFX_DWORD_0)); 1250 ofst += sizeof (efx_dword_t); 1251 } 1252 EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN); 1253 1254 out: 1255 return (0); 1256 1257 fail2: 1258 EFSYS_PROBE(fail2); 1259 fail1: 1260 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1261 1262 return (rc); 1263 } 1264 1265 1266 /* 1267 * Internal routines for for specific MCDI requests. 1268 */ 1269 1270 __checkReturn efx_rc_t 1271 efx_mcdi_drv_attach( 1272 __in efx_nic_t *enp, 1273 __in boolean_t attach) 1274 { 1275 efx_mcdi_req_t req; 1276 uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN, 1277 MC_CMD_DRV_ATTACH_EXT_OUT_LEN)]; 1278 efx_rc_t rc; 1279 1280 (void) memset(payload, 0, sizeof (payload)); 1281 req.emr_cmd = MC_CMD_DRV_ATTACH; 1282 req.emr_in_buf = payload; 1283 req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN; 1284 req.emr_out_buf = payload; 1285 req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN; 1286 1287 /* 1288 * Use DONT_CARE for the datapath firmware type to ensure that the 1289 * driver can attach to an unprivileged function. The datapath firmware 1290 * type to use is controlled by the 'sfboot' utility. 1291 */ 1292 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0); 1293 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1); 1294 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_DONT_CARE); 1295 1296 efx_mcdi_execute(enp, &req); 1297 1298 if (req.emr_rc != 0) { 1299 rc = req.emr_rc; 1300 goto fail1; 1301 } 1302 1303 if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) { 1304 rc = EMSGSIZE; 1305 goto fail2; 1306 } 1307 1308 return (0); 1309 1310 fail2: 1311 EFSYS_PROBE(fail2); 1312 fail1: 1313 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1314 1315 return (rc); 1316 } 1317 1318 __checkReturn efx_rc_t 1319 efx_mcdi_get_board_cfg( 1320 __in efx_nic_t *enp, 1321 __out_opt uint32_t *board_typep, 1322 __out_opt efx_dword_t *capabilitiesp, 1323 __out_ecount_opt(6) uint8_t mac_addrp[6]) 1324 { 1325 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 1326 efx_mcdi_req_t req; 1327 uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN, 1328 MC_CMD_GET_BOARD_CFG_OUT_LENMIN)]; 1329 efx_rc_t rc; 1330 1331 (void) memset(payload, 0, sizeof (payload)); 1332 req.emr_cmd = MC_CMD_GET_BOARD_CFG; 1333 req.emr_in_buf = payload; 1334 req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN; 1335 req.emr_out_buf = payload; 1336 req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN; 1337 1338 efx_mcdi_execute(enp, &req); 1339 1340 if (req.emr_rc != 0) { 1341 rc = req.emr_rc; 1342 goto fail1; 1343 } 1344 1345 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) { 1346 rc = EMSGSIZE; 1347 goto fail2; 1348 } 1349 1350 if (mac_addrp != NULL) { 1351 uint8_t *addrp; 1352 1353 if (emip->emi_port == 1) { 1354 addrp = MCDI_OUT2(req, uint8_t, 1355 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0); 1356 } else if (emip->emi_port == 2) { 1357 addrp = MCDI_OUT2(req, uint8_t, 1358 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1); 1359 } else { 1360 rc = EINVAL; 1361 goto fail3; 1362 } 1363 1364 EFX_MAC_ADDR_COPY(mac_addrp, addrp); 1365 } 1366 1367 if (capabilitiesp != NULL) { 1368 if (emip->emi_port == 1) { 1369 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, 1370 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0); 1371 } else if (emip->emi_port == 2) { 1372 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, 1373 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1); 1374 } else { 1375 rc = EINVAL; 1376 goto fail4; 1377 } 1378 } 1379 1380 if (board_typep != NULL) { 1381 *board_typep = MCDI_OUT_DWORD(req, 1382 GET_BOARD_CFG_OUT_BOARD_TYPE); 1383 } 1384 1385 return (0); 1386 1387 fail4: 1388 EFSYS_PROBE(fail4); 1389 fail3: 1390 EFSYS_PROBE(fail3); 1391 fail2: 1392 EFSYS_PROBE(fail2); 1393 fail1: 1394 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1395 1396 return (rc); 1397 } 1398 1399 __checkReturn efx_rc_t 1400 efx_mcdi_get_resource_limits( 1401 __in efx_nic_t *enp, 1402 __out_opt uint32_t *nevqp, 1403 __out_opt uint32_t *nrxqp, 1404 __out_opt uint32_t *ntxqp) 1405 { 1406 efx_mcdi_req_t req; 1407 uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN, 1408 MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)]; 1409 efx_rc_t rc; 1410 1411 (void) memset(payload, 0, sizeof (payload)); 1412 req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS; 1413 req.emr_in_buf = payload; 1414 req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN; 1415 req.emr_out_buf = payload; 1416 req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN; 1417 1418 efx_mcdi_execute(enp, &req); 1419 1420 if (req.emr_rc != 0) { 1421 rc = req.emr_rc; 1422 goto fail1; 1423 } 1424 1425 if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) { 1426 rc = EMSGSIZE; 1427 goto fail2; 1428 } 1429 1430 if (nevqp != NULL) 1431 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ); 1432 if (nrxqp != NULL) 1433 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ); 1434 if (ntxqp != NULL) 1435 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ); 1436 1437 return (0); 1438 1439 fail2: 1440 EFSYS_PROBE(fail2); 1441 fail1: 1442 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1443 1444 return (rc); 1445 } 1446 1447 __checkReturn efx_rc_t 1448 efx_mcdi_get_phy_cfg( 1449 __in efx_nic_t *enp) 1450 { 1451 efx_port_t *epp = &(enp->en_port); 1452 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 1453 efx_mcdi_req_t req; 1454 uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN, 1455 MC_CMD_GET_PHY_CFG_OUT_LEN)]; 1456 efx_rc_t rc; 1457 1458 (void) memset(payload, 0, sizeof (payload)); 1459 req.emr_cmd = MC_CMD_GET_PHY_CFG; 1460 req.emr_in_buf = payload; 1461 req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN; 1462 req.emr_out_buf = payload; 1463 req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN; 1464 1465 efx_mcdi_execute(enp, &req); 1466 1467 if (req.emr_rc != 0) { 1468 rc = req.emr_rc; 1469 goto fail1; 1470 } 1471 1472 if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) { 1473 rc = EMSGSIZE; 1474 goto fail2; 1475 } 1476 1477 encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE); 1478 #if EFSYS_OPT_NAMES 1479 (void) strncpy(encp->enc_phy_name, 1480 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME), 1481 MIN(sizeof (encp->enc_phy_name) - 1, 1482 MC_CMD_GET_PHY_CFG_OUT_NAME_LEN)); 1483 #endif /* EFSYS_OPT_NAMES */ 1484 (void) memset(encp->enc_phy_revision, 0, 1485 sizeof (encp->enc_phy_revision)); 1486 memcpy(encp->enc_phy_revision, 1487 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION), 1488 MIN(sizeof (encp->enc_phy_revision) - 1, 1489 MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN)); 1490 #if EFSYS_OPT_PHY_LED_CONTROL 1491 encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) | 1492 (1 << EFX_PHY_LED_OFF) | 1493 (1 << EFX_PHY_LED_ON)); 1494 #endif /* EFSYS_OPT_PHY_LED_CONTROL */ 1495 1496 /* Get the media type of the fixed port, if recognised. */ 1497 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI); 1498 EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4); 1499 EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4); 1500 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP); 1501 EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS); 1502 EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T); 1503 EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS); 1504 epp->ep_fixed_port_type = 1505 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE); 1506 if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES) 1507 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID; 1508 1509 epp->ep_phy_cap_mask = 1510 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP); 1511 #if EFSYS_OPT_PHY_FLAGS 1512 encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS); 1513 #endif /* EFSYS_OPT_PHY_FLAGS */ 1514 1515 encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT); 1516 1517 /* Populate internal state */ 1518 encp->enc_mcdi_mdio_channel = 1519 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL); 1520 1521 #if EFSYS_OPT_PHY_STATS 1522 encp->enc_mcdi_phy_stat_mask = 1523 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK); 1524 #endif /* EFSYS_OPT_PHY_STATS */ 1525 1526 #if EFSYS_OPT_BIST 1527 encp->enc_bist_mask = 0; 1528 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1529 GET_PHY_CFG_OUT_BIST_CABLE_SHORT)) 1530 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT); 1531 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1532 GET_PHY_CFG_OUT_BIST_CABLE_LONG)) 1533 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG); 1534 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1535 GET_PHY_CFG_OUT_BIST)) 1536 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL); 1537 #endif /* EFSYS_OPT_BIST */ 1538 1539 return (0); 1540 1541 fail2: 1542 EFSYS_PROBE(fail2); 1543 fail1: 1544 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1545 1546 return (rc); 1547 } 1548 1549 __checkReturn efx_rc_t 1550 efx_mcdi_firmware_update_supported( 1551 __in efx_nic_t *enp, 1552 __out boolean_t *supportedp) 1553 { 1554 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1555 efx_rc_t rc; 1556 1557 if (emcop != NULL) { 1558 if ((rc = emcop->emco_feature_supported(enp, 1559 EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0) 1560 goto fail1; 1561 } else { 1562 /* Earlier devices always supported updates */ 1563 *supportedp = B_TRUE; 1564 } 1565 1566 return (0); 1567 1568 fail1: 1569 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1570 1571 return (rc); 1572 } 1573 1574 __checkReturn efx_rc_t 1575 efx_mcdi_macaddr_change_supported( 1576 __in efx_nic_t *enp, 1577 __out boolean_t *supportedp) 1578 { 1579 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1580 efx_rc_t rc; 1581 1582 if (emcop != NULL) { 1583 if ((rc = emcop->emco_feature_supported(enp, 1584 EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0) 1585 goto fail1; 1586 } else { 1587 /* Earlier devices always supported MAC changes */ 1588 *supportedp = B_TRUE; 1589 } 1590 1591 return (0); 1592 1593 fail1: 1594 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1595 1596 return (rc); 1597 } 1598 1599 __checkReturn efx_rc_t 1600 efx_mcdi_link_control_supported( 1601 __in efx_nic_t *enp, 1602 __out boolean_t *supportedp) 1603 { 1604 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1605 efx_rc_t rc; 1606 1607 if (emcop != NULL) { 1608 if ((rc = emcop->emco_feature_supported(enp, 1609 EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0) 1610 goto fail1; 1611 } else { 1612 /* Earlier devices always supported link control */ 1613 *supportedp = B_TRUE; 1614 } 1615 1616 return (0); 1617 1618 fail1: 1619 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1620 1621 return (rc); 1622 } 1623 1624 __checkReturn efx_rc_t 1625 efx_mcdi_mac_spoofing_supported( 1626 __in efx_nic_t *enp, 1627 __out boolean_t *supportedp) 1628 { 1629 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1630 efx_rc_t rc; 1631 1632 if (emcop != NULL) { 1633 if ((rc = emcop->emco_feature_supported(enp, 1634 EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0) 1635 goto fail1; 1636 } else { 1637 /* Earlier devices always supported MAC spoofing */ 1638 *supportedp = B_TRUE; 1639 } 1640 1641 return (0); 1642 1643 fail1: 1644 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1645 1646 return (rc); 1647 } 1648 1649 #if EFSYS_OPT_BIST 1650 1651 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 1652 /* 1653 * Enter bist offline mode. This is a fw mode which puts the NIC into a state 1654 * where memory BIST tests can be run and not much else can interfere or happen. 1655 * A reboot is required to exit this mode. 1656 */ 1657 __checkReturn efx_rc_t 1658 efx_mcdi_bist_enable_offline( 1659 __in efx_nic_t *enp) 1660 { 1661 efx_mcdi_req_t req; 1662 efx_rc_t rc; 1663 1664 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0); 1665 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0); 1666 1667 req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST; 1668 req.emr_in_buf = NULL; 1669 req.emr_in_length = 0; 1670 req.emr_out_buf = NULL; 1671 req.emr_out_length = 0; 1672 1673 efx_mcdi_execute(enp, &req); 1674 1675 if (req.emr_rc != 0) { 1676 rc = req.emr_rc; 1677 goto fail1; 1678 } 1679 1680 return (0); 1681 1682 fail1: 1683 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1684 1685 return (rc); 1686 } 1687 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 1688 1689 __checkReturn efx_rc_t 1690 efx_mcdi_bist_start( 1691 __in efx_nic_t *enp, 1692 __in efx_bist_type_t type) 1693 { 1694 efx_mcdi_req_t req; 1695 uint8_t payload[MAX(MC_CMD_START_BIST_IN_LEN, 1696 MC_CMD_START_BIST_OUT_LEN)]; 1697 efx_rc_t rc; 1698 1699 (void) memset(payload, 0, sizeof (payload)); 1700 req.emr_cmd = MC_CMD_START_BIST; 1701 req.emr_in_buf = payload; 1702 req.emr_in_length = MC_CMD_START_BIST_IN_LEN; 1703 req.emr_out_buf = payload; 1704 req.emr_out_length = MC_CMD_START_BIST_OUT_LEN; 1705 1706 switch (type) { 1707 case EFX_BIST_TYPE_PHY_NORMAL: 1708 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST); 1709 break; 1710 case EFX_BIST_TYPE_PHY_CABLE_SHORT: 1711 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1712 MC_CMD_PHY_BIST_CABLE_SHORT); 1713 break; 1714 case EFX_BIST_TYPE_PHY_CABLE_LONG: 1715 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1716 MC_CMD_PHY_BIST_CABLE_LONG); 1717 break; 1718 case EFX_BIST_TYPE_MC_MEM: 1719 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1720 MC_CMD_MC_MEM_BIST); 1721 break; 1722 case EFX_BIST_TYPE_SAT_MEM: 1723 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1724 MC_CMD_PORT_MEM_BIST); 1725 break; 1726 case EFX_BIST_TYPE_REG: 1727 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1728 MC_CMD_REG_BIST); 1729 break; 1730 default: 1731 EFSYS_ASSERT(0); 1732 } 1733 1734 efx_mcdi_execute(enp, &req); 1735 1736 if (req.emr_rc != 0) { 1737 rc = req.emr_rc; 1738 goto fail1; 1739 } 1740 1741 return (0); 1742 1743 fail1: 1744 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1745 1746 return (rc); 1747 } 1748 1749 #endif /* EFSYS_OPT_BIST */ 1750 1751 1752 /* Enable logging of some events (e.g. link state changes) */ 1753 __checkReturn efx_rc_t 1754 efx_mcdi_log_ctrl( 1755 __in efx_nic_t *enp) 1756 { 1757 efx_mcdi_req_t req; 1758 uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN, 1759 MC_CMD_LOG_CTRL_OUT_LEN)]; 1760 efx_rc_t rc; 1761 1762 (void) memset(payload, 0, sizeof (payload)); 1763 req.emr_cmd = MC_CMD_LOG_CTRL; 1764 req.emr_in_buf = payload; 1765 req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN; 1766 req.emr_out_buf = payload; 1767 req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN; 1768 1769 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST, 1770 MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ); 1771 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0); 1772 1773 efx_mcdi_execute(enp, &req); 1774 1775 if (req.emr_rc != 0) { 1776 rc = req.emr_rc; 1777 goto fail1; 1778 } 1779 1780 return (0); 1781 1782 fail1: 1783 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1784 1785 return (rc); 1786 } 1787 1788 1789 #if EFSYS_OPT_MAC_STATS 1790 1791 typedef enum efx_stats_action_e { 1792 EFX_STATS_CLEAR, 1793 EFX_STATS_UPLOAD, 1794 EFX_STATS_ENABLE_NOEVENTS, 1795 EFX_STATS_ENABLE_EVENTS, 1796 EFX_STATS_DISABLE, 1797 } efx_stats_action_t; 1798 1799 static __checkReturn efx_rc_t 1800 efx_mcdi_mac_stats( 1801 __in efx_nic_t *enp, 1802 __in_opt efsys_mem_t *esmp, 1803 __in efx_stats_action_t action, 1804 __in uint16_t period_ms) 1805 { 1806 efx_mcdi_req_t req; 1807 uint8_t payload[MAX(MC_CMD_MAC_STATS_IN_LEN, 1808 MC_CMD_MAC_STATS_OUT_DMA_LEN)]; 1809 int clear = (action == EFX_STATS_CLEAR); 1810 int upload = (action == EFX_STATS_UPLOAD); 1811 int enable = (action == EFX_STATS_ENABLE_NOEVENTS); 1812 int events = (action == EFX_STATS_ENABLE_EVENTS); 1813 int disable = (action == EFX_STATS_DISABLE); 1814 efx_rc_t rc; 1815 1816 (void) memset(payload, 0, sizeof (payload)); 1817 req.emr_cmd = MC_CMD_MAC_STATS; 1818 req.emr_in_buf = payload; 1819 req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN; 1820 req.emr_out_buf = payload; 1821 req.emr_out_length = MC_CMD_MAC_STATS_OUT_DMA_LEN; 1822 1823 MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD, 1824 MAC_STATS_IN_DMA, upload, 1825 MAC_STATS_IN_CLEAR, clear, 1826 MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable, 1827 MAC_STATS_IN_PERIODIC_ENABLE, enable | events, 1828 MAC_STATS_IN_PERIODIC_NOEVENT, !events, 1829 MAC_STATS_IN_PERIOD_MS, (enable | events) ? period_ms : 0); 1830 1831 if (esmp != NULL) { 1832 int bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t); 1833 1834 EFX_STATIC_ASSERT(MC_CMD_MAC_NSTATS * sizeof (uint64_t) <= 1835 EFX_MAC_STATS_SIZE); 1836 1837 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO, 1838 EFSYS_MEM_ADDR(esmp) & 0xffffffff); 1839 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI, 1840 EFSYS_MEM_ADDR(esmp) >> 32); 1841 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes); 1842 } else { 1843 EFSYS_ASSERT(!upload && !enable && !events); 1844 } 1845 1846 /* 1847 * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats, 1848 * as this may fail (and leave periodic DMA enabled) if the 1849 * vadapter has already been deleted. 1850 */ 1851 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID, 1852 (disable ? EVB_PORT_ID_NULL : enp->en_vport_id)); 1853 1854 efx_mcdi_execute(enp, &req); 1855 1856 if (req.emr_rc != 0) { 1857 /* EF10: Expect ENOENT if no DMA queues are initialised */ 1858 if ((req.emr_rc != ENOENT) || 1859 (enp->en_rx_qcount + enp->en_tx_qcount != 0)) { 1860 rc = req.emr_rc; 1861 goto fail1; 1862 } 1863 } 1864 1865 return (0); 1866 1867 fail1: 1868 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1869 1870 return (rc); 1871 } 1872 1873 __checkReturn efx_rc_t 1874 efx_mcdi_mac_stats_clear( 1875 __in efx_nic_t *enp) 1876 { 1877 efx_rc_t rc; 1878 1879 if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR, 0)) != 0) 1880 goto fail1; 1881 1882 return (0); 1883 1884 fail1: 1885 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1886 1887 return (rc); 1888 } 1889 1890 __checkReturn efx_rc_t 1891 efx_mcdi_mac_stats_upload( 1892 __in efx_nic_t *enp, 1893 __in efsys_mem_t *esmp) 1894 { 1895 efx_rc_t rc; 1896 1897 /* 1898 * The MC DMAs aggregate statistics for our convenience, so we can 1899 * avoid having to pull the statistics buffer into the cache to 1900 * maintain cumulative statistics. 1901 */ 1902 if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD, 0)) != 0) 1903 goto fail1; 1904 1905 return (0); 1906 1907 fail1: 1908 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1909 1910 return (rc); 1911 } 1912 1913 __checkReturn efx_rc_t 1914 efx_mcdi_mac_stats_periodic( 1915 __in efx_nic_t *enp, 1916 __in efsys_mem_t *esmp, 1917 __in uint16_t period_ms, 1918 __in boolean_t events) 1919 { 1920 efx_rc_t rc; 1921 1922 /* 1923 * The MC DMAs aggregate statistics for our convenience, so we can 1924 * avoid having to pull the statistics buffer into the cache to 1925 * maintain cumulative statistics. 1926 * Huntington uses a fixed 1sec period. 1927 * Medford uses a fixed 1sec period before v6.2.1.1033 firmware. 1928 */ 1929 if (period_ms == 0) 1930 rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE, 0); 1931 else if (events) 1932 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS, 1933 period_ms); 1934 else 1935 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS, 1936 period_ms); 1937 1938 if (rc != 0) 1939 goto fail1; 1940 1941 return (0); 1942 1943 fail1: 1944 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1945 1946 return (rc); 1947 } 1948 1949 #endif /* EFSYS_OPT_MAC_STATS */ 1950 1951 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 1952 1953 /* 1954 * This function returns the pf and vf number of a function. If it is a pf the 1955 * vf number is 0xffff. The vf number is the index of the vf on that 1956 * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0), 1957 * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff). 1958 */ 1959 __checkReturn efx_rc_t 1960 efx_mcdi_get_function_info( 1961 __in efx_nic_t *enp, 1962 __out uint32_t *pfp, 1963 __out_opt uint32_t *vfp) 1964 { 1965 efx_mcdi_req_t req; 1966 uint8_t payload[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN, 1967 MC_CMD_GET_FUNCTION_INFO_OUT_LEN)]; 1968 efx_rc_t rc; 1969 1970 (void) memset(payload, 0, sizeof (payload)); 1971 req.emr_cmd = MC_CMD_GET_FUNCTION_INFO; 1972 req.emr_in_buf = payload; 1973 req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN; 1974 req.emr_out_buf = payload; 1975 req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN; 1976 1977 efx_mcdi_execute(enp, &req); 1978 1979 if (req.emr_rc != 0) { 1980 rc = req.emr_rc; 1981 goto fail1; 1982 } 1983 1984 if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) { 1985 rc = EMSGSIZE; 1986 goto fail2; 1987 } 1988 1989 *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF); 1990 if (vfp != NULL) 1991 *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF); 1992 1993 return (0); 1994 1995 fail2: 1996 EFSYS_PROBE(fail2); 1997 fail1: 1998 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1999 2000 return (rc); 2001 } 2002 2003 __checkReturn efx_rc_t 2004 efx_mcdi_privilege_mask( 2005 __in efx_nic_t *enp, 2006 __in uint32_t pf, 2007 __in uint32_t vf, 2008 __out uint32_t *maskp) 2009 { 2010 efx_mcdi_req_t req; 2011 uint8_t payload[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN, 2012 MC_CMD_PRIVILEGE_MASK_OUT_LEN)]; 2013 efx_rc_t rc; 2014 2015 (void) memset(payload, 0, sizeof (payload)); 2016 req.emr_cmd = MC_CMD_PRIVILEGE_MASK; 2017 req.emr_in_buf = payload; 2018 req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN; 2019 req.emr_out_buf = payload; 2020 req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN; 2021 2022 MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION, 2023 PRIVILEGE_MASK_IN_FUNCTION_PF, pf, 2024 PRIVILEGE_MASK_IN_FUNCTION_VF, vf); 2025 2026 efx_mcdi_execute(enp, &req); 2027 2028 if (req.emr_rc != 0) { 2029 rc = req.emr_rc; 2030 goto fail1; 2031 } 2032 2033 if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) { 2034 rc = EMSGSIZE; 2035 goto fail2; 2036 } 2037 2038 *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK); 2039 2040 return (0); 2041 2042 fail2: 2043 EFSYS_PROBE(fail2); 2044 fail1: 2045 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2046 2047 return (rc); 2048 } 2049 2050 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 2051 2052 __checkReturn efx_rc_t 2053 efx_mcdi_set_workaround( 2054 __in efx_nic_t *enp, 2055 __in uint32_t type, 2056 __in boolean_t enabled, 2057 __out_opt uint32_t *flagsp) 2058 { 2059 efx_mcdi_req_t req; 2060 uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN, 2061 MC_CMD_WORKAROUND_EXT_OUT_LEN)]; 2062 efx_rc_t rc; 2063 2064 (void) memset(payload, 0, sizeof (payload)); 2065 req.emr_cmd = MC_CMD_WORKAROUND; 2066 req.emr_in_buf = payload; 2067 req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN; 2068 req.emr_out_buf = payload; 2069 req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN; 2070 2071 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type); 2072 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0); 2073 2074 efx_mcdi_execute_quiet(enp, &req); 2075 2076 if (req.emr_rc != 0) { 2077 rc = req.emr_rc; 2078 goto fail1; 2079 } 2080 2081 if (flagsp != NULL) { 2082 if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN) 2083 *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS); 2084 else 2085 *flagsp = 0; 2086 } 2087 2088 return (0); 2089 2090 fail1: 2091 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2092 2093 return (rc); 2094 } 2095 2096 2097 __checkReturn efx_rc_t 2098 efx_mcdi_get_workarounds( 2099 __in efx_nic_t *enp, 2100 __out_opt uint32_t *implementedp, 2101 __out_opt uint32_t *enabledp) 2102 { 2103 efx_mcdi_req_t req; 2104 uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN]; 2105 efx_rc_t rc; 2106 2107 (void) memset(payload, 0, sizeof (payload)); 2108 req.emr_cmd = MC_CMD_GET_WORKAROUNDS; 2109 req.emr_in_buf = NULL; 2110 req.emr_in_length = 0; 2111 req.emr_out_buf = payload; 2112 req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN; 2113 2114 efx_mcdi_execute(enp, &req); 2115 2116 if (req.emr_rc != 0) { 2117 rc = req.emr_rc; 2118 goto fail1; 2119 } 2120 2121 if (implementedp != NULL) { 2122 *implementedp = 2123 MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED); 2124 } 2125 2126 if (enabledp != NULL) { 2127 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED); 2128 } 2129 2130 return (0); 2131 2132 fail1: 2133 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2134 2135 return (rc); 2136 } 2137 2138 /* 2139 * Size of media information page in accordance with SFF-8472 and SFF-8436. 2140 * It is used in MCDI interface as well. 2141 */ 2142 #define EFX_PHY_MEDIA_INFO_PAGE_SIZE 0x80 2143 2144 static __checkReturn efx_rc_t 2145 efx_mcdi_get_phy_media_info( 2146 __in efx_nic_t *enp, 2147 __in uint32_t mcdi_page, 2148 __in uint8_t offset, 2149 __in uint8_t len, 2150 __out_bcount(len) uint8_t *data) 2151 { 2152 efx_mcdi_req_t req; 2153 uint8_t payload[MAX(MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN, 2154 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN( 2155 EFX_PHY_MEDIA_INFO_PAGE_SIZE))]; 2156 efx_rc_t rc; 2157 2158 EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2159 2160 (void) memset(payload, 0, sizeof (payload)); 2161 req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO; 2162 req.emr_in_buf = payload; 2163 req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN; 2164 req.emr_out_buf = payload; 2165 req.emr_out_length = 2166 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2167 2168 MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page); 2169 2170 efx_mcdi_execute(enp, &req); 2171 2172 if (req.emr_rc != 0) { 2173 rc = req.emr_rc; 2174 goto fail1; 2175 } 2176 2177 if (req.emr_out_length_used != 2178 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) { 2179 rc = EMSGSIZE; 2180 goto fail2; 2181 } 2182 2183 if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) != 2184 EFX_PHY_MEDIA_INFO_PAGE_SIZE) { 2185 rc = EIO; 2186 goto fail3; 2187 } 2188 2189 memcpy(data, 2190 MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset, 2191 len); 2192 2193 return (0); 2194 2195 fail3: 2196 EFSYS_PROBE(fail3); 2197 fail2: 2198 EFSYS_PROBE(fail2); 2199 fail1: 2200 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2201 2202 return (rc); 2203 } 2204 2205 /* 2206 * 2-wire device address of the base information in accordance with SFF-8472 2207 * Diagnostic Monitoring Interface for Optical Transceivers section 2208 * 4 Memory Organization. 2209 */ 2210 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE 0xA0 2211 2212 /* 2213 * 2-wire device address of the digital diagnostics monitoring interface 2214 * in accordance with SFF-8472 Diagnostic Monitoring Interface for Optical 2215 * Transceivers section 4 Memory Organization. 2216 */ 2217 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM 0xA2 2218 2219 /* 2220 * Hard wired 2-wire device address for QSFP+ in accordance with SFF-8436 2221 * QSFP+ 10 Gbs 4X PLUGGABLE TRANSCEIVER section 7.4 Device Addressing and 2222 * Operation. 2223 */ 2224 #define EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP 0xA0 2225 2226 __checkReturn efx_rc_t 2227 efx_mcdi_phy_module_get_info( 2228 __in efx_nic_t *enp, 2229 __in uint8_t dev_addr, 2230 __in uint8_t offset, 2231 __in uint8_t len, 2232 __out_bcount(len) uint8_t *data) 2233 { 2234 efx_port_t *epp = &(enp->en_port); 2235 efx_rc_t rc; 2236 uint32_t mcdi_lower_page; 2237 uint32_t mcdi_upper_page; 2238 2239 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 2240 2241 /* 2242 * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages. 2243 * Offset plus length interface allows to access page 0 only. 2244 * I.e. non-zero upper pages are not accessible. 2245 * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6 2246 * QSFP+ Memory Map for details on how information is structured 2247 * and accessible. 2248 */ 2249 switch (epp->ep_fixed_port_type) { 2250 case EFX_PHY_MEDIA_SFP_PLUS: 2251 /* 2252 * In accordance with SFF-8472 Diagnostic Monitoring 2253 * Interface for Optical Transceivers section 4 Memory 2254 * Organization two 2-wire addresses are defined. 2255 */ 2256 switch (dev_addr) { 2257 /* Base information */ 2258 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE: 2259 /* 2260 * MCDI page 0 should be used to access lower 2261 * page 0 (0x00 - 0x7f) at the device address 0xA0. 2262 */ 2263 mcdi_lower_page = 0; 2264 /* 2265 * MCDI page 1 should be used to access upper 2266 * page 0 (0x80 - 0xff) at the device address 0xA0. 2267 */ 2268 mcdi_upper_page = 1; 2269 break; 2270 /* Diagnostics */ 2271 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM: 2272 /* 2273 * MCDI page 2 should be used to access lower 2274 * page 0 (0x00 - 0x7f) at the device address 0xA2. 2275 */ 2276 mcdi_lower_page = 2; 2277 /* 2278 * MCDI page 3 should be used to access upper 2279 * page 0 (0x80 - 0xff) at the device address 0xA2. 2280 */ 2281 mcdi_upper_page = 3; 2282 break; 2283 default: 2284 rc = ENOTSUP; 2285 goto fail1; 2286 } 2287 break; 2288 case EFX_PHY_MEDIA_QSFP_PLUS: 2289 switch (dev_addr) { 2290 case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP: 2291 /* 2292 * MCDI page -1 should be used to access lower page 0 2293 * (0x00 - 0x7f). 2294 */ 2295 mcdi_lower_page = (uint32_t)-1; 2296 /* 2297 * MCDI page 0 should be used to access upper page 0 2298 * (0x80h - 0xff). 2299 */ 2300 mcdi_upper_page = 0; 2301 break; 2302 default: 2303 rc = ENOTSUP; 2304 goto fail1; 2305 } 2306 break; 2307 default: 2308 rc = ENOTSUP; 2309 goto fail1; 2310 } 2311 2312 if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) { 2313 uint8_t read_len = 2314 MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset); 2315 2316 rc = efx_mcdi_get_phy_media_info(enp, 2317 mcdi_lower_page, offset, read_len, data); 2318 if (rc != 0) 2319 goto fail2; 2320 2321 data += read_len; 2322 len -= read_len; 2323 2324 offset = 0; 2325 } else { 2326 offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE; 2327 } 2328 2329 if (len > 0) { 2330 EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2331 EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2332 2333 rc = efx_mcdi_get_phy_media_info(enp, 2334 mcdi_upper_page, offset, len, data); 2335 if (rc != 0) 2336 goto fail3; 2337 } 2338 2339 return (0); 2340 2341 fail3: 2342 EFSYS_PROBE(fail3); 2343 fail2: 2344 EFSYS_PROBE(fail2); 2345 fail1: 2346 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2347 2348 return (rc); 2349 } 2350 2351 #endif /* EFSYS_OPT_MCDI */ 2352