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