1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright(c) 2019-2021 Xilinx, Inc. 4 * Copyright(c) 2008-2019 Solarflare Communications Inc. 5 */ 6 7 #include "efx.h" 8 #include "efx_impl.h" 9 10 #if EFSYS_OPT_MCDI 11 12 /* 13 * There are three versions of the MCDI interface: 14 * - MCDIv0: Siena BootROM. Transport uses MCDIv1 headers. 15 * - MCDIv1: Siena firmware and Huntington BootROM. 16 * - MCDIv2: EF10 firmware (Huntington/Medford) and Medford BootROM. 17 * Transport uses MCDIv2 headers. 18 * 19 * MCDIv2 Header NOT_EPOCH flag 20 * ---------------------------- 21 * A new epoch begins at initial startup or after an MC reboot, and defines when 22 * the MC should reject stale MCDI requests. 23 * 24 * The first MCDI request sent by the host should contain NOT_EPOCH=0, and all 25 * subsequent requests (until the next MC reboot) should contain NOT_EPOCH=1. 26 * 27 * After rebooting the MC will fail all requests with NOT_EPOCH=1 by writing a 28 * response with ERROR=1 and DATALEN=0 until a request is seen with NOT_EPOCH=0. 29 */ 30 31 32 33 #if EFSYS_OPT_SIENA 34 35 static const efx_mcdi_ops_t __efx_mcdi_siena_ops = { 36 siena_mcdi_init, /* emco_init */ 37 siena_mcdi_send_request, /* emco_send_request */ 38 siena_mcdi_poll_reboot, /* emco_poll_reboot */ 39 siena_mcdi_poll_response, /* emco_poll_response */ 40 siena_mcdi_read_response, /* emco_read_response */ 41 siena_mcdi_fini, /* emco_fini */ 42 siena_mcdi_feature_supported, /* emco_feature_supported */ 43 siena_mcdi_get_timeout, /* emco_get_timeout */ 44 }; 45 46 #endif /* EFSYS_OPT_SIENA */ 47 48 #if EFX_OPTS_EF10() 49 50 static const efx_mcdi_ops_t __efx_mcdi_ef10_ops = { 51 ef10_mcdi_init, /* emco_init */ 52 ef10_mcdi_send_request, /* emco_send_request */ 53 ef10_mcdi_poll_reboot, /* emco_poll_reboot */ 54 ef10_mcdi_poll_response, /* emco_poll_response */ 55 ef10_mcdi_read_response, /* emco_read_response */ 56 ef10_mcdi_fini, /* emco_fini */ 57 ef10_mcdi_feature_supported, /* emco_feature_supported */ 58 ef10_mcdi_get_timeout, /* emco_get_timeout */ 59 }; 60 61 #endif /* EFX_OPTS_EF10() */ 62 63 #if EFSYS_OPT_RIVERHEAD 64 65 static const efx_mcdi_ops_t __efx_mcdi_rhead_ops = { 66 ef10_mcdi_init, /* emco_init */ 67 ef10_mcdi_send_request, /* emco_send_request */ 68 ef10_mcdi_poll_reboot, /* emco_poll_reboot */ 69 ef10_mcdi_poll_response, /* emco_poll_response */ 70 ef10_mcdi_read_response, /* emco_read_response */ 71 ef10_mcdi_fini, /* emco_fini */ 72 ef10_mcdi_feature_supported, /* emco_feature_supported */ 73 ef10_mcdi_get_timeout, /* emco_get_timeout */ 74 }; 75 76 #endif /* EFSYS_OPT_RIVERHEAD */ 77 78 79 80 __checkReturn efx_rc_t 81 efx_mcdi_init( 82 __in efx_nic_t *enp, 83 __in const efx_mcdi_transport_t *emtp) 84 { 85 const efx_mcdi_ops_t *emcop; 86 efx_rc_t rc; 87 88 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 89 EFSYS_ASSERT3U(enp->en_mod_flags, ==, 0); 90 91 switch (enp->en_family) { 92 #if EFSYS_OPT_SIENA 93 case EFX_FAMILY_SIENA: 94 emcop = &__efx_mcdi_siena_ops; 95 break; 96 #endif /* EFSYS_OPT_SIENA */ 97 98 #if EFSYS_OPT_HUNTINGTON 99 case EFX_FAMILY_HUNTINGTON: 100 emcop = &__efx_mcdi_ef10_ops; 101 break; 102 #endif /* EFSYS_OPT_HUNTINGTON */ 103 104 #if EFSYS_OPT_MEDFORD 105 case EFX_FAMILY_MEDFORD: 106 emcop = &__efx_mcdi_ef10_ops; 107 break; 108 #endif /* EFSYS_OPT_MEDFORD */ 109 110 #if EFSYS_OPT_MEDFORD2 111 case EFX_FAMILY_MEDFORD2: 112 emcop = &__efx_mcdi_ef10_ops; 113 break; 114 #endif /* EFSYS_OPT_MEDFORD2 */ 115 116 #if EFSYS_OPT_RIVERHEAD 117 case EFX_FAMILY_RIVERHEAD: 118 emcop = &__efx_mcdi_rhead_ops; 119 break; 120 #endif /* EFSYS_OPT_RIVERHEAD */ 121 122 default: 123 EFSYS_ASSERT(0); 124 rc = ENOTSUP; 125 goto fail1; 126 } 127 128 if (enp->en_features & EFX_FEATURE_MCDI_DMA) { 129 /* MCDI requires a DMA buffer in host memory */ 130 if ((emtp == NULL) || (emtp->emt_dma_mem) == NULL) { 131 rc = EINVAL; 132 goto fail2; 133 } 134 } 135 enp->en_mcdi.em_emtp = emtp; 136 137 if (emcop != NULL && emcop->emco_init != NULL) { 138 if ((rc = emcop->emco_init(enp, emtp)) != 0) 139 goto fail3; 140 } 141 142 enp->en_mcdi.em_emcop = emcop; 143 enp->en_mod_flags |= EFX_MOD_MCDI; 144 145 return (0); 146 147 fail3: 148 EFSYS_PROBE(fail3); 149 fail2: 150 EFSYS_PROBE(fail2); 151 fail1: 152 EFSYS_PROBE1(fail1, efx_rc_t, rc); 153 154 enp->en_mcdi.em_emcop = NULL; 155 enp->en_mcdi.em_emtp = NULL; 156 enp->en_mod_flags &= ~EFX_MOD_MCDI; 157 158 return (rc); 159 } 160 161 void 162 efx_mcdi_fini( 163 __in efx_nic_t *enp) 164 { 165 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 166 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 167 168 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 169 EFSYS_ASSERT3U(enp->en_mod_flags, ==, EFX_MOD_MCDI); 170 171 if (emcop != NULL && emcop->emco_fini != NULL) 172 emcop->emco_fini(enp); 173 174 emip->emi_port = 0; 175 emip->emi_aborted = 0; 176 177 enp->en_mcdi.em_emcop = NULL; 178 enp->en_mod_flags &= ~EFX_MOD_MCDI; 179 } 180 181 void 182 efx_mcdi_new_epoch( 183 __in efx_nic_t *enp) 184 { 185 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 186 efsys_lock_state_t state; 187 188 /* Start a new epoch (allow fresh MCDI requests to succeed) */ 189 EFSYS_LOCK(enp->en_eslp, state); 190 emip->emi_new_epoch = B_TRUE; 191 EFSYS_UNLOCK(enp->en_eslp, state); 192 } 193 194 static void 195 efx_mcdi_send_request( 196 __in efx_nic_t *enp, 197 __in void *hdrp, 198 __in size_t hdr_len, 199 __in void *sdup, 200 __in size_t sdu_len) 201 { 202 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 203 204 emcop->emco_send_request(enp, hdrp, hdr_len, sdup, sdu_len); 205 } 206 207 static efx_rc_t 208 efx_mcdi_poll_reboot( 209 __in efx_nic_t *enp) 210 { 211 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 212 efx_rc_t rc; 213 214 rc = emcop->emco_poll_reboot(enp); 215 return (rc); 216 } 217 218 static boolean_t 219 efx_mcdi_poll_response( 220 __in efx_nic_t *enp) 221 { 222 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 223 boolean_t available; 224 225 available = emcop->emco_poll_response(enp); 226 return (available); 227 } 228 229 static void 230 efx_mcdi_read_response( 231 __in efx_nic_t *enp, 232 __out void *bufferp, 233 __in size_t offset, 234 __in size_t length) 235 { 236 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 237 238 emcop->emco_read_response(enp, bufferp, offset, length); 239 } 240 241 void 242 efx_mcdi_request_start( 243 __in efx_nic_t *enp, 244 __in efx_mcdi_req_t *emrp, 245 __in boolean_t ev_cpl) 246 { 247 #if EFSYS_OPT_MCDI_LOGGING 248 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 249 #endif 250 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 251 efx_dword_t hdr[2]; 252 size_t hdr_len; 253 unsigned int max_version; 254 unsigned int seq; 255 unsigned int xflags; 256 boolean_t new_epoch; 257 efsys_lock_state_t state; 258 259 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 260 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 261 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 262 263 /* 264 * efx_mcdi_request_start() is naturally serialised against both 265 * efx_mcdi_request_poll() and efx_mcdi_ev_cpl()/efx_mcdi_ev_death(), 266 * by virtue of there only being one outstanding MCDI request. 267 * Unfortunately, upper layers may also call efx_mcdi_request_abort() 268 * at any time, to timeout a pending mcdi request, That request may 269 * then subsequently complete, meaning efx_mcdi_ev_cpl() or 270 * efx_mcdi_ev_death() may end up running in parallel with 271 * efx_mcdi_request_start(). This race is handled by ensuring that 272 * %emi_pending_req, %emi_ev_cpl and %emi_seq are protected by the 273 * en_eslp lock. 274 */ 275 EFSYS_LOCK(enp->en_eslp, state); 276 EFSYS_ASSERT(emip->emi_pending_req == NULL); 277 emip->emi_pending_req = emrp; 278 emip->emi_ev_cpl = ev_cpl; 279 emip->emi_poll_cnt = 0; 280 seq = emip->emi_seq++ & EFX_MASK32(MCDI_HEADER_SEQ); 281 new_epoch = emip->emi_new_epoch; 282 max_version = emip->emi_max_version; 283 EFSYS_UNLOCK(enp->en_eslp, state); 284 285 xflags = 0; 286 if (ev_cpl) 287 xflags |= MCDI_HEADER_XFLAGS_EVREQ; 288 289 /* 290 * Huntington firmware supports MCDIv2, but the Huntington BootROM only 291 * supports MCDIv1. Use MCDIv1 headers for MCDIv1 commands where 292 * possible to support this. 293 */ 294 if ((max_version >= 2) && 295 ((emrp->emr_cmd > MC_CMD_CMD_SPACE_ESCAPE_7) || 296 (emrp->emr_in_length > MCDI_CTL_SDU_LEN_MAX_V1) || 297 (emrp->emr_out_length > MCDI_CTL_SDU_LEN_MAX_V1))) { 298 /* Construct MCDI v2 header */ 299 hdr_len = sizeof (hdr); 300 EFX_POPULATE_DWORD_8(hdr[0], 301 MCDI_HEADER_CODE, MC_CMD_V2_EXTN, 302 MCDI_HEADER_RESYNC, 1, 303 MCDI_HEADER_DATALEN, 0, 304 MCDI_HEADER_SEQ, seq, 305 MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, 306 MCDI_HEADER_ERROR, 0, 307 MCDI_HEADER_RESPONSE, 0, 308 MCDI_HEADER_XFLAGS, xflags); 309 310 EFX_POPULATE_DWORD_2(hdr[1], 311 MC_CMD_V2_EXTN_IN_EXTENDED_CMD, emrp->emr_cmd, 312 MC_CMD_V2_EXTN_IN_ACTUAL_LEN, emrp->emr_in_length); 313 } else { 314 /* Construct MCDI v1 header */ 315 hdr_len = sizeof (hdr[0]); 316 EFX_POPULATE_DWORD_8(hdr[0], 317 MCDI_HEADER_CODE, emrp->emr_cmd, 318 MCDI_HEADER_RESYNC, 1, 319 MCDI_HEADER_DATALEN, emrp->emr_in_length, 320 MCDI_HEADER_SEQ, seq, 321 MCDI_HEADER_NOT_EPOCH, new_epoch ? 0 : 1, 322 MCDI_HEADER_ERROR, 0, 323 MCDI_HEADER_RESPONSE, 0, 324 MCDI_HEADER_XFLAGS, xflags); 325 } 326 327 #if EFSYS_OPT_MCDI_LOGGING 328 if (emtp->emt_logger != NULL) { 329 emtp->emt_logger(emtp->emt_context, EFX_LOG_MCDI_REQUEST, 330 &hdr[0], hdr_len, 331 emrp->emr_in_buf, emrp->emr_in_length); 332 } 333 #endif /* EFSYS_OPT_MCDI_LOGGING */ 334 335 efx_mcdi_send_request(enp, &hdr[0], hdr_len, 336 emrp->emr_in_buf, emrp->emr_in_length); 337 } 338 339 340 static void 341 efx_mcdi_read_response_header( 342 __in efx_nic_t *enp, 343 __inout efx_mcdi_req_t *emrp) 344 { 345 #if EFSYS_OPT_MCDI_LOGGING 346 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 347 #endif /* EFSYS_OPT_MCDI_LOGGING */ 348 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 349 efx_dword_t hdr[2]; 350 unsigned int hdr_len; 351 unsigned int data_len; 352 unsigned int seq; 353 unsigned int cmd; 354 unsigned int error; 355 efx_rc_t rc; 356 357 EFSYS_ASSERT(emrp != NULL); 358 359 efx_mcdi_read_response(enp, &hdr[0], 0, sizeof (hdr[0])); 360 hdr_len = sizeof (hdr[0]); 361 362 cmd = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE); 363 seq = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_SEQ); 364 error = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_ERROR); 365 366 if (cmd != MC_CMD_V2_EXTN) { 367 data_len = EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_DATALEN); 368 } else { 369 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1])); 370 hdr_len += sizeof (hdr[1]); 371 372 cmd = EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD); 373 data_len = 374 EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_ACTUAL_LEN); 375 } 376 377 if (error && (data_len == 0)) { 378 /* The MC has rebooted since the request was sent. */ 379 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US); 380 efx_mcdi_poll_reboot(enp); 381 rc = EIO; 382 goto fail1; 383 } 384 #if EFSYS_OPT_MCDI_PROXY_AUTH_SERVER 385 if (((cmd != emrp->emr_cmd) && (emrp->emr_cmd != MC_CMD_PROXY_CMD)) || 386 #else 387 if ((cmd != emrp->emr_cmd) || 388 #endif 389 (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) { 390 /* Response is for a different request */ 391 rc = EIO; 392 goto fail2; 393 } 394 if (error) { 395 efx_dword_t err[2]; 396 unsigned int err_len = MIN(data_len, sizeof (err)); 397 int err_code = MC_CMD_ERR_EPROTO; 398 int err_arg = 0; 399 400 /* Read error code (and arg num for MCDI v2 commands) */ 401 efx_mcdi_read_response(enp, &err, hdr_len, err_len); 402 403 if (err_len >= (MC_CMD_ERR_CODE_OFST + sizeof (efx_dword_t))) 404 err_code = EFX_DWORD_FIELD(err[0], EFX_DWORD_0); 405 #ifdef WITH_MCDI_V2 406 if (err_len >= (MC_CMD_ERR_ARG_OFST + sizeof (efx_dword_t))) 407 err_arg = EFX_DWORD_FIELD(err[1], EFX_DWORD_0); 408 #endif 409 emrp->emr_err_code = err_code; 410 emrp->emr_err_arg = err_arg; 411 412 #if EFSYS_OPT_MCDI_PROXY_AUTH 413 if ((err_code == MC_CMD_ERR_PROXY_PENDING) && 414 (err_len == sizeof (err))) { 415 /* 416 * The MCDI request would normally fail with EPERM, but 417 * firmware has forwarded it to an authorization agent 418 * attached to a privileged PF. 419 * 420 * Save the authorization request handle. The client 421 * must wait for a PROXY_RESPONSE event, or timeout. 422 */ 423 emrp->emr_proxy_handle = err_arg; 424 } 425 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ 426 427 #if EFSYS_OPT_MCDI_LOGGING 428 if (emtp->emt_logger != NULL) { 429 emtp->emt_logger(emtp->emt_context, 430 EFX_LOG_MCDI_RESPONSE, 431 &hdr[0], hdr_len, 432 &err[0], err_len); 433 } 434 #endif /* EFSYS_OPT_MCDI_LOGGING */ 435 436 if (!emrp->emr_quiet) { 437 EFSYS_PROBE3(mcdi_err_arg, int, emrp->emr_cmd, 438 int, err_code, int, err_arg); 439 } 440 441 rc = efx_mcdi_request_errcode(err_code); 442 goto fail3; 443 } 444 445 emrp->emr_rc = 0; 446 emrp->emr_out_length_used = data_len; 447 #if EFSYS_OPT_MCDI_PROXY_AUTH 448 emrp->emr_proxy_handle = 0; 449 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ 450 return; 451 452 fail3: 453 fail2: 454 fail1: 455 emrp->emr_rc = rc; 456 emrp->emr_out_length_used = 0; 457 } 458 459 static void 460 efx_mcdi_finish_response( 461 __in efx_nic_t *enp, 462 __in efx_mcdi_req_t *emrp) 463 { 464 #if EFSYS_OPT_MCDI_LOGGING 465 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 466 #endif /* EFSYS_OPT_MCDI_LOGGING */ 467 efx_dword_t hdr[2]; 468 unsigned int hdr_len; 469 size_t bytes; 470 unsigned int resp_off; 471 #if EFSYS_OPT_MCDI_PROXY_AUTH_SERVER 472 unsigned int resp_cmd; 473 boolean_t proxied_cmd_resp = B_FALSE; 474 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */ 475 476 if (emrp->emr_out_buf == NULL) 477 return; 478 479 /* Read the command header to detect MCDI response format */ 480 hdr_len = sizeof (hdr[0]); 481 efx_mcdi_read_response(enp, &hdr[0], 0, hdr_len); 482 if (EFX_DWORD_FIELD(hdr[0], MCDI_HEADER_CODE) == MC_CMD_V2_EXTN) { 483 /* 484 * Read the actual payload length. The length given in the event 485 * is only correct for responses with the V1 format. 486 */ 487 efx_mcdi_read_response(enp, &hdr[1], hdr_len, sizeof (hdr[1])); 488 hdr_len += sizeof (hdr[1]); 489 resp_off = hdr_len; 490 491 emrp->emr_out_length_used = EFX_DWORD_FIELD(hdr[1], 492 MC_CMD_V2_EXTN_IN_ACTUAL_LEN); 493 #if EFSYS_OPT_MCDI_PROXY_AUTH_SERVER 494 /* 495 * A proxy MCDI command is executed by PF on behalf of 496 * one of its VFs. The command to be proxied follows 497 * immediately afterward in the host buffer. 498 * PROXY_CMD inner call complete response should be copied to 499 * output buffer so that it can be returned to the requesting 500 * function in MC_CMD_PROXY_COMPLETE payload. 501 */ 502 resp_cmd = 503 EFX_DWORD_FIELD(hdr[1], MC_CMD_V2_EXTN_IN_EXTENDED_CMD); 504 proxied_cmd_resp = ((emrp->emr_cmd == MC_CMD_PROXY_CMD) && 505 (resp_cmd != MC_CMD_PROXY_CMD)); 506 if (proxied_cmd_resp) { 507 resp_off = 0; 508 emrp->emr_out_length_used += hdr_len; 509 } 510 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */ 511 } else { 512 resp_off = hdr_len; 513 } 514 515 /* Copy payload out into caller supplied buffer */ 516 bytes = MIN(emrp->emr_out_length_used, emrp->emr_out_length); 517 efx_mcdi_read_response(enp, emrp->emr_out_buf, resp_off, bytes); 518 519 /* Report bytes copied to caller (response message may be larger) */ 520 emrp->emr_out_length_used = bytes; 521 522 #if EFSYS_OPT_MCDI_LOGGING 523 if (emtp->emt_logger != NULL) { 524 emtp->emt_logger(emtp->emt_context, 525 EFX_LOG_MCDI_RESPONSE, 526 &hdr[0], hdr_len, 527 emrp->emr_out_buf, bytes); 528 } 529 #endif /* EFSYS_OPT_MCDI_LOGGING */ 530 } 531 532 533 __checkReturn boolean_t 534 efx_mcdi_request_poll( 535 __in efx_nic_t *enp) 536 { 537 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 538 efx_mcdi_req_t *emrp; 539 efsys_lock_state_t state; 540 efx_rc_t rc; 541 542 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 543 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 544 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 545 546 /* Serialise against post-watchdog efx_mcdi_ev* */ 547 EFSYS_LOCK(enp->en_eslp, state); 548 549 EFSYS_ASSERT(emip->emi_pending_req != NULL); 550 EFSYS_ASSERT(!emip->emi_ev_cpl); 551 emrp = emip->emi_pending_req; 552 553 /* Check if hardware is unavailable */ 554 if (efx_nic_hw_unavailable(enp)) { 555 EFSYS_UNLOCK(enp->en_eslp, state); 556 return (B_FALSE); 557 } 558 559 /* Check for reboot atomically w.r.t efx_mcdi_request_start */ 560 if (emip->emi_poll_cnt++ == 0) { 561 if ((rc = efx_mcdi_poll_reboot(enp)) != 0) { 562 emip->emi_pending_req = NULL; 563 EFSYS_UNLOCK(enp->en_eslp, state); 564 565 /* Reboot/Assertion */ 566 if (rc == EIO || rc == EINTR) 567 efx_mcdi_raise_exception(enp, emrp, rc); 568 569 goto fail1; 570 } 571 } 572 573 /* Check if a response is available */ 574 if (efx_mcdi_poll_response(enp) == B_FALSE) { 575 EFSYS_UNLOCK(enp->en_eslp, state); 576 return (B_FALSE); 577 } 578 579 /* Read the response header */ 580 efx_mcdi_read_response_header(enp, emrp); 581 582 /* Request complete */ 583 emip->emi_pending_req = NULL; 584 585 /* Ensure stale MCDI requests fail after an MC reboot. */ 586 emip->emi_new_epoch = B_FALSE; 587 588 EFSYS_UNLOCK(enp->en_eslp, state); 589 590 if ((rc = emrp->emr_rc) != 0) 591 goto fail2; 592 593 efx_mcdi_finish_response(enp, emrp); 594 return (B_TRUE); 595 596 fail2: 597 if (!emrp->emr_quiet) 598 EFSYS_PROBE(fail2); 599 fail1: 600 if (!emrp->emr_quiet) 601 EFSYS_PROBE1(fail1, efx_rc_t, rc); 602 603 return (B_TRUE); 604 } 605 606 __checkReturn boolean_t 607 efx_mcdi_request_abort( 608 __in efx_nic_t *enp) 609 { 610 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 611 efx_mcdi_req_t *emrp; 612 boolean_t aborted; 613 efsys_lock_state_t state; 614 615 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 616 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 617 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 618 619 /* 620 * efx_mcdi_ev_* may have already completed this event, and be 621 * spinning/blocked on the upper layer lock. So it *is* legitimate 622 * to for emi_pending_req to be NULL. If there is a pending event 623 * completed request, then provide a "credit" to allow 624 * efx_mcdi_ev_cpl() to accept a single spurious completion. 625 */ 626 EFSYS_LOCK(enp->en_eslp, state); 627 emrp = emip->emi_pending_req; 628 aborted = (emrp != NULL); 629 if (aborted) { 630 emip->emi_pending_req = NULL; 631 632 /* Error the request */ 633 emrp->emr_out_length_used = 0; 634 emrp->emr_rc = ETIMEDOUT; 635 636 /* Provide a credit for seqno/emr_pending_req mismatches */ 637 if (emip->emi_ev_cpl) 638 ++emip->emi_aborted; 639 640 /* 641 * The upper layer has called us, so we don't 642 * need to complete the request. 643 */ 644 } 645 EFSYS_UNLOCK(enp->en_eslp, state); 646 647 return (aborted); 648 } 649 650 __checkReturn efx_rc_t 651 efx_mcdi_get_client_handle( 652 __in efx_nic_t *enp, 653 __in efx_pcie_interface_t intf, 654 __in uint16_t pf, 655 __in uint16_t vf, 656 __out uint32_t *handle) 657 { 658 efx_mcdi_req_t req; 659 EFX_MCDI_DECLARE_BUF(payload, 660 MC_CMD_GET_CLIENT_HANDLE_IN_LEN, 661 MC_CMD_GET_CLIENT_HANDLE_OUT_LEN); 662 efx_rc_t rc; 663 664 if (handle == NULL) { 665 rc = EINVAL; 666 goto fail1; 667 } 668 669 req.emr_cmd = MC_CMD_GET_CLIENT_HANDLE; 670 req.emr_in_buf = payload; 671 req.emr_in_length = MC_CMD_GET_CLIENT_HANDLE_IN_LEN; 672 req.emr_out_buf = payload; 673 req.emr_out_length = MC_CMD_GET_CLIENT_HANDLE_OUT_LEN; 674 675 MCDI_IN_SET_DWORD(req, GET_CLIENT_HANDLE_IN_TYPE, 676 MC_CMD_GET_CLIENT_HANDLE_IN_TYPE_FUNC); 677 MCDI_IN_SET_WORD(req, GET_CLIENT_HANDLE_IN_FUNC_PF, pf); 678 MCDI_IN_SET_WORD(req, GET_CLIENT_HANDLE_IN_FUNC_VF, vf); 679 MCDI_IN_SET_DWORD(req, GET_CLIENT_HANDLE_IN_FUNC_INTF, intf); 680 681 efx_mcdi_execute(enp, &req); 682 683 if (req.emr_rc != 0) { 684 rc = req.emr_rc; 685 goto fail2; 686 } 687 688 if (req.emr_out_length_used < MC_CMD_GET_CLIENT_HANDLE_OUT_LEN) { 689 rc = EMSGSIZE; 690 goto fail3; 691 } 692 693 *handle = MCDI_OUT_DWORD(req, GET_CLIENT_HANDLE_OUT_HANDLE); 694 695 return 0; 696 fail3: 697 EFSYS_PROBE(fail3); 698 fail2: 699 EFSYS_PROBE(fail2); 700 fail1: 701 EFSYS_PROBE1(fail1, efx_rc_t, rc); 702 return (rc); 703 } 704 705 __checkReturn efx_rc_t 706 efx_mcdi_get_own_client_handle( 707 __in efx_nic_t *enp, 708 __out uint32_t *handle) 709 { 710 efx_rc_t rc; 711 712 rc = efx_mcdi_get_client_handle(enp, PCIE_INTERFACE_CALLER, 713 PCIE_FUNCTION_PF_NULL, PCIE_FUNCTION_VF_NULL, handle); 714 if (rc != 0) 715 goto fail1; 716 717 return (0); 718 fail1: 719 EFSYS_PROBE1(fail1, efx_rc_t, rc); 720 return (rc); 721 } 722 723 void 724 efx_mcdi_get_timeout( 725 __in efx_nic_t *enp, 726 __in efx_mcdi_req_t *emrp, 727 __out uint32_t *timeoutp) 728 { 729 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 730 731 emcop->emco_get_timeout(enp, emrp, timeoutp); 732 } 733 734 __checkReturn efx_rc_t 735 efx_mcdi_request_errcode( 736 __in unsigned int err) 737 { 738 739 switch (err) { 740 /* MCDI v1 */ 741 case MC_CMD_ERR_EPERM: 742 return (EACCES); 743 case MC_CMD_ERR_ENOENT: 744 return (ENOENT); 745 case MC_CMD_ERR_EINTR: 746 return (EINTR); 747 case MC_CMD_ERR_EACCES: 748 return (EACCES); 749 case MC_CMD_ERR_EBUSY: 750 return (EBUSY); 751 case MC_CMD_ERR_EINVAL: 752 return (EINVAL); 753 case MC_CMD_ERR_EDEADLK: 754 return (EDEADLK); 755 case MC_CMD_ERR_ENOSYS: 756 return (ENOTSUP); 757 case MC_CMD_ERR_ETIME: 758 return (ETIMEDOUT); 759 case MC_CMD_ERR_ENOTSUP: 760 return (ENOTSUP); 761 case MC_CMD_ERR_EALREADY: 762 return (EALREADY); 763 764 /* MCDI v2 */ 765 case MC_CMD_ERR_EEXIST: 766 return (EEXIST); 767 #ifdef MC_CMD_ERR_EAGAIN 768 case MC_CMD_ERR_EAGAIN: 769 return (EAGAIN); 770 #endif 771 #ifdef MC_CMD_ERR_ENOSPC 772 case MC_CMD_ERR_ENOSPC: 773 return (ENOSPC); 774 #endif 775 case MC_CMD_ERR_ERANGE: 776 return (ERANGE); 777 778 case MC_CMD_ERR_ALLOC_FAIL: 779 return (ENOMEM); 780 case MC_CMD_ERR_NO_VADAPTOR: 781 return (ENOENT); 782 case MC_CMD_ERR_NO_EVB_PORT: 783 return (ENOENT); 784 case MC_CMD_ERR_NO_VSWITCH: 785 return (ENODEV); 786 case MC_CMD_ERR_VLAN_LIMIT: 787 return (EINVAL); 788 case MC_CMD_ERR_BAD_PCI_FUNC: 789 return (ENODEV); 790 case MC_CMD_ERR_BAD_VLAN_MODE: 791 return (EINVAL); 792 case MC_CMD_ERR_BAD_VSWITCH_TYPE: 793 return (EINVAL); 794 case MC_CMD_ERR_BAD_VPORT_TYPE: 795 return (EINVAL); 796 case MC_CMD_ERR_MAC_EXIST: 797 return (EEXIST); 798 799 case MC_CMD_ERR_PROXY_PENDING: 800 return (EAGAIN); 801 802 default: 803 EFSYS_PROBE1(mc_pcol_error, int, err); 804 return (EIO); 805 } 806 } 807 808 void 809 efx_mcdi_raise_exception( 810 __in efx_nic_t *enp, 811 __in_opt efx_mcdi_req_t *emrp, 812 __in int rc) 813 { 814 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 815 efx_mcdi_exception_t exception; 816 817 /* Reboot or Assertion failure only */ 818 EFSYS_ASSERT(rc == EIO || rc == EINTR); 819 820 /* 821 * If MC_CMD_REBOOT causes a reboot (dependent on parameters), 822 * then the EIO is not worthy of an exception. 823 */ 824 if (emrp != NULL && emrp->emr_cmd == MC_CMD_REBOOT && rc == EIO) 825 return; 826 827 exception = (rc == EIO) 828 ? EFX_MCDI_EXCEPTION_MC_REBOOT 829 : EFX_MCDI_EXCEPTION_MC_BADASSERT; 830 831 emtp->emt_exception(emtp->emt_context, exception); 832 } 833 834 void 835 efx_mcdi_execute( 836 __in efx_nic_t *enp, 837 __inout efx_mcdi_req_t *emrp) 838 { 839 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 840 841 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 842 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 843 844 emrp->emr_quiet = B_FALSE; 845 emtp->emt_execute(emtp->emt_context, emrp); 846 } 847 848 void 849 efx_mcdi_execute_quiet( 850 __in efx_nic_t *enp, 851 __inout efx_mcdi_req_t *emrp) 852 { 853 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 854 855 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 856 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 857 858 emrp->emr_quiet = B_TRUE; 859 emtp->emt_execute(emtp->emt_context, emrp); 860 } 861 862 void 863 efx_mcdi_ev_cpl( 864 __in efx_nic_t *enp, 865 __in unsigned int seq, 866 __in unsigned int outlen, 867 __in int errcode) 868 { 869 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 870 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 871 efx_mcdi_req_t *emrp; 872 efsys_lock_state_t state; 873 874 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_MCDI); 875 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 876 877 /* 878 * Serialise against efx_mcdi_request_poll()/efx_mcdi_request_start() 879 * when we're completing an aborted request. 880 */ 881 EFSYS_LOCK(enp->en_eslp, state); 882 if (emip->emi_pending_req == NULL || !emip->emi_ev_cpl || 883 (seq != ((emip->emi_seq - 1) & EFX_MASK32(MCDI_HEADER_SEQ)))) { 884 EFSYS_ASSERT(emip->emi_aborted > 0); 885 if (emip->emi_aborted > 0) 886 --emip->emi_aborted; 887 EFSYS_UNLOCK(enp->en_eslp, state); 888 return; 889 } 890 891 emrp = emip->emi_pending_req; 892 emip->emi_pending_req = NULL; 893 EFSYS_UNLOCK(enp->en_eslp, state); 894 895 if (emip->emi_max_version >= 2) { 896 /* MCDIv2 response details do not fit into an event. */ 897 efx_mcdi_read_response_header(enp, emrp); 898 } else { 899 if (errcode != 0) { 900 if (!emrp->emr_quiet) { 901 EFSYS_PROBE2(mcdi_err, int, emrp->emr_cmd, 902 int, errcode); 903 } 904 emrp->emr_out_length_used = 0; 905 emrp->emr_rc = efx_mcdi_request_errcode(errcode); 906 } else { 907 emrp->emr_out_length_used = outlen; 908 emrp->emr_rc = 0; 909 } 910 } 911 if (emrp->emr_rc == 0) 912 efx_mcdi_finish_response(enp, emrp); 913 914 emtp->emt_ev_cpl(emtp->emt_context); 915 } 916 917 #if EFSYS_OPT_MCDI_PROXY_AUTH 918 919 __checkReturn efx_rc_t 920 efx_mcdi_get_proxy_handle( 921 __in efx_nic_t *enp, 922 __in efx_mcdi_req_t *emrp, 923 __out uint32_t *handlep) 924 { 925 efx_rc_t rc; 926 927 _NOTE(ARGUNUSED(enp)) 928 929 /* 930 * Return proxy handle from MCDI request that returned with error 931 * MC_MCD_ERR_PROXY_PENDING. This handle is used to wait for a matching 932 * PROXY_RESPONSE event. 933 */ 934 if ((emrp == NULL) || (handlep == NULL)) { 935 rc = EINVAL; 936 goto fail1; 937 } 938 if ((emrp->emr_rc != 0) && 939 (emrp->emr_err_code == MC_CMD_ERR_PROXY_PENDING)) { 940 *handlep = emrp->emr_proxy_handle; 941 rc = 0; 942 } else { 943 *handlep = 0; 944 rc = ENOENT; 945 } 946 return (rc); 947 948 fail1: 949 EFSYS_PROBE1(fail1, efx_rc_t, rc); 950 return (rc); 951 } 952 953 void 954 efx_mcdi_ev_proxy_response( 955 __in efx_nic_t *enp, 956 __in unsigned int handle, 957 __in unsigned int status) 958 { 959 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 960 efx_rc_t rc; 961 962 /* 963 * Handle results of an authorization request for a privileged MCDI 964 * command. If authorization was granted then we must re-issue the 965 * original MCDI request. If authorization failed or timed out, 966 * then the original MCDI request should be completed with the 967 * result code from this event. 968 */ 969 rc = (status == 0) ? 0 : efx_mcdi_request_errcode(status); 970 971 emtp->emt_ev_proxy_response(emtp->emt_context, handle, rc); 972 } 973 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH */ 974 975 #if EFSYS_OPT_MCDI_PROXY_AUTH_SERVER 976 void 977 efx_mcdi_ev_proxy_request( 978 __in efx_nic_t *enp, 979 __in unsigned int index) 980 { 981 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 982 983 if (emtp->emt_ev_proxy_request != NULL) 984 emtp->emt_ev_proxy_request(emtp->emt_context, index); 985 } 986 #endif /* EFSYS_OPT_MCDI_PROXY_AUTH_SERVER */ 987 void 988 efx_mcdi_ev_death( 989 __in efx_nic_t *enp, 990 __in int rc) 991 { 992 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 993 const efx_mcdi_transport_t *emtp = enp->en_mcdi.em_emtp; 994 efx_mcdi_req_t *emrp = NULL; 995 boolean_t ev_cpl; 996 efsys_lock_state_t state; 997 998 /* 999 * The MCDI request (if there is one) has been terminated, either 1000 * by a BADASSERT or REBOOT event. 1001 * 1002 * If there is an outstanding event-completed MCDI operation, then we 1003 * will never receive the completion event (because both MCDI 1004 * completions and BADASSERT events are sent to the same evq). So 1005 * complete this MCDI op. 1006 * 1007 * This function might run in parallel with efx_mcdi_request_poll() 1008 * for poll completed mcdi requests, and also with 1009 * efx_mcdi_request_start() for post-watchdog completions. 1010 */ 1011 EFSYS_LOCK(enp->en_eslp, state); 1012 emrp = emip->emi_pending_req; 1013 ev_cpl = emip->emi_ev_cpl; 1014 if (emrp != NULL && emip->emi_ev_cpl) { 1015 emip->emi_pending_req = NULL; 1016 1017 emrp->emr_out_length_used = 0; 1018 emrp->emr_rc = rc; 1019 ++emip->emi_aborted; 1020 } 1021 1022 /* 1023 * Since we're running in parallel with a request, consume the 1024 * status word before dropping the lock. 1025 */ 1026 if (rc == EIO || rc == EINTR) { 1027 EFSYS_SPIN(EFX_MCDI_STATUS_SLEEP_US); 1028 (void) efx_mcdi_poll_reboot(enp); 1029 emip->emi_new_epoch = B_TRUE; 1030 } 1031 1032 EFSYS_UNLOCK(enp->en_eslp, state); 1033 1034 efx_mcdi_raise_exception(enp, emrp, rc); 1035 1036 if (emrp != NULL && ev_cpl) 1037 emtp->emt_ev_cpl(emtp->emt_context); 1038 } 1039 1040 __checkReturn efx_rc_t 1041 efx_mcdi_get_version( 1042 __in efx_nic_t *enp, 1043 __in uint32_t flags, 1044 __out efx_mcdi_version_t *verp) 1045 { 1046 efx_nic_board_info_t *board_infop = &verp->emv_board_info; 1047 EFX_MCDI_DECLARE_BUF(payload, 1048 MC_CMD_GET_VERSION_EXT_IN_LEN, 1049 MC_CMD_GET_VERSION_V2_OUT_LEN); 1050 efx_word_t *ver_words; 1051 uint16_t version[4]; 1052 efx_mcdi_req_t req; 1053 uint32_t firmware; 1054 efx_rc_t rc; 1055 1056 EFX_STATIC_ASSERT(sizeof (verp->emv_version) == 1057 MC_CMD_GET_VERSION_OUT_VERSION_LEN); 1058 EFX_STATIC_ASSERT(sizeof (verp->emv_firmware) == 1059 MC_CMD_GET_VERSION_OUT_FIRMWARE_LEN); 1060 1061 EFX_STATIC_ASSERT(EFX_MCDI_VERSION_BOARD_INFO == 1062 (1U << MC_CMD_GET_VERSION_V2_OUT_BOARD_EXT_INFO_PRESENT_LBN)); 1063 1064 EFX_STATIC_ASSERT(sizeof (board_infop->enbi_serial) == 1065 MC_CMD_GET_VERSION_V2_OUT_BOARD_SERIAL_LEN); 1066 EFX_STATIC_ASSERT(sizeof (board_infop->enbi_name) == 1067 MC_CMD_GET_VERSION_V2_OUT_BOARD_NAME_LEN); 1068 EFX_STATIC_ASSERT(sizeof (board_infop->enbi_revision) == 1069 MC_CMD_GET_VERSION_V2_OUT_BOARD_REVISION_LEN); 1070 1071 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 1072 1073 req.emr_cmd = MC_CMD_GET_VERSION; 1074 req.emr_in_buf = payload; 1075 req.emr_out_buf = payload; 1076 1077 if ((flags & EFX_MCDI_VERSION_BOARD_INFO) != 0) { 1078 /* Request basic + extended version information. */ 1079 req.emr_in_length = MC_CMD_GET_VERSION_EXT_IN_LEN; 1080 req.emr_out_length = MC_CMD_GET_VERSION_V2_OUT_LEN; 1081 } else { 1082 /* Request only basic version information. */ 1083 req.emr_in_length = MC_CMD_GET_VERSION_IN_LEN; 1084 req.emr_out_length = MC_CMD_GET_VERSION_OUT_LEN; 1085 } 1086 1087 efx_mcdi_execute(enp, &req); 1088 1089 if (req.emr_rc != 0) { 1090 rc = req.emr_rc; 1091 goto fail1; 1092 } 1093 1094 /* bootrom support */ 1095 if (req.emr_out_length_used == MC_CMD_GET_VERSION_V0_OUT_LEN) { 1096 version[0] = version[1] = version[2] = version[3] = 0; 1097 firmware = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 1098 goto out; 1099 } 1100 1101 if (req.emr_out_length_used < req.emr_out_length) { 1102 rc = EMSGSIZE; 1103 goto fail2; 1104 } 1105 1106 ver_words = MCDI_OUT2(req, efx_word_t, GET_VERSION_OUT_VERSION); 1107 version[0] = EFX_WORD_FIELD(ver_words[0], EFX_WORD_0); 1108 version[1] = EFX_WORD_FIELD(ver_words[1], EFX_WORD_0); 1109 version[2] = EFX_WORD_FIELD(ver_words[2], EFX_WORD_0); 1110 version[3] = EFX_WORD_FIELD(ver_words[3], EFX_WORD_0); 1111 firmware = MCDI_OUT_DWORD(req, GET_VERSION_OUT_FIRMWARE); 1112 1113 out: 1114 memset(verp, 0, sizeof (*verp)); 1115 1116 verp->emv_version[0] = version[0]; 1117 verp->emv_version[1] = version[1]; 1118 verp->emv_version[2] = version[2]; 1119 verp->emv_version[3] = version[3]; 1120 verp->emv_firmware = firmware; 1121 1122 verp->emv_flags = MCDI_OUT_DWORD(req, GET_VERSION_V2_OUT_FLAGS); 1123 verp->emv_flags &= flags; 1124 1125 if ((verp->emv_flags & EFX_MCDI_VERSION_BOARD_INFO) != 0) { 1126 memcpy(board_infop->enbi_serial, 1127 MCDI_OUT2(req, char, GET_VERSION_V2_OUT_BOARD_SERIAL), 1128 sizeof (board_infop->enbi_serial)); 1129 memcpy(board_infop->enbi_name, 1130 MCDI_OUT2(req, char, GET_VERSION_V2_OUT_BOARD_NAME), 1131 sizeof (board_infop->enbi_name)); 1132 board_infop->enbi_revision = 1133 MCDI_OUT_DWORD(req, GET_VERSION_V2_OUT_BOARD_REVISION); 1134 } 1135 1136 return (0); 1137 1138 fail2: 1139 EFSYS_PROBE(fail2); 1140 fail1: 1141 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1142 1143 return (rc); 1144 } 1145 1146 static __checkReturn efx_rc_t 1147 efx_mcdi_get_boot_status( 1148 __in efx_nic_t *enp, 1149 __out efx_mcdi_boot_t *statusp) 1150 { 1151 EFX_MCDI_DECLARE_BUF(payload, 1152 MC_CMD_GET_BOOT_STATUS_IN_LEN, 1153 MC_CMD_GET_BOOT_STATUS_OUT_LEN); 1154 efx_mcdi_req_t req; 1155 efx_rc_t rc; 1156 1157 EFSYS_ASSERT3U(enp->en_features, &, EFX_FEATURE_MCDI); 1158 1159 req.emr_cmd = MC_CMD_GET_BOOT_STATUS; 1160 req.emr_in_buf = payload; 1161 req.emr_in_length = MC_CMD_GET_BOOT_STATUS_IN_LEN; 1162 req.emr_out_buf = payload; 1163 req.emr_out_length = MC_CMD_GET_BOOT_STATUS_OUT_LEN; 1164 1165 efx_mcdi_execute_quiet(enp, &req); 1166 1167 /* 1168 * NOTE: Unprivileged functions cannot access boot status, 1169 * so the MCDI request will return EACCES. This is 1170 * also checked in efx_mcdi_version. 1171 */ 1172 1173 if (req.emr_rc != 0) { 1174 rc = req.emr_rc; 1175 goto fail1; 1176 } 1177 1178 if (req.emr_out_length_used < MC_CMD_GET_BOOT_STATUS_OUT_LEN) { 1179 rc = EMSGSIZE; 1180 goto fail2; 1181 } 1182 1183 if (MCDI_OUT_DWORD_FIELD(req, GET_BOOT_STATUS_OUT_FLAGS, 1184 GET_BOOT_STATUS_OUT_FLAGS_PRIMARY)) 1185 *statusp = EFX_MCDI_BOOT_PRIMARY; 1186 else 1187 *statusp = EFX_MCDI_BOOT_SECONDARY; 1188 1189 return (0); 1190 1191 fail2: 1192 EFSYS_PROBE(fail2); 1193 fail1: 1194 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1195 1196 return (rc); 1197 } 1198 1199 __checkReturn efx_rc_t 1200 efx_mcdi_version( 1201 __in efx_nic_t *enp, 1202 __out_ecount_opt(4) uint16_t versionp[4], 1203 __out_opt uint32_t *buildp, 1204 __out_opt efx_mcdi_boot_t *statusp) 1205 { 1206 efx_mcdi_version_t ver; 1207 efx_mcdi_boot_t status; 1208 efx_rc_t rc; 1209 1210 rc = efx_mcdi_get_version(enp, 0, &ver); 1211 if (rc != 0) 1212 goto fail1; 1213 1214 /* The bootrom doesn't understand BOOT_STATUS */ 1215 if (MC_FW_VERSION_IS_BOOTLOADER(ver.emv_firmware)) { 1216 status = EFX_MCDI_BOOT_ROM; 1217 goto out; 1218 } 1219 1220 rc = efx_mcdi_get_boot_status(enp, &status); 1221 if (rc == EACCES) { 1222 /* Unprivileged functions cannot access BOOT_STATUS */ 1223 status = EFX_MCDI_BOOT_PRIMARY; 1224 memset(ver.emv_version, 0, sizeof (ver.emv_version)); 1225 ver.emv_firmware = 0; 1226 } else if (rc != 0) { 1227 goto fail2; 1228 } 1229 1230 out: 1231 if (versionp != NULL) 1232 memcpy(versionp, ver.emv_version, sizeof (ver.emv_version)); 1233 if (buildp != NULL) 1234 *buildp = ver.emv_firmware; 1235 if (statusp != NULL) 1236 *statusp = status; 1237 1238 return (0); 1239 1240 fail2: 1241 EFSYS_PROBE(fail2); 1242 fail1: 1243 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1244 1245 return (rc); 1246 } 1247 1248 __checkReturn efx_rc_t 1249 efx_mcdi_get_capabilities( 1250 __in efx_nic_t *enp, 1251 __out_opt uint32_t *flagsp, 1252 __out_opt uint16_t *rx_dpcpu_fw_idp, 1253 __out_opt uint16_t *tx_dpcpu_fw_idp, 1254 __out_opt uint32_t *flags2p, 1255 __out_opt uint32_t *tso2ncp) 1256 { 1257 efx_mcdi_req_t req; 1258 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_CAPABILITIES_IN_LEN, 1259 MC_CMD_GET_CAPABILITIES_V2_OUT_LEN); 1260 boolean_t v2_capable; 1261 efx_rc_t rc; 1262 1263 req.emr_cmd = MC_CMD_GET_CAPABILITIES; 1264 req.emr_in_buf = payload; 1265 req.emr_in_length = MC_CMD_GET_CAPABILITIES_IN_LEN; 1266 req.emr_out_buf = payload; 1267 req.emr_out_length = MC_CMD_GET_CAPABILITIES_V2_OUT_LEN; 1268 1269 efx_mcdi_execute_quiet(enp, &req); 1270 1271 if (req.emr_rc != 0) { 1272 rc = req.emr_rc; 1273 goto fail1; 1274 } 1275 1276 if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_OUT_LEN) { 1277 rc = EMSGSIZE; 1278 goto fail2; 1279 } 1280 1281 if (flagsp != NULL) 1282 *flagsp = MCDI_OUT_DWORD(req, GET_CAPABILITIES_OUT_FLAGS1); 1283 1284 if (rx_dpcpu_fw_idp != NULL) 1285 *rx_dpcpu_fw_idp = MCDI_OUT_WORD(req, 1286 GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID); 1287 1288 if (tx_dpcpu_fw_idp != NULL) 1289 *tx_dpcpu_fw_idp = MCDI_OUT_WORD(req, 1290 GET_CAPABILITIES_OUT_TX_DPCPU_FW_ID); 1291 1292 if (req.emr_out_length_used < MC_CMD_GET_CAPABILITIES_V2_OUT_LEN) 1293 v2_capable = B_FALSE; 1294 else 1295 v2_capable = B_TRUE; 1296 1297 if (flags2p != NULL) { 1298 *flags2p = (v2_capable) ? 1299 MCDI_OUT_DWORD(req, GET_CAPABILITIES_V2_OUT_FLAGS2) : 1300 0; 1301 } 1302 1303 if (tso2ncp != NULL) { 1304 *tso2ncp = (v2_capable) ? 1305 MCDI_OUT_WORD(req, 1306 GET_CAPABILITIES_V2_OUT_TX_TSO_V2_N_CONTEXTS) : 1307 0; 1308 } 1309 1310 return (0); 1311 1312 fail2: 1313 EFSYS_PROBE(fail2); 1314 fail1: 1315 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1316 1317 return (rc); 1318 } 1319 1320 static __checkReturn efx_rc_t 1321 efx_mcdi_do_reboot( 1322 __in efx_nic_t *enp, 1323 __in boolean_t after_assertion) 1324 { 1325 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_REBOOT_IN_LEN, 1326 MC_CMD_REBOOT_OUT_LEN); 1327 efx_mcdi_req_t req; 1328 efx_rc_t rc; 1329 1330 /* 1331 * We could require the caller to have caused en_mod_flags=0 to 1332 * call this function. This doesn't help the other port though, 1333 * who's about to get the MC ripped out from underneath them. 1334 * Since they have to cope with the subsequent fallout of MCDI 1335 * failures, we should as well. 1336 */ 1337 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 1338 1339 req.emr_cmd = MC_CMD_REBOOT; 1340 req.emr_in_buf = payload; 1341 req.emr_in_length = MC_CMD_REBOOT_IN_LEN; 1342 req.emr_out_buf = payload; 1343 req.emr_out_length = MC_CMD_REBOOT_OUT_LEN; 1344 1345 MCDI_IN_SET_DWORD(req, REBOOT_IN_FLAGS, 1346 (after_assertion ? MC_CMD_REBOOT_FLAGS_AFTER_ASSERTION : 0)); 1347 1348 efx_mcdi_execute_quiet(enp, &req); 1349 1350 if (req.emr_rc == EACCES) { 1351 /* Unprivileged functions cannot reboot the MC. */ 1352 goto out; 1353 } 1354 1355 /* A successful reboot request returns EIO. */ 1356 if (req.emr_rc != 0 && req.emr_rc != EIO) { 1357 rc = req.emr_rc; 1358 goto fail1; 1359 } 1360 1361 out: 1362 return (0); 1363 1364 fail1: 1365 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1366 1367 return (rc); 1368 } 1369 1370 __checkReturn efx_rc_t 1371 efx_mcdi_reboot( 1372 __in efx_nic_t *enp) 1373 { 1374 return (efx_mcdi_do_reboot(enp, B_FALSE)); 1375 } 1376 1377 __checkReturn efx_rc_t 1378 efx_mcdi_exit_assertion_handler( 1379 __in efx_nic_t *enp) 1380 { 1381 return (efx_mcdi_do_reboot(enp, B_TRUE)); 1382 } 1383 1384 __checkReturn efx_rc_t 1385 efx_mcdi_read_assertion( 1386 __in efx_nic_t *enp) 1387 { 1388 efx_mcdi_req_t req; 1389 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_ASSERTS_IN_LEN, 1390 MC_CMD_GET_ASSERTS_OUT_LEN); 1391 const char *reason; 1392 unsigned int flags; 1393 unsigned int index; 1394 unsigned int ofst; 1395 int retry; 1396 efx_rc_t rc; 1397 1398 /* 1399 * Before we attempt to chat to the MC, we should verify that the MC 1400 * isn't in it's assertion handler, either due to a previous reboot, 1401 * or because we're reinitializing due to an eec_exception(). 1402 * 1403 * Use GET_ASSERTS to read any assertion state that may be present. 1404 * Retry this command twice. Once because a boot-time assertion failure 1405 * might cause the 1st MCDI request to fail. And once again because 1406 * we might race with efx_mcdi_exit_assertion_handler() running on 1407 * partner port(s) on the same NIC. 1408 */ 1409 retry = 2; 1410 do { 1411 (void) memset(payload, 0, sizeof (payload)); 1412 req.emr_cmd = MC_CMD_GET_ASSERTS; 1413 req.emr_in_buf = payload; 1414 req.emr_in_length = MC_CMD_GET_ASSERTS_IN_LEN; 1415 req.emr_out_buf = payload; 1416 req.emr_out_length = MC_CMD_GET_ASSERTS_OUT_LEN; 1417 1418 MCDI_IN_SET_DWORD(req, GET_ASSERTS_IN_CLEAR, 1); 1419 efx_mcdi_execute_quiet(enp, &req); 1420 1421 } while ((req.emr_rc == EINTR || req.emr_rc == EIO) && retry-- > 0); 1422 1423 if (req.emr_rc != 0) { 1424 if (req.emr_rc == EACCES) { 1425 /* Unprivileged functions cannot clear assertions. */ 1426 goto out; 1427 } 1428 rc = req.emr_rc; 1429 goto fail1; 1430 } 1431 1432 if (req.emr_out_length_used < MC_CMD_GET_ASSERTS_OUT_LEN) { 1433 rc = EMSGSIZE; 1434 goto fail2; 1435 } 1436 1437 /* Print out any assertion state recorded */ 1438 flags = MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_GLOBAL_FLAGS); 1439 if (flags == MC_CMD_GET_ASSERTS_FLAGS_NO_FAILS) 1440 return (0); 1441 1442 reason = (flags == MC_CMD_GET_ASSERTS_FLAGS_SYS_FAIL) 1443 ? "system-level assertion" 1444 : (flags == MC_CMD_GET_ASSERTS_FLAGS_THR_FAIL) 1445 ? "thread-level assertion" 1446 : (flags == MC_CMD_GET_ASSERTS_FLAGS_WDOG_FIRED) 1447 ? "watchdog reset" 1448 : (flags == MC_CMD_GET_ASSERTS_FLAGS_ADDR_TRAP) 1449 ? "illegal address trap" 1450 : "unknown assertion"; 1451 EFSYS_PROBE3(mcpu_assertion, 1452 const char *, reason, unsigned int, 1453 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_SAVED_PC_OFFS), 1454 unsigned int, 1455 MCDI_OUT_DWORD(req, GET_ASSERTS_OUT_THREAD_OFFS)); 1456 1457 /* Print out the registers (r1 ... r31) */ 1458 ofst = MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST; 1459 for (index = 1; 1460 index < 1 + MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM; 1461 index++) { 1462 EFSYS_PROBE2(mcpu_register, unsigned int, index, unsigned int, 1463 EFX_DWORD_FIELD(*MCDI_OUT(req, efx_dword_t, ofst), 1464 EFX_DWORD_0)); 1465 ofst += sizeof (efx_dword_t); 1466 } 1467 EFSYS_ASSERT(ofst <= MC_CMD_GET_ASSERTS_OUT_LEN); 1468 1469 out: 1470 return (0); 1471 1472 fail2: 1473 EFSYS_PROBE(fail2); 1474 fail1: 1475 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1476 1477 return (rc); 1478 } 1479 1480 1481 /* 1482 * Internal routines for for specific MCDI requests. 1483 */ 1484 1485 __checkReturn efx_rc_t 1486 efx_mcdi_drv_attach( 1487 __in efx_nic_t *enp, 1488 __in boolean_t attach) 1489 { 1490 efx_mcdi_req_t req; 1491 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_DRV_ATTACH_IN_V2_LEN, 1492 MC_CMD_DRV_ATTACH_EXT_OUT_LEN); 1493 efx_rc_t rc; 1494 1495 req.emr_cmd = MC_CMD_DRV_ATTACH; 1496 req.emr_in_buf = payload; 1497 if (enp->en_drv_version[0] == '\0') { 1498 req.emr_in_length = MC_CMD_DRV_ATTACH_IN_LEN; 1499 } else { 1500 req.emr_in_length = MC_CMD_DRV_ATTACH_IN_V2_LEN; 1501 } 1502 req.emr_out_buf = payload; 1503 req.emr_out_length = MC_CMD_DRV_ATTACH_EXT_OUT_LEN; 1504 1505 /* 1506 * Typically, client drivers use DONT_CARE for the datapath firmware 1507 * type to ensure that the driver can attach to an unprivileged 1508 * function. The datapath firmware type to use is controlled by the 1509 * 'sfboot' utility. 1510 * If a client driver wishes to attach with a specific datapath firmware 1511 * type, that can be passed in second argument of efx_nic_probe API. One 1512 * such example is the ESXi native driver that attempts attaching with 1513 * FULL_FEATURED datapath firmware type first and fall backs to 1514 * DONT_CARE datapath firmware type if MC_CMD_DRV_ATTACH fails. 1515 */ 1516 MCDI_IN_POPULATE_DWORD_2(req, DRV_ATTACH_IN_NEW_STATE, 1517 DRV_ATTACH_IN_ATTACH, attach ? 1 : 0, 1518 DRV_ATTACH_IN_SUBVARIANT_AWARE, EFSYS_OPT_FW_SUBVARIANT_AWARE); 1519 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_UPDATE, 1); 1520 MCDI_IN_SET_DWORD(req, DRV_ATTACH_IN_FIRMWARE_ID, enp->efv); 1521 1522 if (req.emr_in_length >= MC_CMD_DRV_ATTACH_IN_V2_LEN) { 1523 EFX_STATIC_ASSERT(sizeof (enp->en_drv_version) == 1524 MC_CMD_DRV_ATTACH_IN_V2_DRIVER_VERSION_LEN); 1525 memcpy(MCDI_IN2(req, char, DRV_ATTACH_IN_V2_DRIVER_VERSION), 1526 enp->en_drv_version, 1527 MC_CMD_DRV_ATTACH_IN_V2_DRIVER_VERSION_LEN); 1528 } 1529 1530 efx_mcdi_execute(enp, &req); 1531 1532 if (req.emr_rc != 0) { 1533 rc = req.emr_rc; 1534 goto fail1; 1535 } 1536 1537 if (req.emr_out_length_used < MC_CMD_DRV_ATTACH_OUT_LEN) { 1538 rc = EMSGSIZE; 1539 goto fail2; 1540 } 1541 1542 return (0); 1543 1544 fail2: 1545 EFSYS_PROBE(fail2); 1546 fail1: 1547 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1548 1549 return (rc); 1550 } 1551 1552 __checkReturn efx_rc_t 1553 efx_mcdi_get_board_cfg( 1554 __in efx_nic_t *enp, 1555 __out_opt uint32_t *board_typep, 1556 __out_opt efx_dword_t *capabilitiesp, 1557 __out_ecount_opt(6) uint8_t mac_addrp[6]) 1558 { 1559 efx_mcdi_iface_t *emip = &(enp->en_mcdi.em_emip); 1560 efx_mcdi_req_t req; 1561 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_BOARD_CFG_IN_LEN, 1562 MC_CMD_GET_BOARD_CFG_OUT_LENMIN); 1563 efx_rc_t rc; 1564 1565 req.emr_cmd = MC_CMD_GET_BOARD_CFG; 1566 req.emr_in_buf = payload; 1567 req.emr_in_length = MC_CMD_GET_BOARD_CFG_IN_LEN; 1568 req.emr_out_buf = payload; 1569 req.emr_out_length = MC_CMD_GET_BOARD_CFG_OUT_LENMIN; 1570 1571 efx_mcdi_execute(enp, &req); 1572 1573 if (req.emr_rc != 0) { 1574 rc = req.emr_rc; 1575 goto fail1; 1576 } 1577 1578 if (req.emr_out_length_used < MC_CMD_GET_BOARD_CFG_OUT_LENMIN) { 1579 rc = EMSGSIZE; 1580 goto fail2; 1581 } 1582 1583 if (mac_addrp != NULL) { 1584 uint8_t *addrp; 1585 1586 if (emip->emi_port == 1) { 1587 addrp = MCDI_OUT2(req, uint8_t, 1588 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0); 1589 } else if (emip->emi_port == 2) { 1590 addrp = MCDI_OUT2(req, uint8_t, 1591 GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1); 1592 } else { 1593 rc = EINVAL; 1594 goto fail3; 1595 } 1596 1597 EFX_MAC_ADDR_COPY(mac_addrp, addrp); 1598 } 1599 1600 if (capabilitiesp != NULL) { 1601 if (emip->emi_port == 1) { 1602 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, 1603 GET_BOARD_CFG_OUT_CAPABILITIES_PORT0); 1604 } else if (emip->emi_port == 2) { 1605 *capabilitiesp = *MCDI_OUT2(req, efx_dword_t, 1606 GET_BOARD_CFG_OUT_CAPABILITIES_PORT1); 1607 } else { 1608 rc = EINVAL; 1609 goto fail4; 1610 } 1611 } 1612 1613 if (board_typep != NULL) { 1614 *board_typep = MCDI_OUT_DWORD(req, 1615 GET_BOARD_CFG_OUT_BOARD_TYPE); 1616 } 1617 1618 return (0); 1619 1620 fail4: 1621 EFSYS_PROBE(fail4); 1622 fail3: 1623 EFSYS_PROBE(fail3); 1624 fail2: 1625 EFSYS_PROBE(fail2); 1626 fail1: 1627 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1628 1629 return (rc); 1630 } 1631 1632 __checkReturn efx_rc_t 1633 efx_mcdi_get_resource_limits( 1634 __in efx_nic_t *enp, 1635 __out_opt uint32_t *nevqp, 1636 __out_opt uint32_t *nrxqp, 1637 __out_opt uint32_t *ntxqp) 1638 { 1639 efx_mcdi_req_t req; 1640 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_RESOURCE_LIMITS_IN_LEN, 1641 MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN); 1642 efx_rc_t rc; 1643 1644 req.emr_cmd = MC_CMD_GET_RESOURCE_LIMITS; 1645 req.emr_in_buf = payload; 1646 req.emr_in_length = MC_CMD_GET_RESOURCE_LIMITS_IN_LEN; 1647 req.emr_out_buf = payload; 1648 req.emr_out_length = MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN; 1649 1650 efx_mcdi_execute(enp, &req); 1651 1652 if (req.emr_rc != 0) { 1653 rc = req.emr_rc; 1654 goto fail1; 1655 } 1656 1657 if (req.emr_out_length_used < MC_CMD_GET_RESOURCE_LIMITS_OUT_LEN) { 1658 rc = EMSGSIZE; 1659 goto fail2; 1660 } 1661 1662 if (nevqp != NULL) 1663 *nevqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_EVQ); 1664 if (nrxqp != NULL) 1665 *nrxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_RXQ); 1666 if (ntxqp != NULL) 1667 *ntxqp = MCDI_OUT_DWORD(req, GET_RESOURCE_LIMITS_OUT_TXQ); 1668 1669 return (0); 1670 1671 fail2: 1672 EFSYS_PROBE(fail2); 1673 fail1: 1674 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1675 1676 return (rc); 1677 } 1678 1679 __checkReturn efx_rc_t 1680 efx_mcdi_get_phy_cfg( 1681 __in efx_nic_t *enp) 1682 { 1683 efx_port_t *epp = &(enp->en_port); 1684 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 1685 efx_mcdi_req_t req; 1686 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_CFG_IN_LEN, 1687 MC_CMD_GET_PHY_CFG_OUT_LEN); 1688 #if EFSYS_OPT_NAMES 1689 const char *namep; 1690 size_t namelen; 1691 #endif 1692 uint32_t phy_media_type; 1693 efx_rc_t rc; 1694 1695 req.emr_cmd = MC_CMD_GET_PHY_CFG; 1696 req.emr_in_buf = payload; 1697 req.emr_in_length = MC_CMD_GET_PHY_CFG_IN_LEN; 1698 req.emr_out_buf = payload; 1699 req.emr_out_length = MC_CMD_GET_PHY_CFG_OUT_LEN; 1700 1701 efx_mcdi_execute(enp, &req); 1702 1703 if (req.emr_rc != 0) { 1704 rc = req.emr_rc; 1705 goto fail1; 1706 } 1707 1708 if (req.emr_out_length_used < MC_CMD_GET_PHY_CFG_OUT_LEN) { 1709 rc = EMSGSIZE; 1710 goto fail2; 1711 } 1712 1713 encp->enc_phy_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_TYPE); 1714 #if EFSYS_OPT_NAMES 1715 namep = MCDI_OUT2(req, char, GET_PHY_CFG_OUT_NAME); 1716 namelen = MIN(sizeof (encp->enc_phy_name) - 1, 1717 strnlen(namep, MC_CMD_GET_PHY_CFG_OUT_NAME_LEN)); 1718 (void) memset(encp->enc_phy_name, 0, 1719 sizeof (encp->enc_phy_name)); 1720 memcpy(encp->enc_phy_name, namep, namelen); 1721 #endif /* EFSYS_OPT_NAMES */ 1722 (void) memset(encp->enc_phy_revision, 0, 1723 sizeof (encp->enc_phy_revision)); 1724 memcpy(encp->enc_phy_revision, 1725 MCDI_OUT2(req, char, GET_PHY_CFG_OUT_REVISION), 1726 MIN(sizeof (encp->enc_phy_revision) - 1, 1727 MC_CMD_GET_PHY_CFG_OUT_REVISION_LEN)); 1728 #if EFSYS_OPT_PHY_LED_CONTROL 1729 encp->enc_led_mask = ((1 << EFX_PHY_LED_DEFAULT) | 1730 (1 << EFX_PHY_LED_OFF) | 1731 (1 << EFX_PHY_LED_ON)); 1732 #endif /* EFSYS_OPT_PHY_LED_CONTROL */ 1733 1734 /* Get the media type of the fixed port, if recognised. */ 1735 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XAUI == EFX_PHY_MEDIA_XAUI); 1736 EFX_STATIC_ASSERT(MC_CMD_MEDIA_CX4 == EFX_PHY_MEDIA_CX4); 1737 EFX_STATIC_ASSERT(MC_CMD_MEDIA_KX4 == EFX_PHY_MEDIA_KX4); 1738 EFX_STATIC_ASSERT(MC_CMD_MEDIA_XFP == EFX_PHY_MEDIA_XFP); 1739 EFX_STATIC_ASSERT(MC_CMD_MEDIA_SFP_PLUS == EFX_PHY_MEDIA_SFP_PLUS); 1740 EFX_STATIC_ASSERT(MC_CMD_MEDIA_BASE_T == EFX_PHY_MEDIA_BASE_T); 1741 EFX_STATIC_ASSERT(MC_CMD_MEDIA_QSFP_PLUS == EFX_PHY_MEDIA_QSFP_PLUS); 1742 phy_media_type = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_MEDIA_TYPE); 1743 epp->ep_fixed_port_type = (efx_phy_media_type_t)phy_media_type; 1744 if (epp->ep_fixed_port_type >= EFX_PHY_MEDIA_NTYPES) 1745 epp->ep_fixed_port_type = EFX_PHY_MEDIA_INVALID; 1746 1747 epp->ep_phy_cap_mask = 1748 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_SUPPORTED_CAP); 1749 #if EFSYS_OPT_PHY_FLAGS 1750 encp->enc_phy_flags_mask = MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_FLAGS); 1751 #endif /* EFSYS_OPT_PHY_FLAGS */ 1752 1753 encp->enc_port = (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_PRT); 1754 1755 /* Populate internal state */ 1756 encp->enc_mcdi_mdio_channel = 1757 (uint8_t)MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_CHANNEL); 1758 1759 #if EFSYS_OPT_PHY_STATS 1760 encp->enc_mcdi_phy_stat_mask = 1761 MCDI_OUT_DWORD(req, GET_PHY_CFG_OUT_STATS_MASK); 1762 #endif /* EFSYS_OPT_PHY_STATS */ 1763 1764 #if EFSYS_OPT_BIST 1765 encp->enc_bist_mask = 0; 1766 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1767 GET_PHY_CFG_OUT_BIST_CABLE_SHORT)) 1768 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_SHORT); 1769 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1770 GET_PHY_CFG_OUT_BIST_CABLE_LONG)) 1771 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_CABLE_LONG); 1772 if (MCDI_OUT_DWORD_FIELD(req, GET_PHY_CFG_OUT_FLAGS, 1773 GET_PHY_CFG_OUT_BIST)) 1774 encp->enc_bist_mask |= (1 << EFX_BIST_TYPE_PHY_NORMAL); 1775 #endif /* EFSYS_OPT_BIST */ 1776 1777 return (0); 1778 1779 fail2: 1780 EFSYS_PROBE(fail2); 1781 fail1: 1782 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1783 1784 return (rc); 1785 } 1786 1787 __checkReturn efx_rc_t 1788 efx_mcdi_firmware_update_supported( 1789 __in efx_nic_t *enp, 1790 __out boolean_t *supportedp) 1791 { 1792 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1793 efx_rc_t rc; 1794 1795 if (emcop != NULL) { 1796 if ((rc = emcop->emco_feature_supported(enp, 1797 EFX_MCDI_FEATURE_FW_UPDATE, supportedp)) != 0) 1798 goto fail1; 1799 } else { 1800 /* Earlier devices always supported updates */ 1801 *supportedp = B_TRUE; 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_macaddr_change_supported( 1814 __in efx_nic_t *enp, 1815 __out boolean_t *supportedp) 1816 { 1817 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1818 efx_rc_t rc; 1819 1820 if (emcop != NULL) { 1821 if ((rc = emcop->emco_feature_supported(enp, 1822 EFX_MCDI_FEATURE_MACADDR_CHANGE, supportedp)) != 0) 1823 goto fail1; 1824 } else { 1825 /* Earlier devices always supported MAC changes */ 1826 *supportedp = B_TRUE; 1827 } 1828 1829 return (0); 1830 1831 fail1: 1832 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1833 1834 return (rc); 1835 } 1836 1837 __checkReturn efx_rc_t 1838 efx_mcdi_link_control_supported( 1839 __in efx_nic_t *enp, 1840 __out boolean_t *supportedp) 1841 { 1842 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1843 efx_rc_t rc; 1844 1845 if (emcop != NULL) { 1846 if ((rc = emcop->emco_feature_supported(enp, 1847 EFX_MCDI_FEATURE_LINK_CONTROL, supportedp)) != 0) 1848 goto fail1; 1849 } else { 1850 /* Earlier devices always supported link control */ 1851 *supportedp = B_TRUE; 1852 } 1853 1854 return (0); 1855 1856 fail1: 1857 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1858 1859 return (rc); 1860 } 1861 1862 __checkReturn efx_rc_t 1863 efx_mcdi_mac_spoofing_supported( 1864 __in efx_nic_t *enp, 1865 __out boolean_t *supportedp) 1866 { 1867 const efx_mcdi_ops_t *emcop = enp->en_mcdi.em_emcop; 1868 efx_rc_t rc; 1869 1870 if (emcop != NULL) { 1871 if ((rc = emcop->emco_feature_supported(enp, 1872 EFX_MCDI_FEATURE_MAC_SPOOFING, supportedp)) != 0) 1873 goto fail1; 1874 } else { 1875 /* Earlier devices always supported MAC spoofing */ 1876 *supportedp = B_TRUE; 1877 } 1878 1879 return (0); 1880 1881 fail1: 1882 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1883 1884 return (rc); 1885 } 1886 1887 #if EFSYS_OPT_BIST 1888 1889 #if EFX_OPTS_EF10() 1890 /* 1891 * Enter bist offline mode. This is a fw mode which puts the NIC into a state 1892 * where memory BIST tests can be run and not much else can interfere or happen. 1893 * A reboot is required to exit this mode. 1894 */ 1895 __checkReturn efx_rc_t 1896 efx_mcdi_bist_enable_offline( 1897 __in efx_nic_t *enp) 1898 { 1899 efx_mcdi_req_t req; 1900 efx_rc_t rc; 1901 1902 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_IN_LEN == 0); 1903 EFX_STATIC_ASSERT(MC_CMD_ENABLE_OFFLINE_BIST_OUT_LEN == 0); 1904 1905 req.emr_cmd = MC_CMD_ENABLE_OFFLINE_BIST; 1906 req.emr_in_buf = NULL; 1907 req.emr_in_length = 0; 1908 req.emr_out_buf = NULL; 1909 req.emr_out_length = 0; 1910 1911 efx_mcdi_execute(enp, &req); 1912 1913 if (req.emr_rc != 0) { 1914 rc = req.emr_rc; 1915 goto fail1; 1916 } 1917 1918 return (0); 1919 1920 fail1: 1921 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1922 1923 return (rc); 1924 } 1925 #endif /* EFX_OPTS_EF10() */ 1926 1927 __checkReturn efx_rc_t 1928 efx_mcdi_bist_start( 1929 __in efx_nic_t *enp, 1930 __in efx_bist_type_t type) 1931 { 1932 efx_mcdi_req_t req; 1933 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_START_BIST_IN_LEN, 1934 MC_CMD_START_BIST_OUT_LEN); 1935 efx_rc_t rc; 1936 1937 req.emr_cmd = MC_CMD_START_BIST; 1938 req.emr_in_buf = payload; 1939 req.emr_in_length = MC_CMD_START_BIST_IN_LEN; 1940 req.emr_out_buf = payload; 1941 req.emr_out_length = MC_CMD_START_BIST_OUT_LEN; 1942 1943 switch (type) { 1944 case EFX_BIST_TYPE_PHY_NORMAL: 1945 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, MC_CMD_PHY_BIST); 1946 break; 1947 case EFX_BIST_TYPE_PHY_CABLE_SHORT: 1948 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1949 MC_CMD_PHY_BIST_CABLE_SHORT); 1950 break; 1951 case EFX_BIST_TYPE_PHY_CABLE_LONG: 1952 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1953 MC_CMD_PHY_BIST_CABLE_LONG); 1954 break; 1955 case EFX_BIST_TYPE_MC_MEM: 1956 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1957 MC_CMD_MC_MEM_BIST); 1958 break; 1959 case EFX_BIST_TYPE_SAT_MEM: 1960 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1961 MC_CMD_PORT_MEM_BIST); 1962 break; 1963 case EFX_BIST_TYPE_REG: 1964 MCDI_IN_SET_DWORD(req, START_BIST_IN_TYPE, 1965 MC_CMD_REG_BIST); 1966 break; 1967 default: 1968 EFSYS_ASSERT(0); 1969 } 1970 1971 efx_mcdi_execute(enp, &req); 1972 1973 if (req.emr_rc != 0) { 1974 rc = req.emr_rc; 1975 goto fail1; 1976 } 1977 1978 return (0); 1979 1980 fail1: 1981 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1982 1983 return (rc); 1984 } 1985 1986 #endif /* EFSYS_OPT_BIST */ 1987 1988 1989 /* Enable logging of some events (e.g. link state changes) */ 1990 __checkReturn efx_rc_t 1991 efx_mcdi_log_ctrl( 1992 __in efx_nic_t *enp) 1993 { 1994 efx_mcdi_req_t req; 1995 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_LOG_CTRL_IN_LEN, 1996 MC_CMD_LOG_CTRL_OUT_LEN); 1997 efx_rc_t rc; 1998 1999 req.emr_cmd = MC_CMD_LOG_CTRL; 2000 req.emr_in_buf = payload; 2001 req.emr_in_length = MC_CMD_LOG_CTRL_IN_LEN; 2002 req.emr_out_buf = payload; 2003 req.emr_out_length = MC_CMD_LOG_CTRL_OUT_LEN; 2004 2005 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST, 2006 MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ); 2007 MCDI_IN_SET_DWORD(req, LOG_CTRL_IN_LOG_DEST_EVQ, 0); 2008 2009 efx_mcdi_execute(enp, &req); 2010 2011 if (req.emr_rc != 0) { 2012 rc = req.emr_rc; 2013 goto fail1; 2014 } 2015 2016 return (0); 2017 2018 fail1: 2019 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2020 2021 return (rc); 2022 } 2023 2024 2025 #if EFSYS_OPT_MAC_STATS 2026 2027 __checkReturn efx_rc_t 2028 efx_mcdi_mac_stats( 2029 __in efx_nic_t *enp, 2030 __in uint32_t vport_id, 2031 __in_opt efsys_mem_t *esmp, 2032 __in efx_stats_action_t action, 2033 __in uint16_t period_ms) 2034 { 2035 efx_mcdi_req_t req; 2036 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_MAC_STATS_IN_LEN, 2037 MC_CMD_MAC_STATS_V2_OUT_DMA_LEN); 2038 int clear = (action == EFX_STATS_CLEAR); 2039 int upload = (action == EFX_STATS_UPLOAD); 2040 int enable = (action == EFX_STATS_ENABLE_NOEVENTS); 2041 int events = (action == EFX_STATS_ENABLE_EVENTS); 2042 int disable = (action == EFX_STATS_DISABLE); 2043 efx_rc_t rc; 2044 2045 req.emr_cmd = MC_CMD_MAC_STATS; 2046 req.emr_in_buf = payload; 2047 req.emr_in_length = MC_CMD_MAC_STATS_IN_LEN; 2048 req.emr_out_buf = payload; 2049 req.emr_out_length = MC_CMD_MAC_STATS_V2_OUT_DMA_LEN; 2050 2051 MCDI_IN_POPULATE_DWORD_6(req, MAC_STATS_IN_CMD, 2052 MAC_STATS_IN_DMA, upload, 2053 MAC_STATS_IN_CLEAR, clear, 2054 MAC_STATS_IN_PERIODIC_CHANGE, enable | events | disable, 2055 MAC_STATS_IN_PERIODIC_ENABLE, enable | events, 2056 MAC_STATS_IN_PERIODIC_NOEVENT, !events, 2057 MAC_STATS_IN_PERIOD_MS, (enable | events) ? period_ms : 0); 2058 2059 if (enable || events || upload) { 2060 const efx_nic_cfg_t *encp = &enp->en_nic_cfg; 2061 uint32_t bytes; 2062 2063 /* Periodic stats or stats upload require a DMA buffer */ 2064 if (esmp == NULL) { 2065 rc = EINVAL; 2066 goto fail1; 2067 } 2068 2069 if (encp->enc_mac_stats_nstats < MC_CMD_MAC_NSTATS) { 2070 /* MAC stats count too small for legacy MAC stats */ 2071 rc = ENOSPC; 2072 goto fail2; 2073 } 2074 2075 bytes = encp->enc_mac_stats_nstats * sizeof (efx_qword_t); 2076 2077 if (EFSYS_MEM_SIZE(esmp) < bytes) { 2078 /* DMA buffer too small */ 2079 rc = ENOSPC; 2080 goto fail3; 2081 } 2082 2083 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_LO, 2084 EFSYS_MEM_ADDR(esmp) & 0xffffffff); 2085 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_ADDR_HI, 2086 EFSYS_MEM_ADDR(esmp) >> 32); 2087 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_DMA_LEN, bytes); 2088 } 2089 2090 /* 2091 * NOTE: Do not use EVB_PORT_ID_ASSIGNED when disabling periodic stats, 2092 * as this may fail (and leave periodic DMA enabled) if the 2093 * vadapter has already been deleted. 2094 */ 2095 MCDI_IN_SET_DWORD(req, MAC_STATS_IN_PORT_ID, 2096 (disable ? EVB_PORT_ID_NULL : vport_id)); 2097 2098 efx_mcdi_execute(enp, &req); 2099 2100 if (req.emr_rc != 0) { 2101 /* EF10: Expect ENOENT if no DMA queues are initialised */ 2102 if ((req.emr_rc != ENOENT) || 2103 (enp->en_rx_qcount + enp->en_tx_qcount != 0)) { 2104 rc = req.emr_rc; 2105 goto fail4; 2106 } 2107 } 2108 2109 return (0); 2110 2111 fail4: 2112 EFSYS_PROBE(fail4); 2113 fail3: 2114 EFSYS_PROBE(fail3); 2115 fail2: 2116 EFSYS_PROBE(fail2); 2117 fail1: 2118 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2119 2120 return (rc); 2121 } 2122 2123 __checkReturn efx_rc_t 2124 efx_mcdi_mac_stats_clear( 2125 __in efx_nic_t *enp) 2126 { 2127 efx_rc_t rc; 2128 2129 if ((rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, NULL, 2130 EFX_STATS_CLEAR, 0)) != 0) 2131 goto fail1; 2132 2133 return (0); 2134 2135 fail1: 2136 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2137 2138 return (rc); 2139 } 2140 2141 __checkReturn efx_rc_t 2142 efx_mcdi_mac_stats_upload( 2143 __in efx_nic_t *enp, 2144 __in efsys_mem_t *esmp) 2145 { 2146 efx_rc_t rc; 2147 2148 /* 2149 * The MC DMAs aggregate statistics for our convenience, so we can 2150 * avoid having to pull the statistics buffer into the cache to 2151 * maintain cumulative statistics. 2152 */ 2153 if ((rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, esmp, 2154 EFX_STATS_UPLOAD, 0)) != 0) 2155 goto fail1; 2156 2157 return (0); 2158 2159 fail1: 2160 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2161 2162 return (rc); 2163 } 2164 2165 __checkReturn efx_rc_t 2166 efx_mcdi_mac_stats_periodic( 2167 __in efx_nic_t *enp, 2168 __in efsys_mem_t *esmp, 2169 __in uint16_t period_ms, 2170 __in boolean_t events) 2171 { 2172 efx_rc_t rc; 2173 2174 /* 2175 * The MC DMAs aggregate statistics for our convenience, so we can 2176 * avoid having to pull the statistics buffer into the cache to 2177 * maintain cumulative statistics. 2178 * Huntington uses a fixed 1sec period. 2179 * Medford uses a fixed 1sec period before v6.2.1.1033 firmware. 2180 */ 2181 if (period_ms == 0) 2182 rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, NULL, 2183 EFX_STATS_DISABLE, 0); 2184 else if (events) 2185 rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, esmp, 2186 EFX_STATS_ENABLE_EVENTS, period_ms); 2187 else 2188 rc = efx_mcdi_mac_stats(enp, enp->en_vport_id, esmp, 2189 EFX_STATS_ENABLE_NOEVENTS, period_ms); 2190 2191 if (rc != 0) 2192 goto fail1; 2193 2194 return (0); 2195 2196 fail1: 2197 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2198 2199 return (rc); 2200 } 2201 2202 #endif /* EFSYS_OPT_MAC_STATS */ 2203 2204 #if EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() 2205 2206 __checkReturn efx_rc_t 2207 efx_mcdi_intf_from_pcie( 2208 __in uint32_t pcie_intf, 2209 __out efx_pcie_interface_t *efx_intf) 2210 { 2211 efx_rc_t rc; 2212 2213 switch (pcie_intf) { 2214 case PCIE_INTERFACE_CALLER: 2215 *efx_intf = EFX_PCIE_INTERFACE_CALLER; 2216 break; 2217 case PCIE_INTERFACE_HOST_PRIMARY: 2218 *efx_intf = EFX_PCIE_INTERFACE_HOST_PRIMARY; 2219 break; 2220 case PCIE_INTERFACE_NIC_EMBEDDED: 2221 *efx_intf = EFX_PCIE_INTERFACE_NIC_EMBEDDED; 2222 break; 2223 default: 2224 rc = EINVAL; 2225 goto fail1; 2226 } 2227 2228 return (0); 2229 2230 fail1: 2231 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2232 2233 return (rc); 2234 } 2235 2236 /* 2237 * This function returns the pf and vf number of a function. If it is a pf the 2238 * vf number is 0xffff. The vf number is the index of the vf on that 2239 * function. So if you have 3 vfs on pf 0 the 3 vfs will return (pf=0,vf=0), 2240 * (pf=0,vf=1), (pf=0,vf=2) aand the pf will return (pf=0, vf=0xffff). 2241 */ 2242 __checkReturn efx_rc_t 2243 efx_mcdi_get_function_info( 2244 __in efx_nic_t *enp, 2245 __out uint32_t *pfp, 2246 __out_opt uint32_t *vfp, 2247 __out_opt efx_pcie_interface_t *intfp) 2248 { 2249 efx_pcie_interface_t intf; 2250 efx_mcdi_req_t req; 2251 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_FUNCTION_INFO_IN_LEN, 2252 MC_CMD_GET_FUNCTION_INFO_OUT_V2_LEN); 2253 uint32_t pcie_intf; 2254 efx_rc_t rc; 2255 2256 req.emr_cmd = MC_CMD_GET_FUNCTION_INFO; 2257 req.emr_in_buf = payload; 2258 req.emr_in_length = MC_CMD_GET_FUNCTION_INFO_IN_LEN; 2259 req.emr_out_buf = payload; 2260 req.emr_out_length = MC_CMD_GET_FUNCTION_INFO_OUT_V2_LEN; 2261 2262 efx_mcdi_execute(enp, &req); 2263 2264 if (req.emr_rc != 0) { 2265 rc = req.emr_rc; 2266 goto fail1; 2267 } 2268 2269 if (req.emr_out_length_used < MC_CMD_GET_FUNCTION_INFO_OUT_LEN) { 2270 rc = EMSGSIZE; 2271 goto fail2; 2272 } 2273 2274 *pfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_PF); 2275 if (vfp != NULL) 2276 *vfp = MCDI_OUT_DWORD(req, GET_FUNCTION_INFO_OUT_VF); 2277 2278 if (req.emr_out_length < MC_CMD_GET_FUNCTION_INFO_OUT_V2_LEN) { 2279 intf = EFX_PCIE_INTERFACE_HOST_PRIMARY; 2280 } else { 2281 pcie_intf = MCDI_OUT_DWORD(req, 2282 GET_FUNCTION_INFO_OUT_V2_INTF); 2283 2284 rc = efx_mcdi_intf_from_pcie(pcie_intf, &intf); 2285 if (rc != 0) 2286 goto fail3; 2287 } 2288 2289 if (intfp != NULL) 2290 *intfp = intf; 2291 2292 return (0); 2293 2294 fail3: 2295 EFSYS_PROBE(fail3); 2296 fail2: 2297 EFSYS_PROBE(fail2); 2298 fail1: 2299 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2300 2301 return (rc); 2302 } 2303 2304 __checkReturn efx_rc_t 2305 efx_mcdi_privilege_mask( 2306 __in efx_nic_t *enp, 2307 __in uint32_t pf, 2308 __in uint32_t vf, 2309 __out uint32_t *maskp) 2310 { 2311 efx_mcdi_req_t req; 2312 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_PRIVILEGE_MASK_IN_LEN, 2313 MC_CMD_PRIVILEGE_MASK_OUT_LEN); 2314 efx_rc_t rc; 2315 2316 req.emr_cmd = MC_CMD_PRIVILEGE_MASK; 2317 req.emr_in_buf = payload; 2318 req.emr_in_length = MC_CMD_PRIVILEGE_MASK_IN_LEN; 2319 req.emr_out_buf = payload; 2320 req.emr_out_length = MC_CMD_PRIVILEGE_MASK_OUT_LEN; 2321 2322 MCDI_IN_POPULATE_DWORD_2(req, PRIVILEGE_MASK_IN_FUNCTION, 2323 PRIVILEGE_MASK_IN_FUNCTION_PF, pf, 2324 PRIVILEGE_MASK_IN_FUNCTION_VF, vf); 2325 2326 efx_mcdi_execute(enp, &req); 2327 2328 if (req.emr_rc != 0) { 2329 rc = req.emr_rc; 2330 goto fail1; 2331 } 2332 2333 if (req.emr_out_length_used < MC_CMD_PRIVILEGE_MASK_OUT_LEN) { 2334 rc = EMSGSIZE; 2335 goto fail2; 2336 } 2337 2338 *maskp = MCDI_OUT_DWORD(req, PRIVILEGE_MASK_OUT_OLD_MASK); 2339 2340 return (0); 2341 2342 fail2: 2343 EFSYS_PROBE(fail2); 2344 fail1: 2345 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2346 2347 return (rc); 2348 } 2349 2350 #endif /* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */ 2351 2352 __checkReturn efx_rc_t 2353 efx_mcdi_set_workaround( 2354 __in efx_nic_t *enp, 2355 __in uint32_t type, 2356 __in boolean_t enabled, 2357 __out_opt uint32_t *flagsp) 2358 { 2359 efx_mcdi_req_t req; 2360 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_WORKAROUND_IN_LEN, 2361 MC_CMD_WORKAROUND_EXT_OUT_LEN); 2362 efx_rc_t rc; 2363 2364 req.emr_cmd = MC_CMD_WORKAROUND; 2365 req.emr_in_buf = payload; 2366 req.emr_in_length = MC_CMD_WORKAROUND_IN_LEN; 2367 req.emr_out_buf = payload; 2368 req.emr_out_length = MC_CMD_WORKAROUND_OUT_LEN; 2369 2370 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_TYPE, type); 2371 MCDI_IN_SET_DWORD(req, WORKAROUND_IN_ENABLED, enabled ? 1 : 0); 2372 2373 efx_mcdi_execute_quiet(enp, &req); 2374 2375 if (req.emr_rc != 0) { 2376 rc = req.emr_rc; 2377 goto fail1; 2378 } 2379 2380 if (flagsp != NULL) { 2381 if (req.emr_out_length_used >= MC_CMD_WORKAROUND_EXT_OUT_LEN) 2382 *flagsp = MCDI_OUT_DWORD(req, WORKAROUND_EXT_OUT_FLAGS); 2383 else 2384 *flagsp = 0; 2385 } 2386 2387 return (0); 2388 2389 fail1: 2390 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2391 2392 return (rc); 2393 } 2394 2395 2396 __checkReturn efx_rc_t 2397 efx_mcdi_get_workarounds( 2398 __in efx_nic_t *enp, 2399 __out_opt uint32_t *implementedp, 2400 __out_opt uint32_t *enabledp) 2401 { 2402 efx_mcdi_req_t req; 2403 EFX_MCDI_DECLARE_BUF(payload, 0, MC_CMD_GET_WORKAROUNDS_OUT_LEN); 2404 efx_rc_t rc; 2405 2406 req.emr_cmd = MC_CMD_GET_WORKAROUNDS; 2407 req.emr_in_buf = NULL; 2408 req.emr_in_length = 0; 2409 req.emr_out_buf = payload; 2410 req.emr_out_length = MC_CMD_GET_WORKAROUNDS_OUT_LEN; 2411 2412 efx_mcdi_execute(enp, &req); 2413 2414 if (req.emr_rc != 0) { 2415 rc = req.emr_rc; 2416 goto fail1; 2417 } 2418 2419 if (req.emr_out_length_used < MC_CMD_GET_WORKAROUNDS_OUT_LEN) { 2420 rc = EMSGSIZE; 2421 goto fail2; 2422 } 2423 2424 if (implementedp != NULL) { 2425 *implementedp = 2426 MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_IMPLEMENTED); 2427 } 2428 2429 if (enabledp != NULL) { 2430 *enabledp = MCDI_OUT_DWORD(req, GET_WORKAROUNDS_OUT_ENABLED); 2431 } 2432 2433 return (0); 2434 2435 fail2: 2436 EFSYS_PROBE(fail2); 2437 fail1: 2438 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2439 2440 return (rc); 2441 } 2442 2443 /* 2444 * Size of media information page in accordance with SFF-8472 and SFF-8436. 2445 * It is used in MCDI interface as well. 2446 */ 2447 #define EFX_PHY_MEDIA_INFO_PAGE_SIZE 0x80 2448 2449 /* 2450 * Transceiver identifiers from SFF-8024 Table 4-1. 2451 */ 2452 #define EFX_SFF_TRANSCEIVER_ID_SFP 0x03 /* SFP/SFP+/SFP28 */ 2453 #define EFX_SFF_TRANSCEIVER_ID_QSFP 0x0c /* QSFP */ 2454 #define EFX_SFF_TRANSCEIVER_ID_QSFP_PLUS 0x0d /* QSFP+ or later */ 2455 #define EFX_SFF_TRANSCEIVER_ID_QSFP28 0x11 /* QSFP28 or later */ 2456 2457 static __checkReturn efx_rc_t 2458 efx_mcdi_get_phy_media_info( 2459 __in efx_nic_t *enp, 2460 __in uint32_t mcdi_page, 2461 __in uint8_t offset, 2462 __in uint8_t len, 2463 __out_bcount(len) uint8_t *data) 2464 { 2465 efx_mcdi_req_t req; 2466 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN, 2467 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN( 2468 EFX_PHY_MEDIA_INFO_PAGE_SIZE)); 2469 efx_rc_t rc; 2470 2471 EFSYS_ASSERT((uint32_t)offset + len <= EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2472 2473 req.emr_cmd = MC_CMD_GET_PHY_MEDIA_INFO; 2474 req.emr_in_buf = payload; 2475 req.emr_in_length = MC_CMD_GET_PHY_MEDIA_INFO_IN_LEN; 2476 req.emr_out_buf = payload; 2477 req.emr_out_length = 2478 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2479 2480 MCDI_IN_SET_DWORD(req, GET_PHY_MEDIA_INFO_IN_PAGE, mcdi_page); 2481 2482 efx_mcdi_execute(enp, &req); 2483 2484 if (req.emr_rc != 0) { 2485 rc = req.emr_rc; 2486 goto fail1; 2487 } 2488 2489 if (req.emr_out_length_used != 2490 MC_CMD_GET_PHY_MEDIA_INFO_OUT_LEN(EFX_PHY_MEDIA_INFO_PAGE_SIZE)) { 2491 rc = EMSGSIZE; 2492 goto fail2; 2493 } 2494 2495 if (MCDI_OUT_DWORD(req, GET_PHY_MEDIA_INFO_OUT_DATALEN) != 2496 EFX_PHY_MEDIA_INFO_PAGE_SIZE) { 2497 rc = EIO; 2498 goto fail3; 2499 } 2500 2501 memcpy(data, 2502 MCDI_OUT2(req, uint8_t, GET_PHY_MEDIA_INFO_OUT_DATA) + offset, 2503 len); 2504 2505 return (0); 2506 2507 fail3: 2508 EFSYS_PROBE(fail3); 2509 fail2: 2510 EFSYS_PROBE(fail2); 2511 fail1: 2512 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2513 2514 return (rc); 2515 } 2516 2517 __checkReturn efx_rc_t 2518 efx_mcdi_phy_module_get_info( 2519 __in efx_nic_t *enp, 2520 __in uint8_t dev_addr, 2521 __in size_t offset, 2522 __in size_t len, 2523 __out_bcount(len) uint8_t *data) 2524 { 2525 efx_port_t *epp = &(enp->en_port); 2526 efx_rc_t rc; 2527 uint32_t mcdi_lower_page; 2528 uint32_t mcdi_upper_page; 2529 uint8_t id; 2530 2531 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 2532 2533 /* 2534 * Map device address to MC_CMD_GET_PHY_MEDIA_INFO pages. 2535 * Offset plus length interface allows to access page 0 only. 2536 * I.e. non-zero upper pages are not accessible. 2537 * See SFF-8472 section 4 Memory Organization and SFF-8436 section 7.6 2538 * QSFP+ Memory Map for details on how information is structured 2539 * and accessible. 2540 */ 2541 switch (epp->ep_fixed_port_type) { 2542 case EFX_PHY_MEDIA_SFP_PLUS: 2543 case EFX_PHY_MEDIA_QSFP_PLUS: 2544 /* Port type supports modules */ 2545 break; 2546 default: 2547 rc = ENOTSUP; 2548 goto fail1; 2549 } 2550 2551 /* 2552 * For all supported port types, MCDI page 0 offset 0 holds the 2553 * transceiver identifier. Probe to determine the data layout. 2554 * Definitions from SFF-8024 Table 4-1. 2555 */ 2556 rc = efx_mcdi_get_phy_media_info(enp, 2557 0, 0, sizeof(id), &id); 2558 if (rc != 0) 2559 goto fail2; 2560 2561 switch (id) { 2562 case EFX_SFF_TRANSCEIVER_ID_SFP: 2563 /* 2564 * In accordance with SFF-8472 Diagnostic Monitoring 2565 * Interface for Optical Transceivers section 4 Memory 2566 * Organization two 2-wire addresses are defined. 2567 */ 2568 switch (dev_addr) { 2569 /* Base information */ 2570 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_BASE: 2571 /* 2572 * MCDI page 0 should be used to access lower 2573 * page 0 (0x00 - 0x7f) at the device address 0xA0. 2574 */ 2575 mcdi_lower_page = 0; 2576 /* 2577 * MCDI page 1 should be used to access upper 2578 * page 0 (0x80 - 0xff) at the device address 0xA0. 2579 */ 2580 mcdi_upper_page = 1; 2581 break; 2582 /* Diagnostics */ 2583 case EFX_PHY_MEDIA_INFO_DEV_ADDR_SFP_DDM: 2584 /* 2585 * MCDI page 2 should be used to access lower 2586 * page 0 (0x00 - 0x7f) at the device address 0xA2. 2587 */ 2588 mcdi_lower_page = 2; 2589 /* 2590 * MCDI page 3 should be used to access upper 2591 * page 0 (0x80 - 0xff) at the device address 0xA2. 2592 */ 2593 mcdi_upper_page = 3; 2594 break; 2595 default: 2596 rc = ENOTSUP; 2597 goto fail3; 2598 } 2599 break; 2600 case EFX_SFF_TRANSCEIVER_ID_QSFP: 2601 case EFX_SFF_TRANSCEIVER_ID_QSFP_PLUS: 2602 case EFX_SFF_TRANSCEIVER_ID_QSFP28: 2603 switch (dev_addr) { 2604 case EFX_PHY_MEDIA_INFO_DEV_ADDR_QSFP: 2605 /* 2606 * MCDI page -1 should be used to access lower page 0 2607 * (0x00 - 0x7f). 2608 */ 2609 mcdi_lower_page = (uint32_t)-1; 2610 /* 2611 * MCDI page 0 should be used to access upper page 0 2612 * (0x80h - 0xff). 2613 */ 2614 mcdi_upper_page = 0; 2615 break; 2616 default: 2617 rc = ENOTSUP; 2618 goto fail3; 2619 } 2620 break; 2621 default: 2622 rc = ENOTSUP; 2623 goto fail3; 2624 } 2625 2626 EFX_STATIC_ASSERT(EFX_PHY_MEDIA_INFO_PAGE_SIZE <= 0xFF); 2627 2628 if (offset < EFX_PHY_MEDIA_INFO_PAGE_SIZE) { 2629 size_t read_len = 2630 MIN(len, EFX_PHY_MEDIA_INFO_PAGE_SIZE - offset); 2631 2632 rc = efx_mcdi_get_phy_media_info(enp, 2633 mcdi_lower_page, (uint8_t)offset, (uint8_t)read_len, data); 2634 if (rc != 0) 2635 goto fail4; 2636 2637 data += read_len; 2638 len -= read_len; 2639 2640 offset = 0; 2641 } else { 2642 offset -= EFX_PHY_MEDIA_INFO_PAGE_SIZE; 2643 } 2644 2645 if (len > 0) { 2646 EFSYS_ASSERT3U(len, <=, EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2647 EFSYS_ASSERT3U(offset, <, EFX_PHY_MEDIA_INFO_PAGE_SIZE); 2648 2649 rc = efx_mcdi_get_phy_media_info(enp, 2650 mcdi_upper_page, (uint8_t)offset, (uint8_t)len, data); 2651 if (rc != 0) 2652 goto fail5; 2653 } 2654 2655 return (0); 2656 2657 fail5: 2658 EFSYS_PROBE(fail5); 2659 fail4: 2660 EFSYS_PROBE(fail4); 2661 fail3: 2662 EFSYS_PROBE(fail3); 2663 fail2: 2664 EFSYS_PROBE(fail2); 2665 fail1: 2666 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2667 2668 return (rc); 2669 } 2670 2671 #if EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() 2672 2673 #define INIT_EVQ_MAXNBUFS MC_CMD_INIT_EVQ_V2_IN_DMA_ADDR_MAXNUM 2674 2675 #if EFX_OPTS_EF10() 2676 # if (INIT_EVQ_MAXNBUFS < EF10_EVQ_MAXNBUFS) 2677 # error "INIT_EVQ_MAXNBUFS too small" 2678 # endif 2679 #endif /* EFX_OPTS_EF10 */ 2680 #if EFSYS_OPT_RIVERHEAD 2681 # if (INIT_EVQ_MAXNBUFS < RHEAD_EVQ_MAXNBUFS) 2682 # error "INIT_EVQ_MAXNBUFS too small" 2683 # endif 2684 #endif /* EFSYS_OPT_RIVERHEAD */ 2685 2686 __checkReturn efx_rc_t 2687 efx_mcdi_init_evq( 2688 __in efx_nic_t *enp, 2689 __in unsigned int instance, 2690 __in efsys_mem_t *esmp, 2691 __in size_t nevs, 2692 __in uint32_t irq, 2693 __in uint32_t target_evq, 2694 __in uint32_t us, 2695 __in uint32_t flags, 2696 __in boolean_t low_latency) 2697 { 2698 const efx_nic_cfg_t *encp = efx_nic_cfg_get(enp); 2699 efx_mcdi_req_t req; 2700 EFX_MCDI_DECLARE_BUF(payload, 2701 MC_CMD_INIT_EVQ_V2_IN_LEN(INIT_EVQ_MAXNBUFS), 2702 MC_CMD_INIT_EVQ_V2_OUT_LEN); 2703 boolean_t interrupting; 2704 int ev_extended_width; 2705 int ev_cut_through; 2706 int ev_merge; 2707 unsigned int evq_type; 2708 efx_qword_t *dma_addr; 2709 uint64_t addr; 2710 int npages; 2711 int i; 2712 efx_rc_t rc; 2713 2714 npages = efx_evq_nbufs(enp, nevs, flags); 2715 if (npages > INIT_EVQ_MAXNBUFS) { 2716 rc = EINVAL; 2717 goto fail1; 2718 } 2719 2720 req.emr_cmd = MC_CMD_INIT_EVQ; 2721 req.emr_in_buf = payload; 2722 req.emr_in_length = MC_CMD_INIT_EVQ_V2_IN_LEN(npages); 2723 req.emr_out_buf = payload; 2724 req.emr_out_length = MC_CMD_INIT_EVQ_V2_OUT_LEN; 2725 2726 MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_SIZE, nevs); 2727 MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_INSTANCE, instance); 2728 2729 interrupting = ((flags & EFX_EVQ_FLAGS_NOTIFY_MASK) == 2730 EFX_EVQ_FLAGS_NOTIFY_INTERRUPT); 2731 2732 if (interrupting) 2733 MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_IRQ_NUM, irq); 2734 else 2735 MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TARGET_EVQ, target_evq); 2736 2737 if (encp->enc_init_evq_v2_supported) { 2738 /* 2739 * On Medford the low latency license is required to enable RX 2740 * and event cut through and to disable RX batching. If event 2741 * queue type in flags is auto, we let the firmware decide the 2742 * settings to use. If the adapter has a low latency license, 2743 * it will choose the best settings for low latency, otherwise 2744 * it will choose the best settings for throughput. 2745 */ 2746 switch (flags & EFX_EVQ_FLAGS_TYPE_MASK) { 2747 case EFX_EVQ_FLAGS_TYPE_AUTO: 2748 evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_AUTO; 2749 break; 2750 case EFX_EVQ_FLAGS_TYPE_THROUGHPUT: 2751 evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_THROUGHPUT; 2752 break; 2753 case EFX_EVQ_FLAGS_TYPE_LOW_LATENCY: 2754 evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_LOW_LATENCY; 2755 break; 2756 default: 2757 rc = EINVAL; 2758 goto fail2; 2759 } 2760 /* EvQ type controls merging, no manual settings */ 2761 ev_merge = 0; 2762 ev_cut_through = 0; 2763 } else { 2764 /* EvQ types other than manual are not supported */ 2765 evq_type = MC_CMD_INIT_EVQ_V2_IN_FLAG_TYPE_MANUAL; 2766 /* 2767 * On Huntington RX and TX event batching can only be requested 2768 * together (even if the datapath firmware doesn't actually 2769 * support RX batching). If event cut through is enabled no RX 2770 * batching will occur. 2771 * 2772 * So always enable RX and TX event batching, and enable event 2773 * cut through if we want low latency operation. 2774 */ 2775 ev_merge = 1; 2776 switch (flags & EFX_EVQ_FLAGS_TYPE_MASK) { 2777 case EFX_EVQ_FLAGS_TYPE_AUTO: 2778 ev_cut_through = low_latency ? 1 : 0; 2779 break; 2780 case EFX_EVQ_FLAGS_TYPE_THROUGHPUT: 2781 ev_cut_through = 0; 2782 break; 2783 case EFX_EVQ_FLAGS_TYPE_LOW_LATENCY: 2784 ev_cut_through = 1; 2785 break; 2786 default: 2787 rc = EINVAL; 2788 goto fail2; 2789 } 2790 } 2791 2792 /* 2793 * On EF100, extended width event queues have a different event 2794 * descriptor layout and are used to support descriptor proxy queues. 2795 */ 2796 ev_extended_width = 0; 2797 #if EFSYS_OPT_EV_EXTENDED_WIDTH 2798 if (encp->enc_init_evq_extended_width_supported) { 2799 if (flags & EFX_EVQ_FLAGS_EXTENDED_WIDTH) 2800 ev_extended_width = 1; 2801 } 2802 #endif 2803 2804 MCDI_IN_POPULATE_DWORD_8(req, INIT_EVQ_V2_IN_FLAGS, 2805 INIT_EVQ_V2_IN_FLAG_INTERRUPTING, interrupting, 2806 INIT_EVQ_V2_IN_FLAG_RPTR_DOS, 0, 2807 INIT_EVQ_V2_IN_FLAG_INT_ARMD, 0, 2808 INIT_EVQ_V2_IN_FLAG_CUT_THRU, ev_cut_through, 2809 INIT_EVQ_V2_IN_FLAG_RX_MERGE, ev_merge, 2810 INIT_EVQ_V2_IN_FLAG_TX_MERGE, ev_merge, 2811 INIT_EVQ_V2_IN_FLAG_TYPE, evq_type, 2812 INIT_EVQ_V2_IN_FLAG_EXT_WIDTH, ev_extended_width); 2813 2814 /* If the value is zero then disable the timer */ 2815 if (us == 0) { 2816 MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_MODE, 2817 MC_CMD_INIT_EVQ_V2_IN_TMR_MODE_DIS); 2818 MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_LOAD, 0); 2819 MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_RELOAD, 0); 2820 } else { 2821 unsigned int ticks; 2822 2823 if ((rc = efx_ev_usecs_to_ticks(enp, us, &ticks)) != 0) 2824 goto fail3; 2825 2826 MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_MODE, 2827 MC_CMD_INIT_EVQ_V2_IN_TMR_INT_HLDOFF); 2828 MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_LOAD, ticks); 2829 MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_TMR_RELOAD, ticks); 2830 } 2831 2832 MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_COUNT_MODE, 2833 MC_CMD_INIT_EVQ_V2_IN_COUNT_MODE_DIS); 2834 MCDI_IN_SET_DWORD(req, INIT_EVQ_V2_IN_COUNT_THRSHLD, 0); 2835 2836 dma_addr = MCDI_IN2(req, efx_qword_t, INIT_EVQ_V2_IN_DMA_ADDR); 2837 addr = EFSYS_MEM_ADDR(esmp); 2838 2839 for (i = 0; i < npages; i++) { 2840 EFX_POPULATE_QWORD_2(*dma_addr, 2841 EFX_DWORD_1, (uint32_t)(addr >> 32), 2842 EFX_DWORD_0, (uint32_t)(addr & 0xffffffff)); 2843 2844 dma_addr++; 2845 addr += EFX_BUF_SIZE; 2846 } 2847 2848 efx_mcdi_execute(enp, &req); 2849 2850 if (req.emr_rc != 0) { 2851 rc = req.emr_rc; 2852 goto fail4; 2853 } 2854 2855 if (encp->enc_init_evq_v2_supported) { 2856 if (req.emr_out_length_used < MC_CMD_INIT_EVQ_V2_OUT_LEN) { 2857 rc = EMSGSIZE; 2858 goto fail5; 2859 } 2860 EFSYS_PROBE1(mcdi_evq_flags, uint32_t, 2861 MCDI_OUT_DWORD(req, INIT_EVQ_V2_OUT_FLAGS)); 2862 } else { 2863 if (req.emr_out_length_used < MC_CMD_INIT_EVQ_OUT_LEN) { 2864 rc = EMSGSIZE; 2865 goto fail6; 2866 } 2867 } 2868 2869 /* NOTE: ignore the returned IRQ param as firmware does not set it. */ 2870 2871 return (0); 2872 2873 fail6: 2874 EFSYS_PROBE(fail6); 2875 fail5: 2876 EFSYS_PROBE(fail5); 2877 fail4: 2878 EFSYS_PROBE(fail4); 2879 fail3: 2880 EFSYS_PROBE(fail3); 2881 fail2: 2882 EFSYS_PROBE(fail2); 2883 fail1: 2884 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2885 2886 return (rc); 2887 } 2888 2889 __checkReturn efx_rc_t 2890 efx_mcdi_fini_evq( 2891 __in efx_nic_t *enp, 2892 __in uint32_t instance) 2893 { 2894 efx_mcdi_req_t req; 2895 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_EVQ_IN_LEN, 2896 MC_CMD_FINI_EVQ_OUT_LEN); 2897 efx_rc_t rc; 2898 2899 req.emr_cmd = MC_CMD_FINI_EVQ; 2900 req.emr_in_buf = payload; 2901 req.emr_in_length = MC_CMD_FINI_EVQ_IN_LEN; 2902 req.emr_out_buf = payload; 2903 req.emr_out_length = MC_CMD_FINI_EVQ_OUT_LEN; 2904 2905 MCDI_IN_SET_DWORD(req, FINI_EVQ_IN_INSTANCE, instance); 2906 2907 efx_mcdi_execute_quiet(enp, &req); 2908 2909 if (req.emr_rc != 0) { 2910 rc = req.emr_rc; 2911 goto fail1; 2912 } 2913 2914 return (0); 2915 2916 fail1: 2917 /* 2918 * EALREADY is not an error, but indicates that the MC has rebooted and 2919 * that the EVQ has already been destroyed. 2920 */ 2921 if (rc != EALREADY) 2922 EFSYS_PROBE1(fail1, efx_rc_t, rc); 2923 2924 return (rc); 2925 } 2926 2927 __checkReturn efx_rc_t 2928 efx_mcdi_init_rxq( 2929 __in efx_nic_t *enp, 2930 __in uint32_t ndescs, 2931 __in efx_evq_t *eep, 2932 __in uint32_t label, 2933 __in uint32_t instance, 2934 __in efsys_mem_t *esmp, 2935 __in const efx_mcdi_init_rxq_params_t *params) 2936 { 2937 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 2938 efx_mcdi_req_t req; 2939 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_INIT_RXQ_V5_IN_LEN, 2940 MC_CMD_INIT_RXQ_V5_OUT_LEN); 2941 int npages = efx_rxq_nbufs(enp, ndescs); 2942 int i; 2943 efx_qword_t *dma_addr; 2944 uint64_t addr; 2945 efx_rc_t rc; 2946 uint32_t dma_mode; 2947 boolean_t want_outer_classes; 2948 boolean_t no_cont_ev; 2949 2950 EFSYS_ASSERT3U(ndescs, <=, encp->enc_rxq_max_ndescs); 2951 2952 if ((esmp == NULL) || 2953 (EFSYS_MEM_SIZE(esmp) < efx_rxq_size(enp, ndescs))) { 2954 rc = EINVAL; 2955 goto fail1; 2956 } 2957 2958 no_cont_ev = (eep->ee_flags & EFX_EVQ_FLAGS_NO_CONT_EV); 2959 if ((no_cont_ev == B_TRUE) && (params->disable_scatter == B_FALSE)) { 2960 /* TODO: Support scatter in NO_CONT_EV mode */ 2961 rc = EINVAL; 2962 goto fail2; 2963 } 2964 2965 if (params->ps_buf_size > 0) 2966 dma_mode = MC_CMD_INIT_RXQ_EXT_IN_PACKED_STREAM; 2967 else if (params->es_bufs_per_desc > 0) 2968 dma_mode = MC_CMD_INIT_RXQ_V3_IN_EQUAL_STRIDE_SUPER_BUFFER; 2969 else 2970 dma_mode = MC_CMD_INIT_RXQ_EXT_IN_SINGLE_PACKET; 2971 2972 if (encp->enc_tunnel_encapsulations_supported != 0 && 2973 !params->want_inner_classes) { 2974 /* 2975 * WANT_OUTER_CLASSES can only be specified on hardware which 2976 * supports tunnel encapsulation offloads, even though it is 2977 * effectively the behaviour the hardware gives. 2978 * 2979 * Also, on hardware which does support such offloads, older 2980 * firmware rejects the flag if the offloads are not supported 2981 * by the current firmware variant, which means this may fail if 2982 * the capabilities are not updated when the firmware variant 2983 * changes. This is not an issue on newer firmware, as it was 2984 * changed in bug 69842 (v6.4.2.1007) to permit this flag to be 2985 * specified on all firmware variants. 2986 */ 2987 want_outer_classes = B_TRUE; 2988 } else { 2989 want_outer_classes = B_FALSE; 2990 } 2991 2992 req.emr_cmd = MC_CMD_INIT_RXQ; 2993 req.emr_in_buf = payload; 2994 req.emr_in_length = MC_CMD_INIT_RXQ_V5_IN_LEN; 2995 req.emr_out_buf = payload; 2996 req.emr_out_length = MC_CMD_INIT_RXQ_V5_OUT_LEN; 2997 2998 MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_SIZE, ndescs); 2999 MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_TARGET_EVQ, eep->ee_index); 3000 MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_LABEL, label); 3001 MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_INSTANCE, instance); 3002 MCDI_IN_POPULATE_DWORD_10(req, INIT_RXQ_EXT_IN_FLAGS, 3003 INIT_RXQ_EXT_IN_FLAG_BUFF_MODE, 0, 3004 INIT_RXQ_EXT_IN_FLAG_HDR_SPLIT, 0, 3005 INIT_RXQ_EXT_IN_FLAG_TIMESTAMP, 0, 3006 INIT_RXQ_EXT_IN_CRC_MODE, 0, 3007 INIT_RXQ_EXT_IN_FLAG_PREFIX, 1, 3008 INIT_RXQ_EXT_IN_FLAG_DISABLE_SCATTER, params->disable_scatter, 3009 INIT_RXQ_EXT_IN_DMA_MODE, 3010 dma_mode, 3011 INIT_RXQ_EXT_IN_PACKED_STREAM_BUFF_SIZE, params->ps_buf_size, 3012 INIT_RXQ_EXT_IN_FLAG_WANT_OUTER_CLASSES, want_outer_classes, 3013 INIT_RXQ_EXT_IN_FLAG_NO_CONT_EV, no_cont_ev); 3014 MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_OWNER_ID, 0); 3015 MCDI_IN_SET_DWORD(req, INIT_RXQ_EXT_IN_PORT_ID, enp->en_vport_id); 3016 3017 if (params->es_bufs_per_desc > 0) { 3018 MCDI_IN_SET_DWORD(req, 3019 INIT_RXQ_V3_IN_ES_PACKET_BUFFERS_PER_BUCKET, 3020 params->es_bufs_per_desc); 3021 MCDI_IN_SET_DWORD(req, 3022 INIT_RXQ_V3_IN_ES_MAX_DMA_LEN, params->es_max_dma_len); 3023 MCDI_IN_SET_DWORD(req, 3024 INIT_RXQ_V3_IN_ES_PACKET_STRIDE, params->es_buf_stride); 3025 MCDI_IN_SET_DWORD(req, 3026 INIT_RXQ_V3_IN_ES_HEAD_OF_LINE_BLOCK_TIMEOUT, 3027 params->hol_block_timeout); 3028 } 3029 3030 if (encp->enc_init_rxq_with_buffer_size) 3031 MCDI_IN_SET_DWORD(req, INIT_RXQ_V4_IN_BUFFER_SIZE_BYTES, 3032 params->buf_size); 3033 3034 MCDI_IN_SET_DWORD(req, INIT_RXQ_V5_IN_RX_PREFIX_ID, params->prefix_id); 3035 3036 dma_addr = MCDI_IN2(req, efx_qword_t, INIT_RXQ_IN_DMA_ADDR); 3037 addr = EFSYS_MEM_ADDR(esmp); 3038 3039 for (i = 0; i < npages; i++) { 3040 EFX_POPULATE_QWORD_2(*dma_addr, 3041 EFX_DWORD_1, (uint32_t)(addr >> 32), 3042 EFX_DWORD_0, (uint32_t)(addr & 0xffffffff)); 3043 3044 dma_addr++; 3045 addr += EFX_BUF_SIZE; 3046 } 3047 3048 efx_mcdi_execute(enp, &req); 3049 3050 if (req.emr_rc != 0) { 3051 rc = req.emr_rc; 3052 goto fail3; 3053 } 3054 3055 return (0); 3056 3057 fail3: 3058 EFSYS_PROBE(fail3); 3059 fail2: 3060 EFSYS_PROBE(fail2); 3061 fail1: 3062 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3063 3064 return (rc); 3065 } 3066 3067 __checkReturn efx_rc_t 3068 efx_mcdi_fini_rxq( 3069 __in efx_nic_t *enp, 3070 __in uint32_t instance) 3071 { 3072 efx_mcdi_req_t req; 3073 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_RXQ_IN_LEN, 3074 MC_CMD_FINI_RXQ_OUT_LEN); 3075 efx_rc_t rc; 3076 3077 req.emr_cmd = MC_CMD_FINI_RXQ; 3078 req.emr_in_buf = payload; 3079 req.emr_in_length = MC_CMD_FINI_RXQ_IN_LEN; 3080 req.emr_out_buf = payload; 3081 req.emr_out_length = MC_CMD_FINI_RXQ_OUT_LEN; 3082 3083 MCDI_IN_SET_DWORD(req, FINI_RXQ_IN_INSTANCE, instance); 3084 3085 efx_mcdi_execute_quiet(enp, &req); 3086 3087 if (req.emr_rc != 0) { 3088 rc = req.emr_rc; 3089 goto fail1; 3090 } 3091 3092 return (0); 3093 3094 fail1: 3095 /* 3096 * EALREADY is not an error, but indicates that the MC has rebooted and 3097 * that the RXQ has already been destroyed. 3098 */ 3099 if (rc != EALREADY) 3100 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3101 3102 return (rc); 3103 } 3104 3105 __checkReturn efx_rc_t 3106 efx_mcdi_init_txq( 3107 __in efx_nic_t *enp, 3108 __in uint32_t ndescs, 3109 __in uint32_t target_evq, 3110 __in uint32_t label, 3111 __in uint32_t instance, 3112 __in uint16_t flags, 3113 __in efsys_mem_t *esmp) 3114 { 3115 efx_mcdi_req_t req; 3116 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_INIT_TXQ_EXT_IN_LEN, 3117 MC_CMD_INIT_TXQ_OUT_LEN); 3118 efx_qword_t *dma_addr; 3119 uint64_t addr; 3120 int npages; 3121 int i; 3122 efx_rc_t rc; 3123 3124 EFSYS_ASSERT(MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_MAXNUM >= 3125 efx_txq_nbufs(enp, enp->en_nic_cfg.enc_txq_max_ndescs)); 3126 3127 if ((esmp == NULL) || 3128 (EFSYS_MEM_SIZE(esmp) < efx_txq_size(enp, ndescs))) { 3129 rc = EINVAL; 3130 goto fail1; 3131 } 3132 3133 npages = efx_txq_nbufs(enp, ndescs); 3134 if (MC_CMD_INIT_TXQ_IN_LEN(npages) > sizeof (payload)) { 3135 rc = EINVAL; 3136 goto fail2; 3137 } 3138 3139 req.emr_cmd = MC_CMD_INIT_TXQ; 3140 req.emr_in_buf = payload; 3141 req.emr_in_length = MC_CMD_INIT_TXQ_IN_LEN(npages); 3142 req.emr_out_buf = payload; 3143 req.emr_out_length = MC_CMD_INIT_TXQ_OUT_LEN; 3144 3145 MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_SIZE, ndescs); 3146 MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_TARGET_EVQ, target_evq); 3147 MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_LABEL, label); 3148 MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_INSTANCE, instance); 3149 3150 MCDI_IN_POPULATE_DWORD_9(req, INIT_TXQ_IN_FLAGS, 3151 INIT_TXQ_IN_FLAG_BUFF_MODE, 0, 3152 INIT_TXQ_IN_FLAG_IP_CSUM_DIS, 3153 (flags & EFX_TXQ_CKSUM_IPV4) ? 0 : 1, 3154 INIT_TXQ_IN_FLAG_TCP_CSUM_DIS, 3155 (flags & EFX_TXQ_CKSUM_TCPUDP) ? 0 : 1, 3156 INIT_TXQ_EXT_IN_FLAG_INNER_IP_CSUM_EN, 3157 (flags & EFX_TXQ_CKSUM_INNER_IPV4) ? 1 : 0, 3158 INIT_TXQ_EXT_IN_FLAG_INNER_TCP_CSUM_EN, 3159 (flags & EFX_TXQ_CKSUM_INNER_TCPUDP) ? 1 : 0, 3160 INIT_TXQ_EXT_IN_FLAG_TSOV2_EN, (flags & EFX_TXQ_FATSOV2) ? 1 : 0, 3161 INIT_TXQ_IN_FLAG_TCP_UDP_ONLY, 0, 3162 INIT_TXQ_IN_CRC_MODE, 0, 3163 INIT_TXQ_IN_FLAG_TIMESTAMP, 0); 3164 3165 MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_OWNER_ID, 0); 3166 MCDI_IN_SET_DWORD(req, INIT_TXQ_IN_PORT_ID, enp->en_vport_id); 3167 3168 dma_addr = MCDI_IN2(req, efx_qword_t, INIT_TXQ_IN_DMA_ADDR); 3169 addr = EFSYS_MEM_ADDR(esmp); 3170 3171 for (i = 0; i < npages; i++) { 3172 EFX_POPULATE_QWORD_2(*dma_addr, 3173 EFX_DWORD_1, (uint32_t)(addr >> 32), 3174 EFX_DWORD_0, (uint32_t)(addr & 0xffffffff)); 3175 3176 dma_addr++; 3177 addr += EFX_BUF_SIZE; 3178 } 3179 3180 efx_mcdi_execute(enp, &req); 3181 3182 if (req.emr_rc != 0) { 3183 rc = req.emr_rc; 3184 goto fail3; 3185 } 3186 3187 return (0); 3188 3189 fail3: 3190 EFSYS_PROBE(fail3); 3191 fail2: 3192 EFSYS_PROBE(fail2); 3193 fail1: 3194 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3195 3196 return (rc); 3197 } 3198 3199 __checkReturn efx_rc_t 3200 efx_mcdi_fini_txq( 3201 __in efx_nic_t *enp, 3202 __in uint32_t instance) 3203 { 3204 efx_mcdi_req_t req; 3205 EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FINI_TXQ_IN_LEN, 3206 MC_CMD_FINI_TXQ_OUT_LEN); 3207 efx_rc_t rc; 3208 3209 req.emr_cmd = MC_CMD_FINI_TXQ; 3210 req.emr_in_buf = payload; 3211 req.emr_in_length = MC_CMD_FINI_TXQ_IN_LEN; 3212 req.emr_out_buf = payload; 3213 req.emr_out_length = MC_CMD_FINI_TXQ_OUT_LEN; 3214 3215 MCDI_IN_SET_DWORD(req, FINI_TXQ_IN_INSTANCE, instance); 3216 3217 efx_mcdi_execute_quiet(enp, &req); 3218 3219 if (req.emr_rc != 0) { 3220 rc = req.emr_rc; 3221 goto fail1; 3222 } 3223 3224 return (0); 3225 3226 fail1: 3227 /* 3228 * EALREADY is not an error, but indicates that the MC has rebooted and 3229 * that the TXQ has already been destroyed. 3230 */ 3231 if (rc != EALREADY) 3232 EFSYS_PROBE1(fail1, efx_rc_t, rc); 3233 3234 return (rc); 3235 } 3236 3237 #endif /* EFSYS_OPT_RIVERHEAD || EFX_OPTS_EF10() */ 3238 3239 #endif /* EFSYS_OPT_MCDI */ 3240