1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2024 Oxide Computer Company 14 */ 15 16 /* 17 * This file contains everything having to do with communicating with 18 * the admin queue for sending commands to the device. 19 */ 20 21 #include "ena_hw.h" 22 #include "ena.h" 23 24 /* 25 * Mark the context as complete (a response has been received). 26 */ 27 static void 28 ena_complete_cmd_ctx(ena_cmd_ctx_t *ctx, enahw_resp_desc_t *hwresp) 29 { 30 bcopy(hwresp, ctx->ectx_resp, sizeof (*hwresp)); 31 ctx->ectx_pending = false; 32 } 33 34 static inline void 35 ena_reset_cmd_ctx(ena_cmd_ctx_t *ctx) 36 { 37 ctx->ectx_pending = false; 38 ctx->ectx_resp = NULL; 39 ctx->ectx_cmd_opcode = ENAHW_CMD_NONE; 40 } 41 42 /* 43 * Reset and release the context back to the free list. 44 */ 45 static void 46 ena_release_cmd_ctx(ena_t *ena, ena_cmd_ctx_t *ctx) 47 { 48 ASSERT(ctx->ectx_pending == false); 49 ena_reset_cmd_ctx(ctx); 50 51 mutex_enter(&ena->ena_aq.ea_sq_lock); 52 /* 53 * We return the free descriptor to the end of the list so that we 54 * cycle through them with each admin command, and don't end up almost 55 * always re-using the same entry with the same command ID. While the 56 * controller does not appear to mind, it's a little counter-intuitive. 57 */ 58 list_remove(&ena->ena_aq.ea_cmd_ctxs_used, ctx); 59 list_insert_tail(&ena->ena_aq.ea_cmd_ctxs_free, ctx); 60 ena->ena_aq.ea_pending_cmds--; 61 mutex_exit(&ena->ena_aq.ea_sq_lock); 62 } 63 64 void 65 ena_release_all_cmd_ctx(ena_t *ena) 66 { 67 ena_adminq_t *aq = &ena->ena_aq; 68 ena_cmd_ctx_t *ctx; 69 70 mutex_enter(&aq->ea_sq_lock); 71 while ((ctx = list_remove_head(&aq->ea_cmd_ctxs_used)) != NULL) { 72 ena_reset_cmd_ctx(ctx); 73 list_insert_tail(&aq->ea_cmd_ctxs_free, ctx); 74 } 75 aq->ea_pending_cmds = 0; 76 mutex_exit(&aq->ea_sq_lock); 77 } 78 79 void 80 ena_create_cmd_ctx(ena_t *ena) 81 { 82 ena_adminq_t *aq = &ena->ena_aq; 83 84 for (uint_t i = 0; i < aq->ea_qlen; i++) { 85 ena_cmd_ctx_t *ctx = &aq->ea_cmd_ctxs[i]; 86 87 ctx->ectx_id = i; 88 ena_reset_cmd_ctx(ctx); 89 list_insert_tail(&aq->ea_cmd_ctxs_free, ctx); 90 } 91 } 92 93 /* 94 * Acquire the next available command context. 95 */ 96 static ena_cmd_ctx_t * 97 ena_acquire_cmd_ctx(ena_adminq_t *aq) 98 { 99 VERIFY(MUTEX_HELD(&aq->ea_sq_lock)); 100 ASSERT3U(aq->ea_pending_cmds, <, aq->ea_qlen); 101 ena_cmd_ctx_t *ctx = list_remove_head(&aq->ea_cmd_ctxs_free); 102 list_insert_head(&aq->ea_cmd_ctxs_used, ctx); 103 104 ctx->ectx_pending = true; 105 return (ctx); 106 } 107 108 /* 109 * Submit a command to the admin queue. 110 */ 111 int 112 ena_admin_submit_cmd(ena_t *ena, enahw_cmd_desc_t *cmd, enahw_resp_desc_t *resp, 113 ena_cmd_ctx_t **ctx) 114 { 115 VERIFY3U(cmd->ecd_opcode, !=, 0); 116 ena_adminq_t *aq = &ena->ena_aq; 117 ena_admin_sq_t *sq = &aq->ea_sq; 118 const uint16_t modulo_mask = aq->ea_qlen - 1; 119 ena_cmd_ctx_t *lctx = NULL; 120 121 mutex_enter(&aq->ea_sq_lock); 122 uint16_t tail_mod = sq->eas_tail & modulo_mask; 123 124 if (aq->ea_pending_cmds >= aq->ea_qlen) { 125 mutex_enter(&aq->ea_stat_lock); 126 aq->ea_stats.queue_full++; 127 mutex_exit(&aq->ea_stat_lock); 128 mutex_exit(&aq->ea_sq_lock); 129 return (ENOSPC); 130 } 131 132 lctx = ena_acquire_cmd_ctx(aq); 133 lctx->ectx_cmd_opcode = cmd->ecd_opcode; 134 lctx->ectx_resp = resp; 135 136 cmd->ecd_flags = sq->eas_phase & ENAHW_CMD_PHASE_MASK; 137 ENAHW_CMD_ID(cmd, lctx->ectx_id); 138 bcopy(cmd, &sq->eas_entries[tail_mod], sizeof (*cmd)); 139 ENA_DMA_SYNC(sq->eas_dma, DDI_DMA_SYNC_FORDEV); 140 141 sq->eas_tail++; 142 aq->ea_pending_cmds++; 143 144 mutex_enter(&aq->ea_stat_lock); 145 aq->ea_stats.cmds_submitted++; 146 mutex_exit(&aq->ea_stat_lock); 147 148 DTRACE_PROBE4(cmd__submit, enahw_cmd_desc_t *, cmd, ena_cmd_ctx_t *, 149 lctx, uint16_t, tail_mod, uint8_t, sq->eas_phase); 150 151 if ((sq->eas_tail & modulo_mask) == 0) { 152 sq->eas_phase ^= 1; 153 } 154 155 ena_hw_abs_write32(ena, sq->eas_dbaddr, sq->eas_tail); 156 mutex_exit(&aq->ea_sq_lock); 157 *ctx = lctx; 158 return (0); 159 } 160 161 /* 162 * Read a single response from the admin queue. 163 */ 164 static void 165 ena_admin_read_resp(ena_t *ena, enahw_resp_desc_t *hwresp) 166 { 167 ena_adminq_t *aq = &ena->ena_aq; 168 ena_admin_cq_t *cq = &aq->ea_cq; 169 ena_cmd_ctx_t *ctx = NULL; 170 uint16_t modulo_mask = aq->ea_qlen - 1; 171 172 VERIFY(MUTEX_HELD(&aq->ea_cq_lock)); 173 174 uint16_t head_mod = cq->eac_head & modulo_mask; 175 uint8_t phase = cq->eac_phase & ENAHW_RESP_PHASE_MASK; 176 uint16_t cmd_id = ENAHW_RESP_CMD_ID(hwresp); 177 178 ctx = &aq->ea_cmd_ctxs[cmd_id]; 179 180 ASSERT3U(ctx->ectx_id, ==, cmd_id); 181 ena_complete_cmd_ctx(ctx, hwresp); 182 183 if (hwresp->erd_status != ENAHW_RESP_SUCCESS) { 184 mutex_enter(&aq->ea_stat_lock); 185 aq->ea_stats.cmds_fail++; 186 mutex_exit(&aq->ea_stat_lock); 187 DTRACE_PROBE4(cmd__fail, enahw_resp_desc_t *, hwresp, 188 ena_cmd_ctx_t *, ctx, uint16_t, head_mod, uint8_t, phase); 189 return; 190 } 191 192 DTRACE_PROBE4(cmd__success, enahw_resp_desc_t *, hwresp, 193 ena_cmd_ctx_t *, ctx, uint16_t, head_mod, uint8_t, phase); 194 mutex_enter(&aq->ea_stat_lock); 195 aq->ea_stats.cmds_success++; 196 mutex_exit(&aq->ea_stat_lock); 197 } 198 199 static void 200 ena_admin_process_responses(ena_t *ena) 201 { 202 ena_adminq_t *aq = &ena->ena_aq; 203 ena_admin_cq_t *cq = &aq->ea_cq; 204 uint16_t modulo_mask = aq->ea_qlen - 1; 205 enahw_resp_desc_t *hwresp; 206 207 mutex_enter(&aq->ea_cq_lock); 208 uint16_t head_mod = cq->eac_head & modulo_mask; 209 uint8_t phase = cq->eac_phase & ENAHW_RESP_PHASE_MASK; 210 211 ENA_DMA_SYNC(cq->eac_dma, DDI_DMA_SYNC_FORKERNEL); 212 hwresp = &cq->eac_entries[head_mod]; 213 while ((hwresp->erd_flags & ENAHW_RESP_PHASE_MASK) == phase) { 214 ena_admin_read_resp(ena, hwresp); 215 216 cq->eac_head++; 217 head_mod = cq->eac_head & modulo_mask; 218 219 if (head_mod == 0) { 220 phase ^= 1; 221 } 222 223 hwresp = &cq->eac_entries[head_mod]; 224 } 225 226 cq->eac_phase = phase; 227 mutex_exit(&aq->ea_cq_lock); 228 } 229 230 /* 231 * Wait for the command described by ctx to complete by polling for 232 * status updates. 233 */ 234 int 235 ena_admin_poll_for_resp(ena_t *ena, ena_cmd_ctx_t *ctx) 236 { 237 int ret = 0; 238 hrtime_t expire = gethrtime() + ena->ena_aq.ea_cmd_timeout_ns; 239 240 for (;;) { 241 ena_admin_process_responses(ena); 242 243 if (!ctx->ectx_pending) { 244 break; 245 } 246 247 /* Wait for 1 millisecond. */ 248 delay(drv_usectohz(1000)); 249 250 if (gethrtime() > expire) { 251 /* 252 * We have no visibility into the device to 253 * confirm it is making progress on this 254 * command. At this point the driver and 255 * device cannot agree on the state of the 256 * world: perhaps the device is still making 257 * progress but not fast enough, perhaps the 258 * device completed the command but there was 259 * a failure to deliver the reply, perhaps the 260 * command failed but once again the reply was 261 * not delivered. With this unknown state the 262 * best thing to do is to reset the device and 263 * start from scratch. There is even a reset 264 * reason code just for this. 265 */ 266 ena_err(ena, "timed out waiting for admin response"); 267 ena_trigger_reset(ena, ENAHW_RESET_ADMIN_TO); 268 return (EIO); 269 } 270 } 271 272 ret = enahw_resp_status_to_errno(ena, ctx->ectx_resp->erd_status); 273 ena_release_cmd_ctx(ena, ctx); 274 return (ret); 275 } 276 277 void 278 ena_free_host_info(ena_t *ena) 279 { 280 ena_dma_free(&ena->ena_host_info); 281 } 282 283 bool 284 ena_init_host_info(ena_t *ena) 285 { 286 enahw_host_info_t *ehi; 287 int ret = 0; 288 int *regs; 289 uint_t nregs; 290 ena_dma_buf_t *hi_dma; 291 enahw_cmd_desc_t cmd; 292 enahw_feat_host_attr_t *ha_cmd = 293 &cmd.ecd_cmd.ecd_set_feat.ecsf_feat.ecsf_host_attr; 294 enahw_resp_desc_t resp; 295 296 hi_dma = &ena->ena_host_info; 297 298 if (hi_dma->edb_va == NULL) { 299 ena_dma_conf_t conf = { 300 .edc_size = ENAHW_HOST_INFO_ALLOC_SZ, 301 .edc_align = ENAHW_HOST_INFO_ALIGNMENT, 302 .edc_sgl = 1, 303 .edc_endian = DDI_NEVERSWAP_ACC, 304 .edc_stream = false, 305 }; 306 307 if (!ena_dma_alloc(ena, hi_dma, &conf, 4096)) { 308 ena_err(ena, "failed to allocate DMA for host info"); 309 return (false); 310 } 311 } 312 313 ehi = (void *)hi_dma->edb_va; 314 ehi->ehi_ena_spec_version = 315 ((ENA_SPEC_VERSION_MAJOR << ENAHW_HOST_INFO_SPEC_MAJOR_SHIFT) | 316 (ENA_SPEC_VERSION_MINOR)); 317 318 ehi->ehi_bdf = 0; 319 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ena->ena_dip, 320 DDI_PROP_DONTPASS, "reg", ®s, &nregs) == DDI_PROP_SUCCESS) { 321 if (nregs != 0) { 322 ehi->ehi_bdf |= PCI_REG_BUS_G(regs[0]) << 8; 323 ehi->ehi_bdf |= PCI_REG_DEV_G(regs[0]) << 3; 324 ehi->ehi_bdf |= PCI_REG_FUNC_G(regs[0]); 325 } 326 327 ddi_prop_free(regs); 328 } 329 330 /* 331 * There is no illumos OS type, it would be nice to ping 332 * someone at Amazon and see if we can't get one added. 333 */ 334 ehi->ehi_os_type = ENAHW_OS_FREEBSD; 335 ehi->ehi_kernel_ver = 511; /* If you know you know */ 336 (void) strlcpy((char *)ehi->ehi_kernel_ver_str, utsname.version, 337 sizeof (ehi->ehi_kernel_ver_str)); 338 ehi->ehi_os_dist = 0; /* What everyone else does. */ 339 ehi->ehi_driver_ver = 340 (ENA_MODULE_VER_MAJOR) | 341 (ENA_MODULE_VER_MINOR << ENAHW_HOST_INFO_MINOR_SHIFT) | 342 (ENA_MODULE_VER_SUBMINOR << ENAHW_HOST_INFO_SUB_MINOR_SHIFT); 343 ehi->ehi_num_cpus = ncpus_online; 344 345 /* 346 * ENA devices are not created equal. Some will support 347 * features not found in others. This field tells the device 348 * which features the driver supports. 349 * 350 * ENAHW_HOST_INFO_RX_OFFSET 351 * 352 * Some ENA devices will write the frame data at an offset 353 * in the buffer, presumably for alignment purposes. We 354 * support this feature for the sole reason that the Linux 355 * driver does as well. 356 * 357 * ENAHW_HOST_INFO_INTERRUPT_MODERATION 358 * 359 * Based on the Linux history this flag indicates that the 360 * driver "supports interrupt moderation properly". What 361 * that means is anyone's guess. The Linux driver seems to 362 * have some "adaptive" interrupt moderation, so perhaps 363 * it's that? In any case, FreeBSD doesn't bother with 364 * setting this flag, so we'll leave it be for now as well. 365 * 366 * If you're curious to know if the device supports 367 * interrupt moderation: the FEAT_INTERRUPT_MODERATION flag 368 * will be set in ena_hw.eh_supported_features. 369 * 370 * ENAHW_HOST_INFO_RX_BUF_MIRRORING 371 * 372 * Support traffic mirroring by allowing the hypervisor to 373 * read the buffer memory directly. This probably has to do 374 * with AWS flow logs, allowing more efficient mirroring. 375 * But it's hard to say for sure given we only have the 376 * Linux commit log to go off of. In any case, the only 377 * requirement for this feature is that the Rx DMA buffers 378 * be read/write, which they are. 379 * 380 * ENAHW_HOST_INFO_RSS_CONFIGURABLE_FUNCTION_KEY 381 * 382 * The device supports the retrieving and updating of the 383 * RSS function and hash key. As we don't yet implement RSS 384 * this is disabled. 385 * 386 * ENA_ADMIN_HOST_INFO_RX_PAGE_REUSE 387 * 388 * Dynamic Rx Buffer feature. This feature allows the driver to 389 * avoid additional Rx buffer allocations by effectively using a 390 * buffer more than once if there is space remaining after receiving 391 * a packet. We currently use fixed TCBs and rings and don't 392 * implement this feature. 393 * 394 * ENA_ADMIN_HOST_INFO_TX_IPV6_CSUM_OFFLOAD 395 * 396 * Indicate that the driver supports Tx IPv6 checksum offload. 397 * 398 * ENA_ADMIN_HOST_INFO_PHC 399 * 400 * Instructs the device to enable its PHC (Precision Time Protocol 401 * Hardware Clock). In Linux, this would be exposed to userland NTP 402 * software as a PTP device. We don't support this so leave it 403 * disabled. 404 */ 405 ehi->ehi_driver_supported_features = 406 ENAHW_HOST_INFO_RX_OFFSET_MASK | 407 ENAHW_HOST_INFO_RX_BUF_MIRRORING_MASK; 408 409 ENA_DMA_SYNC(*hi_dma, DDI_DMA_SYNC_FORDEV); 410 bzero(&cmd, sizeof (cmd)); 411 ena_set_dma_addr(ena, hi_dma->edb_cookie->dmac_laddress, 412 &ha_cmd->efha_os_addr); 413 414 /* 415 * You might notice the "debug area" is not allocated or 416 * configured, that is on purpose. 417 * 418 * The "debug area" is a region of host memory that contains 419 * the String Set (SS) tables used to report statistics to 420 * tools like ethtool (on Linux). This table consists of one 421 * of more entries of a 32-byte string (the name of the 422 * statistic) along with its associated 64-bit value. The 423 * stats reported here contain both the host-side stats as 424 * well as device-reported stats (ENAHW_GET_STATS_TYPE_ENI). I 425 * believe the reason for calling it the "debug area" is that 426 * it can be accessed from outside of the guest, allowing an 427 * AWS user (?) or Amazon employee to get basic information 428 * about the state of the device from the guest's point of 429 * view. 430 * 431 * In the fullness of time, our driver should probably support 432 * this aspect of ENA. For the time being, all testing 433 * indicates the driver and device function fine without it. 434 */ 435 436 ret = ena_set_feature(ena, &cmd, &resp, ENAHW_FEAT_HOST_ATTR_CONFIG, 437 ENAHW_FEAT_HOST_ATTR_CONFIG_VER); 438 if (ret != 0) { 439 ena_err(ena, "failed to set host attributes: %d", ret); 440 ena_dma_free(hi_dma); 441 return (false); 442 } 443 444 return (true); 445 } 446 447 int 448 ena_create_cq(ena_t *ena, uint16_t num_descs, uint64_t phys_addr, 449 bool is_tx, uint32_t vector, uint16_t *hw_index, 450 uint32_t **unmask_addr, uint32_t **numanode) 451 { 452 int ret; 453 enahw_cmd_desc_t cmd; 454 enahw_cmd_create_cq_t *cmd_cq = &cmd.ecd_cmd.ecd_create_cq; 455 enahw_resp_desc_t resp; 456 enahw_resp_create_cq_t *resp_cq = &resp.erd_resp.erd_create_cq; 457 ena_cmd_ctx_t *ctx = NULL; 458 uint8_t desc_size = is_tx ? sizeof (enahw_tx_cdesc_t) : 459 sizeof (enahw_rx_cdesc_t); 460 461 bzero(&cmd, sizeof (cmd)); 462 bzero(&resp, sizeof (resp)); 463 464 cmd.ecd_opcode = ENAHW_CMD_CREATE_CQ; 465 ENAHW_CMD_CREATE_CQ_INTERRUPT_MODE_ENABLE(cmd_cq); 466 ASSERT3U(desc_size % 4, ==, 0); 467 ENAHW_CMD_CREATE_CQ_DESC_SIZE_WORDS(cmd_cq, desc_size / 4); 468 cmd_cq->ecq_num_descs = num_descs; 469 cmd_cq->ecq_msix_vector = vector; 470 ena_set_dma_addr(ena, phys_addr, &cmd_cq->ecq_addr); 471 472 if ((ret = ena_admin_submit_cmd(ena, &cmd, &resp, &ctx)) != 0) { 473 ena_err(ena, "failed to submit Create CQ command: %d", ret); 474 return (ret); 475 } 476 477 if ((ret = ena_admin_poll_for_resp(ena, ctx)) != 0) { 478 ena_err(ena, "failed to Create CQ: %d", ret); 479 return (ret); 480 } 481 482 *hw_index = resp_cq->ercq_idx; 483 *unmask_addr = (uint32_t *)(ena->ena_reg_base + 484 resp_cq->ercq_interrupt_mask_reg_offset); 485 486 if (resp_cq->ercq_numa_node_reg_offset != 0) { 487 *numanode = (uint32_t *)(ena->ena_reg_base + 488 resp_cq->ercq_numa_node_reg_offset); 489 } else { 490 *numanode = NULL; 491 } 492 493 /* 494 * The CQ head doorbell register is no longer supported by any 495 * existing adapter hardware. 496 */ 497 VERIFY0(resp_cq->ercq_head_db_reg_offset); 498 499 return (0); 500 } 501 502 int 503 ena_destroy_cq(ena_t *ena, uint16_t hw_idx) 504 { 505 enahw_cmd_desc_t cmd; 506 enahw_resp_desc_t resp; 507 ena_cmd_ctx_t *ctx = NULL; 508 int ret; 509 510 bzero(&cmd, sizeof (cmd)); 511 bzero(&resp, sizeof (resp)); 512 cmd.ecd_opcode = ENAHW_CMD_DESTROY_CQ; 513 cmd.ecd_cmd.ecd_destroy_cq.edcq_idx = hw_idx; 514 515 if ((ret = ena_admin_submit_cmd(ena, &cmd, &resp, &ctx)) != 0) { 516 ena_err(ena, "failed to submit Destroy CQ command: %d", ret); 517 return (ret); 518 } 519 520 if ((ret = ena_admin_poll_for_resp(ena, ctx)) != 0) { 521 ena_err(ena, "failed to Destroy CQ: %d", ret); 522 return (ret); 523 } 524 525 return (0); 526 } 527 528 int 529 ena_create_sq(ena_t *ena, uint16_t num_descs, uint64_t phys_addr, 530 bool is_tx, uint16_t cq_index, uint16_t *hw_index, uint32_t **db_addr) 531 { 532 int ret; 533 enahw_cmd_desc_t cmd; 534 enahw_cmd_create_sq_t *cmd_sq = &cmd.ecd_cmd.ecd_create_sq; 535 enahw_resp_desc_t resp; 536 enahw_resp_create_sq_t *resp_sq = &resp.erd_resp.erd_create_sq; 537 enahw_sq_direction_t dir = 538 is_tx ? ENAHW_SQ_DIRECTION_TX : ENAHW_SQ_DIRECTION_RX; 539 ena_cmd_ctx_t *ctx = NULL; 540 541 if (!ISP2(num_descs)) { 542 ena_err(ena, "the number of descs must be a power of 2, but " 543 " is %d", num_descs); 544 return (false); 545 } 546 547 bzero(&cmd, sizeof (cmd)); 548 bzero(&resp, sizeof (resp)); 549 cmd.ecd_opcode = ENAHW_CMD_CREATE_SQ; 550 ENAHW_CMD_CREATE_SQ_DIR(cmd_sq, dir); 551 ENAHW_CMD_CREATE_SQ_PLACEMENT_POLICY(cmd_sq, 552 ENAHW_PLACEMENT_POLICY_HOST); 553 ENAHW_CMD_CREATE_SQ_COMPLETION_POLICY(cmd_sq, 554 ENAHW_COMPLETION_POLICY_DESC); 555 /* 556 * We limit all SQ descriptor rings to an SGL of 1, therefore 557 * they are always physically contiguous. 558 */ 559 ENAHW_CMD_CREATE_SQ_PHYSMEM_CONTIG(cmd_sq); 560 cmd_sq->ecsq_cq_idx = cq_index; 561 cmd_sq->ecsq_num_descs = num_descs; 562 563 /* 564 * If we ever use a non-host placement policy, then guard this 565 * code against placement type (this value should not be set 566 * for device placement). 567 */ 568 ena_set_dma_addr(ena, phys_addr, &cmd_sq->ecsq_base); 569 570 if ((ret = ena_admin_submit_cmd(ena, &cmd, &resp, &ctx)) != 0) { 571 ena_err(ena, "failed to submit Create SQ command: %d", ret); 572 return (ret); 573 } 574 575 if ((ret = ena_admin_poll_for_resp(ena, ctx)) != 0) { 576 ena_err(ena, "failed to Create SQ: %d", ret); 577 return (ret); 578 } 579 580 *hw_index = resp_sq->ersq_idx; 581 *db_addr = (uint32_t *)(ena->ena_reg_base + 582 resp_sq->ersq_db_reg_offset); 583 return (0); 584 } 585 586 int 587 ena_destroy_sq(ena_t *ena, uint16_t hw_idx, bool is_tx) 588 { 589 enahw_cmd_desc_t cmd; 590 enahw_cmd_destroy_sq_t *cmd_sq = &cmd.ecd_cmd.ecd_destroy_sq; 591 enahw_sq_direction_t dir = 592 is_tx ? ENAHW_SQ_DIRECTION_TX : ENAHW_SQ_DIRECTION_RX; 593 enahw_resp_desc_t resp; 594 ena_cmd_ctx_t *ctx = NULL; 595 int ret; 596 597 bzero(&cmd, sizeof (cmd)); 598 bzero(&resp, sizeof (resp)); 599 cmd.ecd_opcode = ENAHW_CMD_DESTROY_SQ; 600 cmd_sq->edsq_idx = hw_idx; 601 ENAHW_CMD_DESTROY_SQ_DIR(cmd_sq, dir); 602 603 if ((ret = ena_admin_submit_cmd(ena, &cmd, &resp, &ctx)) != 0) { 604 ena_err(ena, "failed to submit Destroy SQ command: %d", ret); 605 return (ret); 606 } 607 608 if ((ret = ena_admin_poll_for_resp(ena, ctx)) != 0) { 609 ena_err(ena, "failed Destroy SQ: %d", ret); 610 return (ret); 611 } 612 613 return (0); 614 } 615 616 int 617 ena_set_feature(ena_t *ena, enahw_cmd_desc_t *cmd, enahw_resp_desc_t *resp, 618 const enahw_feature_id_t feat_id, const uint8_t feat_ver) 619 { 620 enahw_cmd_set_feat_t *cmd_sf = &cmd->ecd_cmd.ecd_set_feat; 621 ena_cmd_ctx_t *ctx = NULL; 622 int ret = 0; 623 624 if (!ena_is_feat_avail(ena, feat_id)) { 625 ena_err(ena, "attempted to set unsupported feature: 0x%x %d" 626 " (0x%x)", feat_id, feat_ver, ena->ena_supported_features); 627 return (ENOTSUP); 628 } 629 630 cmd->ecd_opcode = ENAHW_CMD_SET_FEATURE; 631 cmd_sf->ecsf_comm.efc_id = feat_id; 632 cmd_sf->ecsf_comm.efc_version = feat_ver; 633 cmd_sf->ecsf_comm.efc_flags = 0; 634 635 if ((ret = ena_admin_submit_cmd(ena, cmd, resp, &ctx)) != 0) { 636 ena_err(ena, "failed to submit Set Feature command: %d", ret); 637 return (ret); 638 } 639 640 return (ena_admin_poll_for_resp(ena, ctx)); 641 } 642 643 int 644 ena_get_feature(ena_t *ena, enahw_resp_desc_t *resp, 645 const enahw_feature_id_t feat_id, const uint8_t feat_ver) 646 { 647 enahw_cmd_desc_t cmd; 648 enahw_cmd_get_feat_t *cmd_gf = &cmd.ecd_cmd.ecd_get_feat; 649 ena_cmd_ctx_t *ctx = NULL; 650 int ret = 0; 651 652 if (!ena_is_feat_avail(ena, feat_id)) { 653 return (ENOTSUP); 654 } 655 656 bzero(&cmd, sizeof (cmd)); 657 cmd.ecd_opcode = ENAHW_CMD_GET_FEATURE; 658 cmd_gf->ecgf_comm.efc_id = feat_id; 659 cmd_gf->ecgf_comm.efc_version = feat_ver; 660 ENAHW_GET_FEAT_FLAGS_GET_CURR_VAL(cmd_gf); 661 662 if ((ret = ena_admin_submit_cmd(ena, &cmd, resp, &ctx)) != 0) { 663 ena_err(ena, "failed to submit Get Feature command: %d", ret); 664 return (ret); 665 } 666 667 return (ena_admin_poll_for_resp(ena, ctx)); 668 } 669 670 int 671 ena_admin_get_basic_stats(ena_t *ena, enahw_resp_desc_t *resp) 672 { 673 int ret = 0; 674 enahw_cmd_desc_t cmd; 675 enahw_cmd_get_stats_t *cmd_stats = &cmd.ecd_cmd.ecd_get_stats; 676 ena_cmd_ctx_t *ctx = NULL; 677 678 bzero(&cmd, sizeof (cmd)); 679 bzero(resp, sizeof (*resp)); 680 cmd.ecd_opcode = ENAHW_CMD_GET_STATS; 681 cmd_stats->ecgs_type = ENAHW_GET_STATS_TYPE_BASIC; 682 cmd_stats->ecgs_scope = ENAHW_GET_STATS_SCOPE_ETH; 683 cmd_stats->ecgs_device_id = ENAHW_CMD_GET_STATS_MY_DEVICE_ID; 684 685 if ((ret = ena_admin_submit_cmd(ena, &cmd, resp, &ctx)) != 0) { 686 ena_err(ena, "failed to submit Get Basic Stats command: %d", 687 ret); 688 return (ret); 689 } 690 691 if ((ret = ena_admin_poll_for_resp(ena, ctx)) != 0) { 692 ena_err(ena, "failed to Get Basic Stats: %d", ret); 693 return (ret); 694 } 695 696 return (0); 697 } 698 699 int 700 ena_admin_get_eni_stats(ena_t *ena, enahw_resp_desc_t *resp) 701 { 702 int ret = 0; 703 enahw_cmd_desc_t cmd; 704 enahw_cmd_get_stats_t *cmd_stats = &cmd.ecd_cmd.ecd_get_stats; 705 ena_cmd_ctx_t *ctx = NULL; 706 707 bzero(&cmd, sizeof (cmd)); 708 bzero(resp, sizeof (*resp)); 709 cmd.ecd_opcode = ENAHW_CMD_GET_STATS; 710 cmd_stats->ecgs_type = ENAHW_GET_STATS_TYPE_ENI; 711 cmd_stats->ecgs_scope = ENAHW_GET_STATS_SCOPE_ETH; 712 cmd_stats->ecgs_device_id = ENAHW_CMD_GET_STATS_MY_DEVICE_ID; 713 714 if ((ret = ena_admin_submit_cmd(ena, &cmd, resp, &ctx)) != 0) { 715 ena_err(ena, "failed to submit Get ENI Stats command: %d", ret); 716 return (ret); 717 } 718 719 if ((ret = ena_admin_poll_for_resp(ena, ctx)) != 0) { 720 ena_err(ena, "failed to Get ENI Stats: %d", ret); 721 return (ret); 722 } 723 724 return (0); 725 } 726