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