1 /*- 2 * Copyright (c) 2008-2015 Solarflare Communications Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * The views and conclusions contained in the software and documentation are 27 * those of the authors and should not be interpreted as representing official 28 * policies, either expressed or implied, of the FreeBSD Project. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include "efsys.h" 35 #include "efx.h" 36 #include "efx_types.h" 37 #include "efx_regs.h" 38 #include "efx_regs_mcdi.h" 39 #include "efx_impl.h" 40 41 #if EFSYS_OPT_MCDI 42 43 44 #if EFSYS_OPT_SIENA 45 46 static efx_mcdi_ops_t __efx_mcdi_siena_ops = { 47 siena_mcdi_init, /* emco_init */ 48 siena_mcdi_request_copyin, /* emco_request_copyin */ 49 siena_mcdi_request_copyout, /* emco_request_copyout */ 50 siena_mcdi_poll_reboot, /* emco_poll_reboot */ 51 siena_mcdi_poll_response, /* emco_poll_response */ 52 siena_mcdi_read_response, /* emco_read_response */ 53 siena_mcdi_fini, /* emco_fini */ 54 siena_mcdi_feature_supported, /* emco_feature_supported */ 55 }; 56 57 #endif /* EFSYS_OPT_SIENA */ 58 59 #if EFSYS_OPT_HUNTINGTON 60 61 static efx_mcdi_ops_t __efx_mcdi_hunt_ops = { 62 hunt_mcdi_init, /* emco_init */ 63 hunt_mcdi_request_copyin, /* emco_request_copyin */ 64 hunt_mcdi_request_copyout, /* emco_request_copyout */ 65 hunt_mcdi_poll_reboot, /* emco_poll_reboot */ 66 hunt_mcdi_poll_response, /* emco_poll_response */ 67 hunt_mcdi_read_response, /* emco_read_response */ 68 hunt_mcdi_fini, /* emco_fini */ 69 hunt_mcdi_feature_supported, /* emco_feature_supported */ 70 }; 71 72 #endif /* EFSYS_OPT_HUNTINGTON */ 73 74 75 76 __checkReturn efx_rc_t 77 efx_mcdi_init( 78 __in efx_nic_t *enp, 79 __in const efx_mcdi_transport_t *emtp) 80 { 81 efx_mcdi_ops_t *emcop; 82 efx_rc_t rc; 83 84 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 85 EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); 86 87 switch (enp->en_family) { 88 #if EFSYS_OPT_FALCON 89 case EFX_FAMILY_FALCON: 90 emcop = NULL; 91 emtp = NULL; 92 break; 93 #endif /* EFSYS_OPT_FALCON */ 94 95 #if EFSYS_OPT_SIENA 96 case EFX_FAMILY_SIENA: 97 emcop = (efx_mcdi_ops_t *)&__efx_mcdi_siena_ops; 98 break; 99 #endif /* EFSYS_OPT_SIENA */ 100 101 #if EFSYS_OPT_HUNTINGTON 102 case EFX_FAMILY_HUNTINGTON: 103 emcop = (efx_mcdi_ops_t *)&__efx_mcdi_hunt_ops; 104 break; 105 #endif /* EFSYS_OPT_HUNTINGTON */ 106 107 default: 108 EFSYS_ASSERT(0); 109 rc = ENOTSUP; 110 goto fail1; 111 } 112 113 if (enp->en_features & EFX_FEATURE_MCDI_DMA) { 114 /* MCDI requires a DMA buffer in host memory */ 115 if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) { 116 rc = EINVAL; 117 goto fail2; 118 } 119 } 120 enp->en_mcdi.em_emtp = emtp; 121 122 if (emcop != NULL && emcop->emco_init != NULL) { 123 if ((rc = emcop->emco_init(enp, emtp)) != 0) 124 goto fail3; 125 } 126 127 enp->en_mcdi.em_emcop = emcop; 128 enp->en_mod_flags |= EFX_MOD_MCDI; 129 130 return (0); 131 132 fail3: 133 EFSYS_PROBE(fail3); 134 fail2: 135 EFSYS_PROBE(fail2); 136 fail1: 137 EFSYS_PROBE1(fail1, efx_rc_t, rc); 138 139 enp->en_mcdi.em_emcop = NULL; 140 enp->en_mcdi.em_emtp = NULL; 141 enp->en_mod_flags &= ~EFX_MOD_MCDI; 142 143 return (rc); 144 } 145 146 void 147 efx_mcdi_fini( 148 __in efx_nic_t *enp) 149 { 150 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 151 efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 152 153 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 154 EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI); 155 156 if (emcop != NULL && emcop->emco_fini != NULL) 157 emcop->emco_fini(enp); 158 159 emip->emi_port = 0; 160 emip->emi_aborted = 0; 161 162 enp->en_mcdi.em_emcop = NULL; 163 enp->en_mod_flags &= ~EFX_MOD_MCDI; 164 } 165 166 void 167 efx_mcdi_new_epoch( 168 __in efx_nic_t *enp) 169 { 170 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 171 int state; 172 173 /* Start a new epoch (allow fresh MCDI requests to succeed) */ 174 EFSYS_LOCK(enp->en_eslp, state); 175 emip->emi_new_epoch = B_TRUE; 176 EFSYS_UNLOCK(enp->en_eslp, state); 177 } 178 179 static void 180 efx_mcdi_request_copyin( 181 __in efx_nic_t *enp, 182 __in efx_mcdi_req_t *emrp, 183 __in unsigned int seq, 184 __in boolean_t ev_cpl, 185 __in boolean_t new_epoch) 186 { 187 efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 188 189 emcop->emco_request_copyin(enp, emrp, seq, ev_cpl, new_epoch); 190 } 191 192 static void 193 efx_mcdi_request_copyout( 194 __in efx_nic_t *enp, 195 __in efx_mcdi_req_t *emrp) 196 { 197 efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 198 199 emcop->emco_request_copyout(enp, emrp); 200 } 201 202 static efx_rc_t 203 efx_mcdi_poll_reboot( 204 __in efx_nic_t *enp) 205 { 206 efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 207 efx_rc_t rc; 208 209 rc = emcop->emco_poll_reboot(enp); 210 return (rc); 211 } 212 213 static boolean_t 214 efx_mcdi_poll_response( 215 __in efx_nic_t *enp) 216 { 217 efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 218 boolean_t available; 219 220 available = emcop->emco_poll_response(enp); 221 return (available); 222 } 223 224 static void 225 efx_mcdi_read_response( 226 __in efx_nic_t *enp, 227 __out void *bufferp, 228 __in size_t offset, 229 __in size_t length) 230 { 231 efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 232 233 emcop->emco_read_response(enp, bufferp, offset, length); 234 } 235 236 void 237 efx_mcdi_request_start( 238 __in efx_nic_t *enp, 239 __in efx_mcdi_req_t *emrp, 240 __in boolean_t ev_cpl) 241 { 242 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 243 unsigned int seq; 244 boolean_t new_epoch; 245 int state; 246 247 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 248 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 249 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 250 251 /* 252 * efx_mcdi_request_start() is naturally serialised against both 253 * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(), 254 * by virtue of there only being one outstanding MCDI request. 255 * Unfortunately, upper layers may also call efx_mcdi_request_abort() 256 * at any time, to timeout a pending mcdi request, That request may 257 * then subsequently complete, meaning efx_mcdi_ev_cpl() or 258 * efx_mcdi_ev_death() may end up running in parallel with 259 * efx_mcdi_request_start(). This race is handled by ensuring that 260 * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the 261 * en_eslp lock. 262 */ 263 EFSYS_LOCK(enp->en_eslp, state); 264 EFSYS_ASSERT(emip->emi_pending_req == NULL); 265 emip->emi_pending_req = emrp; 266 emip->emi_ev_cpl = ev_cpl; 267 emip->emi_poll_cnt = 0; 268 seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ); 269 new_epoch = emip->emi_new_epoch; 270 EFSYS_UNLOCK(enp->en_eslp, state); 271 272 efx_mcdi_request_copyin(enp, emrp, seq, ev_cpl, new_epoch); 273 } 274 275 276 void 277 efx_mcdi_read_response_header( 278 __in efx_nic_t *enp, 279 __inout efx_mcdi_req_t *emrp) 280 { 281 #if EFSYS_OPT_MCDI_LOGGING 282 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 283 #endif /* EFSYS_OPT_MCDI_LOGGING */ 284 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 285 efx_dword_t hdr[2]; 286 unsigned int hdr_len; 287 unsigned int data_len; 288 unsigned int seq; 289 unsigned int cmd; 290 unsigned int error; 291 efx_rc_t rc; 292 293 EFSYS_ASSERT(emrp != NULL); 294 295 efx_mcdi_read_response(enp, &hdr[0], 0, sizeof (hdr[0])); 296 hdr_len = sizeof (hdr[0]); 297 298 cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE); 299 seq = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ); 300 error = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR); 301 302 if (cmd != MC_CMD_V2_EXTN) { 303 data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN); 304 } else { 305 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1])); 306 hdr_len += sizeof (hdr[1]); 307 308 cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD); 309 data_len = 310 EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN); 311 } 312 313 if (error && (data_len == 0)) { 314 /* The MC has rebooted since the request was sent. */ 315 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US); 316 efx_mcdi_poll_reboot(enp); 317 rc = EIO; 318 goto fail1; 319 } 320 if ((cmd != emrp->emr_cmd) || 321 (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) { 322 /* Response is for a different request */ 323 rc = EIO; 324 goto fail2; 325 } 326 if (error) { 327 efx_dword_t err[2]; 328 unsigned int err_len = MIN(data_len, sizeof (err)); 329 int err_code = MC_CMD_ERR_EPROTO; 330 int err_arg = 0; 331 332 /* Read error code (and arg num for MCDI v2 commands) */ 333 efx_mcdi_read_response(enp, &err, hdr_len, err_len); 334 335 if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t))) 336 err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0); 337 #ifdef WITH_MCDI_V2 338 if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t))) 339 err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0); 340 #endif 341 emrp->emr_err_code = err_code; 342 emrp->emr_err_arg = err_arg; 343 344 #if EFSYS_OPT_MCDI_PROXY_AUTH 345 if ((err_code == MC_CMD_ERR_PROXY_PENDING) && 346 (err_len == sizeof (err))) { 347 /* 348 * The MCDI request would normally fail with EPERM, but 349 * firmware has forwarded it to an authorization agent 350 * attached to a privileged PF. 351 * 352 * Save the authorization request handle. The client 353 * must wait for a PROXY_RESPONSE event, or timeout. 354 */ 355 emrp->emr_proxy_handle = err_arg; 356 } 357 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ 358 359 #if EFSYS_OPT_MCDI_LOGGING 360 if (emtp->emt_logger != NULL) { 361 emtp->emt_logger(emtp->emt_context, 362 EFX_LOG_MCDI_RESPONSE, 363 &hdr, hdr_len, 364 &err, err_len); 365 } 366 #endif /* EFSYS_OPT_MCDI_LOGGING */ 367 368 if (!emrp->emr_quiet) { 369 EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd, 370 int, err_code, int, err_arg); 371 } 372 373 rc = efx_mcdi_request_errcode(err_code); 374 goto fail3; 375 } 376 377 emrp->emr_rc = 0; 378 emrp->emr_out_length_used = data_len; 379 #if EFSYS_OPT_MCDI_PROXY_AUTH 380 emrp->emr_proxy_handle = 0; 381 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ 382 return; 383 384 fail3: 385 if (!emrp->emr_quiet) 386 EFSYS_PROBE(fail3); 387 fail2: 388 if (!emrp->emr_quiet) 389 EFSYS_PROBE(fail2); 390 fail1: 391 if (!emrp->emr_quiet) 392 EFSYS_PROBE1(fail1, efx_rc_t, rc); 393 394 emrp->emr_rc = rc; 395 emrp->emr_out_length_used = 0; 396 } 397 398 399 __checkReturn boolean_t 400 efx_mcdi_request_poll( 401 __in efx_nic_t *enp) 402 { 403 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 404 efx_mcdi_req_t *emrp; 405 int state; 406 efx_rc_t rc; 407 408 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 409 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 410 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 411 412 /* Serialise against post-watchdog efx_mcdi_ev* */ 413 EFSYS_LOCK(enp->en_eslp, state); 414 415 EFSYS_ASSERT(emip->emi_pending_req != NULL); 416 EFSYS_ASSERT(!emip->emi_ev_cpl); 417 emrp = emip->emi_pending_req; 418 419 /* Check for reboot atomically w.r.t efx_mcdi_request_start */ 420 if (emip->emi_poll_cnt++ == 0) { 421 if ((rc = efx_mcdi_poll_reboot(enp)) != 0) { 422 emip->emi_pending_req = NULL; 423 EFSYS_UNLOCK(enp->en_eslp, state); 424 goto fail1; 425 } 426 } 427 428 /* Check if a response is available */ 429 if (efx_mcdi_poll_response(enp) == B_FALSE) { 430 EFSYS_UNLOCK(enp->en_eslp, state); 431 return (B_FALSE); 432 } 433 434 /* Read the response header */ 435 efx_mcdi_read_response_header(enp, emrp); 436 437 /* Request complete */ 438 emip->emi_pending_req = NULL; 439 440 EFSYS_UNLOCK(enp->en_eslp, state); 441 442 if ((rc = emrp->emr_rc) != 0) 443 goto fail2; 444 445 efx_mcdi_request_copyout(enp, emrp); 446 return (B_TRUE); 447 448 fail2: 449 if (!emrp->emr_quiet) 450 EFSYS_PROBE(fail2); 451 fail1: 452 if (!emrp->emr_quiet) 453 EFSYS_PROBE1(fail1, efx_rc_t, rc); 454 455 /* Reboot/Assertion */ 456 if (rc == EIO || rc == EINTR) 457 efx_mcdi_raise_exception(enp, emrp, rc); 458 459 return (B_TRUE); 460 } 461 462 __checkReturn boolean_t 463 efx_mcdi_request_abort( 464 __in efx_nic_t *enp) 465 { 466 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 467 efx_mcdi_req_t *emrp; 468 boolean_t aborted; 469 int state; 470 471 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 472 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 473 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 474 475 /* 476 * efx_mcdi_ev_* may have already completed this event, and be 477 * spinning/blocked on the upper layer lock. So it *is* legitimate 478 * to for emi_pending_req to be NULL. If there is a pending event 479 * completed request, then provide a "credit" to allow 480 * efx_mcdi_ev_cpl() to accept a single spurious completion. 481 */ 482 EFSYS_LOCK(enp->en_eslp, state); 483 emrp = emip->emi_pending_req; 484 aborted = (emrp != NULL); 485 if (aborted) { 486 emip->emi_pending_req = NULL; 487 488 /* Error the request */ 489 emrp->emr_out_length_used = 0; 490 emrp->emr_rc = ETIMEDOUT; 491 492 /* Provide a credit for seqno/emr_pending_req mismatches */ 493 if (emip->emi_ev_cpl) 494 ++emip->emi_aborted; 495 496 /* 497 * The upper layer has called us, so we don't 498 * need to complete the request. 499 */ 500 } 501 EFSYS_UNLOCK(enp->en_eslp, state); 502 503 return (aborted); 504 } 505 506 __checkReturn efx_rc_t 507 efx_mcdi_request_errcode( 508 __in unsigned int err) 509 { 510 511 switch (err) { 512 /* MCDI v1 */ 513 case MC_CMD_ERR_EPERM: 514 return (EACCES); 515 case MC_CMD_ERR_ENOENT: 516 return (ENOENT); 517 case MC_CMD_ERR_EINTR: 518 return (EINTR); 519 case MC_CMD_ERR_EACCES: 520 return (EACCES); 521 case MC_CMD_ERR_EBUSY: 522 return (EBUSY); 523 case MC_CMD_ERR_EINVAL: 524 return (EINVAL); 525 case MC_CMD_ERR_EDEADLK: 526 return (EDEADLK); 527 case MC_CMD_ERR_ENOSYS: 528 return (ENOTSUP); 529 case MC_CMD_ERR_ETIME: 530 return (ETIMEDOUT); 531 case MC_CMD_ERR_ENOTSUP: 532 return (ENOTSUP); 533 case MC_CMD_ERR_EALREADY: 534 return (EALREADY); 535 536 /* MCDI v2 */ 537 #ifdef MC_CMD_ERR_EAGAIN 538 case MC_CMD_ERR_EAGAIN: 539 return (EAGAIN); 540 #endif 541 #ifdef MC_CMD_ERR_ENOSPC 542 case MC_CMD_ERR_ENOSPC: 543 return (ENOSPC); 544 #endif 545 546 case MC_CMD_ERR_ALLOC_FAIL: 547 return (ENOMEM); 548 case MC_CMD_ERR_NO_VADAPTOR: 549 return (ENOENT); 550 case MC_CMD_ERR_NO_EVB_PORT: 551 return (ENOENT); 552 case MC_CMD_ERR_NO_VSWITCH: 553 return (ENODEV); 554 case MC_CMD_ERR_VLAN_LIMIT: 555 return (EINVAL); 556 case MC_CMD_ERR_BAD_PCI_FUNC: 557 return (ENODEV); 558 case MC_CMD_ERR_BAD_VLAN_MODE: 559 return (EINVAL); 560 case MC_CMD_ERR_BAD_VSWITCH_TYPE: 561 return (EINVAL); 562 case MC_CMD_ERR_BAD_VPORT_TYPE: 563 return (EINVAL); 564 case MC_CMD_ERR_MAC_EXIST: 565 return (EEXIST); 566 567 case MC_CMD_ERR_PROXY_PENDING: 568 return (EAGAIN); 569 570 default: 571 EFSYS_PROBE1(mc_pcol_error, int, err); 572 return (EIO); 573 } 574 } 575 576 void 577 efx_mcdi_raise_exception( 578 __in efx_nic_t *enp, 579 __in_opt efx_mcdi_req_t *emrp, 580 __in int rc) 581 { 582 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 583 efx_mcdi_exception_t exception; 584 585 /* Reboot or Assertion failure only */ 586 EFSYS_ASSERT(rc == EIO || rc == EINTR); 587 588 /* 589 * If MC_CMD_REBOOT causes a reboot (dependent on parameters), 590 * then the EIO is not worthy of an exception. 591 */ 592 if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO) 593 return; 594 595 exception = (rc == EIO) 596 ? EFX_MCDI_EXCEPTION_MC_REBOOT 597 : EFX_MCDI_EXCEPTION_MC_BADASSERT; 598 599 emtp->emt_exception(emtp->emt_context, exception); 600 } 601 602 void 603 efx_mcdi_execute( 604 __in efx_nic_t *enp, 605 __inout efx_mcdi_req_t *emrp) 606 { 607 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 608 609 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 610 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 611 612 emrp->emr_quiet = B_FALSE; 613 emtp->emt_execute(emtp->emt_context, emrp); 614 } 615 616 void 617 efx_mcdi_execute_quiet( 618 __in efx_nic_t *enp, 619 __inout efx_mcdi_req_t *emrp) 620 { 621 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 622 623 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 624 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 625 626 emrp->emr_quiet = B_TRUE; 627 emtp->emt_execute(emtp->emt_context, emrp); 628 } 629 630 void 631 efx_mcdi_ev_cpl( 632 __in efx_nic_t *enp, 633 __in unsigned int seq, 634 __in unsigned int outlen, 635 __in int errcode) 636 { 637 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 638 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 639 efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 640 efx_nic_cfg_t *encp = &enp->en_nic_cfg; 641 efx_mcdi_req_t *emrp; 642 int state; 643 644 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 645 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 646 647 /* 648 * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start() 649 * when we're completing an aborted request. 650 */ 651 EFSYS_LOCK(enp->en_eslp, state); 652 if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl || 653 (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) { 654 EFSYS_ASSERT(emip->emi_aborted > 0); 655 if (emip->emi_aborted > 0) 656 --emip->emi_aborted; 657 EFSYS_UNLOCK(enp->en_eslp, state); 658 return; 659 } 660 661 emrp = emip->emi_pending_req; 662 emip->emi_pending_req = NULL; 663 EFSYS_UNLOCK(enp->en_eslp, state); 664 665 if (encp->enc_mcdi_max_payload_length > MCDI_CTL_SDU_LEN_MAX_V1) { 666 /* MCDIv2 response details do not fit into an event. */ 667 efx_mcdi_read_response_header(enp, emrp); 668 } else { 669 if (errcode != 0) { 670 if (!emrp->emr_quiet) { 671 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd, 672 int, errcode); 673 } 674 emrp->emr_out_length_used = 0; 675 emrp->emr_rc = efx_mcdi_request_errcode(errcode); 676 } else { 677 emrp->emr_out_length_used = outlen; 678 emrp->emr_rc = 0; 679 } 680 } 681 if (errcode == 0) { 682 emcop->emco_request_copyout(enp, emrp); 683 } 684 685 emtp->emt_ev_cpl(emtp->emt_context); 686 } 687 688 #if EFSYS_OPT_MCDI_PROXY_AUTH 689 690 __checkReturn efx_rc_t 691 efx_mcdi_get_proxy_handle( 692 __in efx_nic_t *enp, 693 __in efx_mcdi_req_t *emrp, 694 __out uint32_t *handlep) 695 { 696 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 697 efx_rc_t rc; 698 699 /* 700 * Return proxy handle from MCDI request that returned with error 701 * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching 702 * PROXY_RESPONSE event. 703 */ 704 if ((emrp == NULL) || (handlep == NULL)) { 705 rc = EINVAL; 706 goto fail1; 707 } 708 if ((emrp->emr_rc != 0) && 709 (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) { 710 *handlep = emrp->emr_proxy_handle; 711 rc = 0; 712 } else { 713 *handlep = 0; 714 rc = ENOENT; 715 } 716 return (rc); 717 718 fail1: 719 EFSYS_PROBE1(fail1, efx_rc_t, rc); 720 return (rc); 721 } 722 723 void 724 efx_mcdi_ev_proxy_response( 725 __in efx_nic_t *enp, 726 __in unsigned int handle, 727 __in unsigned int status) 728 { 729 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 730 efx_rc_t rc; 731 732 /* 733 * Handle results of an authorization request for a privileged MCDI 734 * command. If authorization was granted then we must re-issue the 735 * original MCDI request. If authorization failed or timed out, 736 * then the original MCDI request should be completed with the 737 * result code from this event. 738 */ 739 rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status); 740 741 emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc); 742 } 743 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ 744 745 void 746 efx_mcdi_ev_death( 747 __in efx_nic_t *enp, 748 __in int rc) 749 { 750 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 751 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 752 efx_mcdi_req_t *emrp = NULL; 753 boolean_t ev_cpl; 754 int state; 755 756 /* 757 * The MCDI request (if there is one) has been terminated, either 758 * by a BADASSERT or REBOOT event. 759 * 760 * If there is an outstanding event-completed MCDI operation, then we 761 * will never receive the completion event (because both MCDI 762 * completions and BADASSERT events are sent to the same evq). So 763 * complete this MCDI op. 764 * 765 * This function might run in parallel with efx_mcdi_request_poll() 766 * for poll completed mcdi requests, and also with 767 * efx_mcdi_request_start() for post-watchdog completions. 768 */ 769 EFSYS_LOCK(enp->en_eslp, state); 770 emrp = emip->emi_pending_req; 771 ev_cpl = emip->emi_ev_cpl; 772 if (emrp != NULL && emip->emi_ev_cpl) { 773 emip->emi_pending_req = NULL; 774 775 emrp->emr_out_length_used = 0; 776 emrp->emr_rc = rc; 777 ++emip->emi_aborted; 778 } 779 780 /* 781 * Since we're running in parallel with a request, consume the 782 * status word before dropping the lock. 783 */ 784 if (rc == EIO || rc == EINTR) { 785 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US); 786 (void) efx_mcdi_poll_reboot(enp); 787 emip->emi_new_epoch = B_TRUE; 788 } 789 790 EFSYS_UNLOCK(enp->en_eslp, state); 791 792 efx_mcdi_raise_exception(enp, emrp, rc); 793 794 if (emrp != NULL && ev_cpl) 795 emtp->emt_ev_cpl(emtp->emt_context); 796 } 797 798 __checkReturn efx_rc_t 799 efx_mcdi_version( 800 __in efx_nic_t *enp, 801 __out_ecount_opt(4) uint16_t versionp[4], 802 __out_opt uint32_t *buildp, 803 __out_opt efx_mcdi_boot_t *statusp) 804 { 805 efx_mcdi_req_t req; 806 uint8_t payload[MAX(MAX(MC_CMD_GET_VERSION_IN_LEN, 807 MC_CMD_GET_VERSION_OUT_LEN), 808 MAX(MC_CMD_GET_BOOT_STATUS_IN_LEN, 809 MC_CMD_GET_BOOT_STATUS_OUT_LEN))]; 810 efx_word_t *ver_words; 811 uint16_t version[4]; 812 uint32_t build; 813 efx_mcdi_boot_t status; 814 efx_rc_t rc; 815 816 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 817 818 (void) memset(payload, 0, sizeof (payload)); 819 req.emr_cmd = MC_CMD_GET_VERSION; 820 req.emr_in_buf = payload; 821 req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN; 822 req.emr_out_buf = payload; 823 req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN; 824 825 efx_mcdi_execute(enp, &req); 826 827 if (req.emr_rc != 0) { 828 rc = req.emr_rc; 829 goto fail1; 830 } 831 832 /* bootrom support */ 833 if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) { 834 version[0] = version[1] = version[2] = version[3] = 0; 835 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 836 837 goto version; 838 } 839 840 if (req.emr_out_length_used < MC_CMD_GET_VERSION_OUT_LEN) { 841 rc = EMSGSIZE; 842 goto fail2; 843 } 844 845 ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION); 846 version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0); 847 version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0); 848 version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0); 849 version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0); 850 build = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 851 852 version: 853 /* The bootrom doesn't understand BOOT_STATUS */ 854 if (MC_FW_VERSION_IS_BOOTLOADER(build)) { 855 status = EFX_MCDI_BOOT_ROM; 856 goto out; 857 } 858 859 (void) memset(payload, 0, sizeof (payload)); 860 req.emr_cmd = MC_CMD_GET_BOOT_STATUS; 861 req.emr_in_buf = payload; 862 req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN; 863 req.emr_out_buf = payload; 864 req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN; 865 866 efx_mcdi_execute_quiet(enp, &req); 867 868 if (req.emr_rc == EACCES) { 869 /* Unprivileged functions cannot access BOOT_STATUS */ 870 status = EFX_MCDI_BOOT_PRIMARY; 871 version[0] = version[1] = version[2] = version[3] = 0; 872 build = 0; 873 goto out; 874 } 875 876 if (req.emr_rc != 0) { 877 rc = req.emr_rc; 878 goto fail3; 879 } 880 881 if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) { 882 rc = EMSGSIZE; 883 goto fail4; 884 } 885 886 if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS, 887 GET_BOOT_STATUS_OUT_FLAGS_PRIMARY)) 888 status = EFX_MCDI_BOOT_PRIMARY; 889 else 890 status = EFX_MCDI_BOOT_SECONDARY; 891 892 out: 893 if (versionp != NULL) 894 memcpy(versionp, version, sizeof (version)); 895 if (buildp != NULL) 896 *buildp = build; 897 if (statusp != NULL) 898 *statusp = status; 899 900 return (0); 901 902 fail4: 903 EFSYS_PROBE(fail4); 904 fail3: 905 EFSYS_PROBE(fail3); 906 fail2: 907 EFSYS_PROBE(fail2); 908 fail1: 909 EFSYS_PROBE1(fail1, efx_rc_t, rc); 910 911 return (rc); 912 } 913 914 static __checkReturn efx_rc_t 915 efx_mcdi_do_reboot( 916 __in efx_nic_t *enp, 917 __in boolean_t after_assertion) 918 { 919 uint8_t payload[MAX(MC_CMD_REBOOT_IN_LEN, MC_CMD_REBOOT_OUT_LEN)]; 920 efx_mcdi_req_t req; 921 efx_rc_t rc; 922 923 /* 924 * We could require the caller to have caused en_mod_flags=0 to 925 * call this function. This doesn't help the other port though, 926 * who's about to get the MC ripped out from underneath them. 927 * Since they have to cope with the subsequent fallout of MCDI 928 * failures, we should as well. 929 */ 930 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 931 932 (void) memset(payload, 0, sizeof (payload)); 933 req.emr_cmd = MC_CMD_REBOOT; 934 req.emr_in_buf = payload; 935 req.emr_in_length = MC_CMD_REBOOT_IN_LEN; 936 req.emr_out_buf = payload; 937 req.emr_out_length = MC_CMD_REBOOT_OUT_LEN; 938 939 MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS, 940 (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0)); 941 942 efx_mcdi_execute_quiet(enp, &req); 943 944 if (req.emr_rc == EACCES) { 945 /* Unprivileged functions cannot reboot the MC. */ 946 goto out; 947 } 948 949 /* A successful reboot request returns EIO. */ 950 if (req.emr_rc != 0 && req.emr_rc != EIO) { 951 rc = req.emr_rc; 952 goto fail1; 953 } 954 955 out: 956 return (0); 957 958 fail1: 959 EFSYS_PROBE1(fail1, efx_rc_t, rc); 960 961 return (rc); 962 } 963 964 __checkReturn efx_rc_t 965 efx_mcdi_reboot( 966 __in efx_nic_t *enp) 967 { 968 return (efx_mcdi_do_reboot(enp, B_FALSE)); 969 } 970 971 __checkReturn efx_rc_t 972 efx_mcdi_exit_assertion_handler( 973 __in efx_nic_t *enp) 974 { 975 return (efx_mcdi_do_reboot(enp, B_TRUE)); 976 } 977 978 __checkReturn efx_rc_t 979 efx_mcdi_read_assertion( 980 __in efx_nic_t *enp) 981 { 982 efx_mcdi_req_t req; 983 uint8_t payload[MAX(MC_CMD_GET_ASSERTS_IN_LEN, 984 MC_CMD_GET_ASSERTS_OUT_LEN)]; 985 const char *reason; 986 unsigned int flags; 987 unsigned int index; 988 unsigned int ofst; 989 int retry; 990 efx_rc_t rc; 991 992 /* 993 * Before we attempt to chat to the MC, we should verify that the MC 994 * isn't in it's assertion handler, either due to a previous reboot, 995 * or because we're reinitializing due to an eec_exception(). 996 * 997 * Use GET_ASSERTS to read any assertion state that may be present. 998 * Retry this command twice. Once because a boot-time assertion failure 999 * might cause the 1st MCDI request to fail. And once again because 1000 * we might race with efx_mcdi_exit_assertion_handler() running on 1001 * partner port(s) on the same NIC. 1002 */ 1003 retry = 2; 1004 do { 1005 (void) memset(payload, 0, sizeof (payload)); 1006 req.emr_cmd = MC_CMD_GET_ASSERTS; 1007 req.emr_in_buf = payload; 1008 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN; 1009 req.emr_out_buf = payload; 1010 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN; 1011 1012 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1); 1013 efx_mcdi_execute_quiet(enp, &req); 1014 1015 } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0); 1016 1017 if (req.emr_rc != 0) { 1018 if (req.emr_rc == EACCES) { 1019 /* Unprivileged functions cannot clear assertions. */ 1020 goto out; 1021 } 1022 rc = req.emr_rc; 1023 goto fail1; 1024 } 1025 1026 if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) { 1027 rc = EMSGSIZE; 1028 goto fail2; 1029 } 1030 1031 /* Print out any assertion state recorded */ 1032 flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS); 1033 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) 1034 return (0); 1035 1036 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL) 1037 ? "system-level assertion" 1038 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL) 1039 ? "thread-level assertion" 1040 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED) 1041 ? "watchdog reset" 1042 : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP) 1043 ? "illegal address trap" 1044 : "unknown assertion"; 1045 EFSYS_PROBE3(mcpu_assertion, 1046 const char *, reason, unsigned int, 1047 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS), 1048 unsigned int, 1049 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS)); 1050 1051 /* Print out the registers (r1 ... r31) */ 1052 ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST; 1053 for (index = 1; 1054 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM; 1055 index++) { 1056 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int, 1057 EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst), 1058 EFX_DWORD_0)); 1059 ofst += sizeof (efx_dword_t); 1060 } 1061 EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN); 1062 1063 out: 1064 return (0); 1065 1066 fail2: 1067 EFSYS_PROBE(fail2); 1068 fail1: 1069 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1070 1071 return (rc); 1072 } 1073 1074 1075 /* 1076 * Internal routines for for specific MCDI requests. 1077 */ 1078 1079 __checkReturn efx_rc_t 1080 efx_mcdi_drv_attach( 1081 __in efx_nic_t *enp, 1082 __in boolean_t attach) 1083 { 1084 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 1085 efx_mcdi_req_t req; 1086 uint8_t payload[MAX(MC_CMD_DRV_ATTACH_IN_LEN, 1087 MC_CMD_DRV_ATTACH_EXT_OUT_LEN)]; 1088 uint32_t flags; 1089 efx_rc_t rc; 1090 1091 (void) memset(payload, 0, sizeof (payload)); 1092 req.emr_cmd = MC_CMD_DRV_ATTACH; 1093 req.emr_in_buf = payload; 1094 req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN; 1095 req.emr_out_buf = payload; 1096 req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN; 1097 1098 /* 1099 * Use DONT_CARE for the datapath firmware type to ensure that the 1100 * driver can attach to an unprivileged function. The datapath firmware 1101 * type to use is controlled by the 'sfboot' utility. 1102 */ 1103 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_NEW_STATE, attach ? 1 : 0); 1104 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1); 1105 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, MC_CMD_FW_DONT_CARE); 1106 1107 efx_mcdi_execute(enp, &req); 1108 1109 if (req.emr_rc != 0) { 1110 rc = req.emr_rc; 1111 goto fail1; 1112 } 1113 1114 if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) { 1115 rc = EMSGSIZE; 1116 goto fail2; 1117 } 1118 1119 if (attach == B_FALSE) { 1120 flags = 0; 1121 } else if (enp->en_family == EFX_FAMILY_SIENA) { 1122 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 1123 1124 /* Create synthetic privileges for Siena functions */ 1125 flags = EFX_NIC_FUNC_LINKCTRL | EFX_NIC_FUNC_TRUSTED; 1126 if (emip->emi_port == 1) 1127 flags |= EFX_NIC_FUNC_PRIMARY; 1128 } else { 1129 EFX_STATIC_ASSERT(EFX_NIC_FUNC_PRIMARY == 1130 (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_PRIMARY)); 1131 EFX_STATIC_ASSERT(EFX_NIC_FUNC_LINKCTRL == 1132 (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_LINKCTRL)); 1133 EFX_STATIC_ASSERT(EFX_NIC_FUNC_TRUSTED == 1134 (1u << MC_CMD_DRV_ATTACH_EXT_OUT_FLAG_TRUSTED)); 1135 1136 /* Save function privilege flags (EF10 and later) */ 1137 if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_EXT_OUT_LEN) { 1138 rc = EMSGSIZE; 1139 goto fail3; 1140 } 1141 flags = MCDI_OUT_DWORD(req, DRV_ATTACH_EXT_OUT_FUNC_FLAGS); 1142 } 1143 encp->enc_func_flags = flags; 1144 1145 return (0); 1146 1147 fail3: 1148 EFSYS_PROBE(fail3); 1149 fail2: 1150 EFSYS_PROBE(fail2); 1151 fail1: 1152 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1153 1154 return (rc); 1155 } 1156 1157 __checkReturn efx_rc_t 1158 efx_mcdi_get_board_cfg( 1159 __in efx_nic_t *enp, 1160 __out_opt uint32_t *board_typep, 1161 __out_opt efx_dword_t *capabilitiesp, 1162 __out_ecount_opt(6) uint8_t mac_addrp[6]) 1163 { 1164 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 1165 efx_mcdi_req_t req; 1166 uint8_t payload[MAX(MC_CMD_GET_BOARD_CFG_IN_LEN, 1167 MC_CMD_GET_BOARD_CFG_OUT_LENMIN)]; 1168 efx_rc_t rc; 1169 1170 (void) memset(payload, 0, sizeof (payload)); 1171 req.emr_cmd = MC_CMD_GET_BOARD_CFG; 1172 req.emr_in_buf = payload; 1173 req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN; 1174 req.emr_out_buf = payload; 1175 req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN; 1176 1177 efx_mcdi_execute(enp, &req); 1178 1179 if (req.emr_rc != 0) { 1180 rc = req.emr_rc; 1181 goto fail1; 1182 } 1183 1184 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) { 1185 rc = EMSGSIZE; 1186 goto fail2; 1187 } 1188 1189 if (mac_addrp != NULL) { 1190 uint8_t *addrp; 1191 1192 if (emip->emi_port == 1) { 1193 addrp = MCDI_OUT2(req, uint8_t, 1194 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0); 1195 } else if (emip->emi_port == 2) { 1196 addrp = MCDI_OUT2(req, uint8_t, 1197 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1); 1198 } else { 1199 rc = EINVAL; 1200 goto fail3; 1201 } 1202 1203 EFX_MAC_ADDR_COPY(mac_addrp, addrp); 1204 } 1205 1206 if (capabilitiesp != NULL) { 1207 if (emip->emi_port == 1) { 1208 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, 1209 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0); 1210 } else if (emip->emi_port == 2) { 1211 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, 1212 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1); 1213 } else { 1214 rc = EINVAL; 1215 goto fail4; 1216 } 1217 } 1218 1219 if (board_typep != NULL) { 1220 *board_typep = MCDI_OUT_DWORD(req, 1221 GET_BOARD_CFG_OUT_BOARD_TYPE); 1222 } 1223 1224 return (0); 1225 1226 fail4: 1227 EFSYS_PROBE(fail4); 1228 fail3: 1229 EFSYS_PROBE(fail3); 1230 fail2: 1231 EFSYS_PROBE(fail2); 1232 fail1: 1233 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1234 1235 return (rc); 1236 } 1237 1238 __checkReturn efx_rc_t 1239 efx_mcdi_get_resource_limits( 1240 __in efx_nic_t *enp, 1241 __out_opt uint32_t *nevqp, 1242 __out_opt uint32_t *nrxqp, 1243 __out_opt uint32_t *ntxqp) 1244 { 1245 efx_mcdi_req_t req; 1246 uint8_t payload[MAX(MC_CMD_GET_RESOURCE_LIMITS_IN_LEN, 1247 MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN)]; 1248 efx_rc_t rc; 1249 1250 (void) memset(payload, 0, sizeof (payload)); 1251 req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS; 1252 req.emr_in_buf = payload; 1253 req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN; 1254 req.emr_out_buf = payload; 1255 req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN; 1256 1257 efx_mcdi_execute(enp, &req); 1258 1259 if (req.emr_rc != 0) { 1260 rc = req.emr_rc; 1261 goto fail1; 1262 } 1263 1264 if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) { 1265 rc = EMSGSIZE; 1266 goto fail2; 1267 } 1268 1269 if (nevqp != NULL) 1270 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ); 1271 if (nrxqp != NULL) 1272 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ); 1273 if (ntxqp != NULL) 1274 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ); 1275 1276 return (0); 1277 1278 fail2: 1279 EFSYS_PROBE(fail2); 1280 fail1: 1281 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1282 1283 return (rc); 1284 } 1285 1286 __checkReturn efx_rc_t 1287 efx_mcdi_get_phy_cfg( 1288 __in efx_nic_t *enp) 1289 { 1290 efx_port_t *epp = &(enp->en_port); 1291 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 1292 efx_mcdi_req_t req; 1293 uint8_t payload[MAX(MC_CMD_GET_PHY_CFG_IN_LEN, 1294 MC_CMD_GET_PHY_CFG_OUT_LEN)]; 1295 efx_rc_t rc; 1296 1297 (void) memset(payload, 0, sizeof (payload)); 1298 req.emr_cmd = MC_CMD_GET_PHY_CFG; 1299 req.emr_in_buf = payload; 1300 req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN; 1301 req.emr_out_buf = payload; 1302 req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN; 1303 1304 efx_mcdi_execute(enp, &req); 1305 1306 if (req.emr_rc != 0) { 1307 rc = req.emr_rc; 1308 goto fail1; 1309 } 1310 1311 if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) { 1312 rc = EMSGSIZE; 1313 goto fail2; 1314 } 1315 1316 encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE); 1317 #if EFSYS_OPT_NAMES 1318 (void) strncpy(encp->enc_phy_name, 1319 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME), 1320 MIN(sizeof (encp->enc_phy_name) - 1, 1321 MC_CMD_GET_PHY_CFG_OUT_NAME_LEN)); 1322 #endif /* EFSYS_OPT_NAMES */ 1323 (void) memset(encp->enc_phy_revision, 0, 1324 sizeof (encp->enc_phy_revision)); 1325 memcpy(encp->enc_phy_revision, 1326 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION), 1327 MIN(sizeof (encp->enc_phy_revision) - 1, 1328 MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN)); 1329 #if EFSYS_OPT_PHY_LED_CONTROL 1330 encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) | 1331 (1 << EFX_PHY_LED_OFF) | 1332 (1 << EFX_PHY_LED_ON)); 1333 #endif /* EFSYS_OPT_PHY_LED_CONTROL */ 1334 1335 #if EFSYS_OPT_PHY_PROPS 1336 encp->enc_phy_nprops = 0; 1337 #endif /* EFSYS_OPT_PHY_PROPS */ 1338 1339 /* Get the media type of the fixed port, if recognised. */ 1340 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI); 1341 EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4); 1342 EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4); 1343 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP); 1344 EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS); 1345 EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T); 1346 EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS); 1347 epp->ep_fixed_port_type = 1348 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE); 1349 if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES) 1350 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID; 1351 1352 epp->ep_phy_cap_mask = 1353 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP); 1354 #if EFSYS_OPT_PHY_FLAGS 1355 encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS); 1356 #endif /* EFSYS_OPT_PHY_FLAGS */ 1357 1358 encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT); 1359 1360 /* Populate internal state */ 1361 encp->enc_mcdi_mdio_channel = 1362 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL); 1363 1364 #if EFSYS_OPT_PHY_STATS 1365 encp->enc_mcdi_phy_stat_mask = 1366 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK); 1367 #endif /* EFSYS_OPT_PHY_STATS */ 1368 1369 #if EFSYS_OPT_BIST 1370 encp->enc_bist_mask = 0; 1371 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1372 GET_PHY_CFG_OUT_BIST_CABLE_SHORT)) 1373 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT); 1374 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1375 GET_PHY_CFG_OUT_BIST_CABLE_LONG)) 1376 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG); 1377 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1378 GET_PHY_CFG_OUT_BIST)) 1379 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL); 1380 #endif /* EFSYS_OPT_BIST */ 1381 1382 return (0); 1383 1384 fail2: 1385 EFSYS_PROBE(fail2); 1386 fail1: 1387 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1388 1389 return (rc); 1390 } 1391 1392 __checkReturn efx_rc_t 1393 efx_mcdi_firmware_update_supported( 1394 __in efx_nic_t *enp, 1395 __out boolean_t *supportedp) 1396 { 1397 efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1398 efx_rc_t rc; 1399 1400 if (emcop != NULL) { 1401 if ((rc = emcop->emco_feature_supported(enp, 1402 EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0) 1403 goto fail1; 1404 } else { 1405 /* Earlier devices always supported updates */ 1406 *supportedp = B_TRUE; 1407 } 1408 1409 return (0); 1410 1411 fail1: 1412 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1413 1414 return (rc); 1415 } 1416 1417 __checkReturn efx_rc_t 1418 efx_mcdi_macaddr_change_supported( 1419 __in efx_nic_t *enp, 1420 __out boolean_t *supportedp) 1421 { 1422 efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1423 efx_rc_t rc; 1424 1425 if (emcop != NULL) { 1426 if ((rc = emcop->emco_feature_supported(enp, 1427 EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0) 1428 goto fail1; 1429 } else { 1430 /* Earlier devices always supported MAC changes */ 1431 *supportedp = B_TRUE; 1432 } 1433 1434 return (0); 1435 1436 fail1: 1437 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1438 1439 return (rc); 1440 } 1441 1442 __checkReturn efx_rc_t 1443 efx_mcdi_link_control_supported( 1444 __in efx_nic_t *enp, 1445 __out boolean_t *supportedp) 1446 { 1447 efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1448 efx_rc_t rc; 1449 1450 if (emcop != NULL) { 1451 if ((rc = emcop->emco_feature_supported(enp, 1452 EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0) 1453 goto fail1; 1454 } else { 1455 /* Earlier devices always supported link control */ 1456 *supportedp = B_TRUE; 1457 } 1458 1459 return (0); 1460 1461 fail1: 1462 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1463 1464 return (rc); 1465 } 1466 1467 __checkReturn efx_rc_t 1468 efx_mcdi_mac_spoofing_supported( 1469 __in efx_nic_t *enp, 1470 __out boolean_t *supportedp) 1471 { 1472 efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1473 efx_rc_t rc; 1474 1475 if (emcop != NULL) { 1476 if ((rc = emcop->emco_feature_supported(enp, 1477 EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0) 1478 goto fail1; 1479 } else { 1480 /* Earlier devices always supported MAC spoofing */ 1481 *supportedp = B_TRUE; 1482 } 1483 1484 return (0); 1485 1486 fail1: 1487 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1488 1489 return (rc); 1490 } 1491 1492 #if EFSYS_OPT_BIST 1493 1494 #if EFSYS_OPT_HUNTINGTON 1495 /* 1496 * Enter bist offline mode. This is a fw mode which puts the NIC into a state 1497 * where memory BIST tests can be run and not much else can interfere or happen. 1498 * A reboot is required to exit this mode. 1499 */ 1500 __checkReturn efx_rc_t 1501 efx_mcdi_bist_enable_offline( 1502 __in efx_nic_t *enp) 1503 { 1504 efx_mcdi_req_t req; 1505 efx_rc_t rc; 1506 1507 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0); 1508 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0); 1509 1510 req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST; 1511 req.emr_in_buf = NULL; 1512 req.emr_in_length = 0; 1513 req.emr_out_buf = NULL; 1514 req.emr_out_length = 0; 1515 1516 efx_mcdi_execute(enp, &req); 1517 1518 if (req.emr_rc != 0) { 1519 rc = req.emr_rc; 1520 goto fail1; 1521 } 1522 1523 return (0); 1524 1525 fail1: 1526 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1527 1528 return (rc); 1529 } 1530 #endif /* EFSYS_OPT_HUNTINGTON */ 1531 1532 __checkReturn efx_rc_t 1533 efx_mcdi_bist_start( 1534 __in efx_nic_t *enp, 1535 __in efx_bist_type_t type) 1536 { 1537 efx_mcdi_req_t req; 1538 uint8_t payload[MAX(MC_CMD_START_BIST_IN_LEN, 1539 MC_CMD_START_BIST_OUT_LEN)]; 1540 efx_rc_t rc; 1541 1542 (void) memset(payload, 0, sizeof (payload)); 1543 req.emr_cmd = MC_CMD_START_BIST; 1544 req.emr_in_buf = payload; 1545 req.emr_in_length = MC_CMD_START_BIST_IN_LEN; 1546 req.emr_out_buf = payload; 1547 req.emr_out_length = MC_CMD_START_BIST_OUT_LEN; 1548 1549 switch (type) { 1550 case EFX_BIST_TYPE_PHY_NORMAL: 1551 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST); 1552 break; 1553 case EFX_BIST_TYPE_PHY_CABLE_SHORT: 1554 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1555 MC_CMD_PHY_BIST_CABLE_SHORT); 1556 break; 1557 case EFX_BIST_TYPE_PHY_CABLE_LONG: 1558 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1559 MC_CMD_PHY_BIST_CABLE_LONG); 1560 break; 1561 case EFX_BIST_TYPE_MC_MEM: 1562 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1563 MC_CMD_MC_MEM_BIST); 1564 break; 1565 case EFX_BIST_TYPE_SAT_MEM: 1566 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1567 MC_CMD_PORT_MEM_BIST); 1568 break; 1569 case EFX_BIST_TYPE_REG: 1570 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1571 MC_CMD_REG_BIST); 1572 break; 1573 default: 1574 EFSYS_ASSERT(0); 1575 } 1576 1577 efx_mcdi_execute(enp, &req); 1578 1579 if (req.emr_rc != 0) { 1580 rc = req.emr_rc; 1581 goto fail1; 1582 } 1583 1584 return (0); 1585 1586 fail1: 1587 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1588 1589 return (rc); 1590 } 1591 1592 #endif /* EFSYS_OPT_BIST */ 1593 1594 1595 /* Enable logging of some events (e.g. link state changes) */ 1596 __checkReturn efx_rc_t 1597 efx_mcdi_log_ctrl( 1598 __in efx_nic_t *enp) 1599 { 1600 efx_mcdi_req_t req; 1601 uint8_t payload[MAX(MC_CMD_LOG_CTRL_IN_LEN, 1602 MC_CMD_LOG_CTRL_OUT_LEN)]; 1603 efx_rc_t rc; 1604 1605 (void) memset(payload, 0, sizeof (payload)); 1606 req.emr_cmd = MC_CMD_LOG_CTRL; 1607 req.emr_in_buf = payload; 1608 req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN; 1609 req.emr_out_buf = payload; 1610 req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN; 1611 1612 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST, 1613 MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ); 1614 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0); 1615 1616 efx_mcdi_execute(enp, &req); 1617 1618 if (req.emr_rc != 0) { 1619 rc = req.emr_rc; 1620 goto fail1; 1621 } 1622 1623 return (0); 1624 1625 fail1: 1626 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1627 1628 return (rc); 1629 } 1630 1631 1632 #if EFSYS_OPT_MAC_STATS 1633 1634 typedef enum efx_stats_action_e 1635 { 1636 EFX_STATS_CLEAR, 1637 EFX_STATS_UPLOAD, 1638 EFX_STATS_ENABLE_NOEVENTS, 1639 EFX_STATS_ENABLE_EVENTS, 1640 EFX_STATS_DISABLE, 1641 } efx_stats_action_t; 1642 1643 static __checkReturn efx_rc_t 1644 efx_mcdi_mac_stats( 1645 __in efx_nic_t *enp, 1646 __in_opt efsys_mem_t *esmp, 1647 __in efx_stats_action_t action) 1648 { 1649 efx_mcdi_req_t req; 1650 uint8_t payload[MAX(MC_CMD_MAC_STATS_IN_LEN, 1651 MC_CMD_MAC_STATS_OUT_DMA_LEN)]; 1652 int clear = (action == EFX_STATS_CLEAR); 1653 int upload = (action == EFX_STATS_UPLOAD); 1654 int enable = (action == EFX_STATS_ENABLE_NOEVENTS); 1655 int events = (action == EFX_STATS_ENABLE_EVENTS); 1656 int disable = (action == EFX_STATS_DISABLE); 1657 efx_rc_t rc; 1658 1659 (void) memset(payload, 0, sizeof (payload)); 1660 req.emr_cmd = MC_CMD_MAC_STATS; 1661 req.emr_in_buf = payload; 1662 req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN; 1663 req.emr_out_buf = payload; 1664 req.emr_out_length = MC_CMD_MAC_STATS_OUT_DMA_LEN; 1665 1666 MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD, 1667 MAC_STATS_IN_DMA, upload, 1668 MAC_STATS_IN_CLEAR, clear, 1669 MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable, 1670 MAC_STATS_IN_PERIODIC_ENABLE, enable | events, 1671 MAC_STATS_IN_PERIODIC_NOEVENT, !events, 1672 MAC_STATS_IN_PERIOD_MS, (enable | events) ? 1000: 0); 1673 1674 if (esmp != NULL) { 1675 int bytes = MC_CMD_MAC_NSTATS * sizeof (uint64_t); 1676 1677 EFX_STATIC_ASSERT(MC_CMD_MAC_NSTATS * sizeof (uint64_t) <= 1678 EFX_MAC_STATS_SIZE); 1679 1680 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO, 1681 EFSYS_MEM_ADDR(esmp) & 0xffffffff); 1682 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI, 1683 EFSYS_MEM_ADDR(esmp) >> 32); 1684 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes); 1685 } else { 1686 EFSYS_ASSERT(!upload && !enable && !events); 1687 } 1688 1689 /* 1690 * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats, 1691 * as this may fail (and leave periodic DMA enabled) if the 1692 * vadapter has already been deleted. 1693 */ 1694 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID, 1695 (disable ? EVB_PORT_ID_NULL : enp->en_vport_id)); 1696 1697 efx_mcdi_execute(enp, &req); 1698 1699 if (req.emr_rc != 0) { 1700 /* EF10: Expect ENOENT if no DMA queues are initialised */ 1701 if ((req.emr_rc != ENOENT) || 1702 (enp->en_rx_qcount + enp->en_tx_qcount != 0)) { 1703 rc = req.emr_rc; 1704 goto fail1; 1705 } 1706 } 1707 1708 return (0); 1709 1710 fail1: 1711 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1712 1713 return (rc); 1714 } 1715 1716 __checkReturn efx_rc_t 1717 efx_mcdi_mac_stats_clear( 1718 __in efx_nic_t *enp) 1719 { 1720 efx_rc_t rc; 1721 1722 if ((rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_CLEAR)) != 0) 1723 goto fail1; 1724 1725 return (0); 1726 1727 fail1: 1728 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1729 1730 return (rc); 1731 } 1732 1733 __checkReturn efx_rc_t 1734 efx_mcdi_mac_stats_upload( 1735 __in efx_nic_t *enp, 1736 __in efsys_mem_t *esmp) 1737 { 1738 efx_rc_t rc; 1739 1740 /* 1741 * The MC DMAs aggregate statistics for our convenience, so we can 1742 * avoid having to pull the statistics buffer into the cache to 1743 * maintain cumulative statistics. 1744 */ 1745 if ((rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_UPLOAD)) != 0) 1746 goto fail1; 1747 1748 return (0); 1749 1750 fail1: 1751 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1752 1753 return (rc); 1754 } 1755 1756 __checkReturn efx_rc_t 1757 efx_mcdi_mac_stats_periodic( 1758 __in efx_nic_t *enp, 1759 __in efsys_mem_t *esmp, 1760 __in uint16_t period, 1761 __in boolean_t events) 1762 { 1763 efx_rc_t rc; 1764 1765 /* 1766 * The MC DMAs aggregate statistics for our convenience, so we can 1767 * avoid having to pull the statistics buffer into the cache to 1768 * maintain cumulative statistics. 1769 * Huntington uses a fixed 1sec period, so use that on Siena too. 1770 */ 1771 if (period == 0) 1772 rc = efx_mcdi_mac_stats(enp, NULL, EFX_STATS_DISABLE); 1773 else if (events) 1774 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_EVENTS); 1775 else 1776 rc = efx_mcdi_mac_stats(enp, esmp, EFX_STATS_ENABLE_NOEVENTS); 1777 1778 if (rc != 0) 1779 goto fail1; 1780 1781 return (0); 1782 1783 fail1: 1784 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1785 1786 return (rc); 1787 } 1788 1789 #endif /* EFSYS_OPT_MAC_STATS */ 1790 1791 #if EFSYS_OPT_HUNTINGTON 1792 1793 /* 1794 * This function returns the pf and vf number of a function. If it is a pf the 1795 * vf number is 0xffff. The vf number is the index of the vf on that 1796 * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0), 1797 * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff). 1798 */ 1799 __checkReturn efx_rc_t 1800 efx_mcdi_get_function_info( 1801 __in efx_nic_t *enp, 1802 __out uint32_t *pfp, 1803 __out_opt uint32_t *vfp) 1804 { 1805 efx_mcdi_req_t req; 1806 uint8_t payload[MAX(MC_CMD_GET_FUNCTION_INFO_IN_LEN, 1807 MC_CMD_GET_FUNCTION_INFO_OUT_LEN)]; 1808 efx_rc_t rc; 1809 1810 (void) memset(payload, 0, sizeof (payload)); 1811 req.emr_cmd = MC_CMD_GET_FUNCTION_INFO; 1812 req.emr_in_buf = payload; 1813 req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN; 1814 req.emr_out_buf = payload; 1815 req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_LEN; 1816 1817 efx_mcdi_execute(enp, &req); 1818 1819 if (req.emr_rc != 0) { 1820 rc = req.emr_rc; 1821 goto fail1; 1822 } 1823 1824 if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) { 1825 rc = EMSGSIZE; 1826 goto fail2; 1827 } 1828 1829 *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF); 1830 if (vfp != NULL) 1831 *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF); 1832 1833 return (0); 1834 1835 fail2: 1836 EFSYS_PROBE(fail2); 1837 fail1: 1838 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1839 1840 return (rc); 1841 } 1842 1843 __checkReturn efx_rc_t 1844 efx_mcdi_privilege_mask( 1845 __in efx_nic_t *enp, 1846 __in uint32_t pf, 1847 __in uint32_t vf, 1848 __out uint32_t *maskp) 1849 { 1850 efx_mcdi_req_t req; 1851 uint8_t payload[MAX(MC_CMD_PRIVILEGE_MASK_IN_LEN, 1852 MC_CMD_PRIVILEGE_MASK_OUT_LEN)]; 1853 efx_rc_t rc; 1854 1855 (void) memset(payload, 0, sizeof (payload)); 1856 req.emr_cmd = MC_CMD_PRIVILEGE_MASK; 1857 req.emr_in_buf = payload; 1858 req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN; 1859 req.emr_out_buf = payload; 1860 req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN; 1861 1862 MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION, 1863 PRIVILEGE_MASK_IN_FUNCTION_PF, pf, 1864 PRIVILEGE_MASK_IN_FUNCTION_VF, vf); 1865 1866 efx_mcdi_execute(enp, &req); 1867 1868 if (req.emr_rc != 0) { 1869 rc = req.emr_rc; 1870 goto fail1; 1871 } 1872 1873 if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) { 1874 rc = EMSGSIZE; 1875 goto fail2; 1876 } 1877 1878 *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK); 1879 1880 return (0); 1881 1882 fail2: 1883 EFSYS_PROBE(fail2); 1884 fail1: 1885 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1886 1887 return (rc); 1888 } 1889 1890 #endif /* EFSYS_OPT_HUNTINGTON */ 1891 1892 __checkReturn efx_rc_t 1893 efx_mcdi_set_workaround( 1894 __in efx_nic_t *enp, 1895 __in uint32_t type, 1896 __in boolean_t enabled, 1897 __out_opt uint32_t *flagsp) 1898 { 1899 efx_mcdi_req_t req; 1900 uint8_t payload[MAX(MC_CMD_WORKAROUND_IN_LEN, 1901 MC_CMD_WORKAROUND_EXT_OUT_LEN)]; 1902 efx_rc_t rc; 1903 1904 (void) memset(payload, 0, sizeof (payload)); 1905 req.emr_cmd = MC_CMD_WORKAROUND; 1906 req.emr_in_buf = payload; 1907 req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN; 1908 req.emr_out_buf = payload; 1909 req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN; 1910 1911 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type); 1912 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0); 1913 1914 efx_mcdi_execute_quiet(enp, &req); 1915 1916 if (req.emr_rc != 0) { 1917 rc = req.emr_rc; 1918 goto fail1; 1919 } 1920 1921 if (flagsp != NULL) { 1922 if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN) 1923 *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS); 1924 else 1925 *flagsp = 0; 1926 } 1927 1928 return (0); 1929 1930 fail1: 1931 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1932 1933 return (rc); 1934 } 1935 1936 1937 __checkReturn efx_rc_t 1938 efx_mcdi_get_workarounds( 1939 __in efx_nic_t *enp, 1940 __out_opt uint32_t *implementedp, 1941 __out_opt uint32_t *enabledp) 1942 { 1943 efx_mcdi_req_t req; 1944 uint8_t payload[MC_CMD_GET_WORKAROUNDS_OUT_LEN]; 1945 efx_rc_t rc; 1946 1947 (void) memset(payload, 0, sizeof (payload)); 1948 req.emr_cmd = MC_CMD_GET_WORKAROUNDS; 1949 req.emr_in_buf = NULL; 1950 req.emr_in_length = 0; 1951 req.emr_out_buf = payload; 1952 req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN; 1953 1954 efx_mcdi_execute(enp, &req); 1955 1956 if (req.emr_rc != 0) { 1957 rc = req.emr_rc; 1958 goto fail1; 1959 } 1960 1961 if (implementedp != NULL) { 1962 *implementedp = 1963 MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED); 1964 } 1965 1966 if (enabledp != NULL) { 1967 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED); 1968 } 1969 1970 return (0); 1971 1972 fail1: 1973 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1974 1975 return (rc); 1976 } 1977 1978 1979 #endif /* EFSYS_OPT_MCDI */ 1980