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