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