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