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