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