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
ena_complete_cmd_ctx(ena_cmd_ctx_t * ctx,enahw_resp_desc_t * hwresp)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
ena_reset_cmd_ctx(ena_cmd_ctx_t * ctx)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
ena_release_cmd_ctx(ena_t * ena,ena_cmd_ctx_t * ctx)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
ena_release_all_cmd_ctx(ena_t * ena)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
ena_create_cmd_ctx(ena_t * ena)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 *
ena_acquire_cmd_ctx(ena_adminq_t * aq)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
ena_admin_submit_cmd(ena_t * ena,enahw_cmd_desc_t * cmd,enahw_resp_desc_t * resp,ena_cmd_ctx_t ** ctx)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
ena_admin_read_resp(ena_t * ena,enahw_resp_desc_t * hwresp)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
ena_admin_process_responses(ena_t * ena)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
ena_admin_poll_for_resp(ena_t * ena,ena_cmd_ctx_t * ctx)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
ena_free_host_info(ena_t * ena)278 ena_free_host_info(ena_t *ena)
279 {
280 ena_dma_free(&ena->ena_host_info);
281 }
282
283 bool
ena_init_host_info(ena_t * ena)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
ena_create_cq(ena_t * ena,uint16_t num_descs,uint64_t phys_addr,bool is_tx,uint32_t vector,uint16_t * hw_index,uint32_t ** unmask_addr,uint32_t ** numanode)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
ena_destroy_cq(ena_t * ena,uint16_t hw_idx)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
ena_create_sq(ena_t * ena,uint16_t num_descs,uint64_t phys_addr,bool is_tx,uint16_t cq_index,uint16_t * hw_index,uint32_t ** db_addr)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
ena_destroy_sq(ena_t * ena,uint16_t hw_idx,bool is_tx)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
ena_set_feature(ena_t * ena,enahw_cmd_desc_t * cmd,enahw_resp_desc_t * resp,const enahw_feature_id_t feat_id,const uint8_t feat_ver)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
ena_get_feature(ena_t * ena,enahw_resp_desc_t * resp,const enahw_feature_id_t feat_id,const uint8_t feat_ver)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
ena_admin_get_basic_stats(ena_t * ena,enahw_resp_desc_t * resp)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
ena_admin_get_eni_stats(ena_t * ena,enahw_resp_desc_t * resp)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