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