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