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