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