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