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