1 /* SPDX-License-Identifier: Apache-2.0
2 * Copyright(c) 2023 Cisco Systems, Inc.
6 #include <vnet/dev/dev.h>
8 #include <dev_ena/ena.h>
9 #include <dev_ena/ena_inlines.h>
10 #include <vnet/ethernet/ethernet.h>
12 VLIB_REGISTER_LOG_CLASS (ena_log, static) = {
14 .subclass_name = "admin",
17 VLIB_REGISTER_LOG_CLASS (ena_stats_log, static) = {
19 .subclass_name = "admin-stats",
22 ena_aq_feat_info_t feat_info[] = {
23 #define _(v, ver, gt, st, n, s) \
26 .data_sz = sizeof (s), \
29 foreach_ena_aq_feature_id
34 ena_aq_get_feat_info (ena_aq_feature_id_t id)
36 if (id >= ARRAY_LEN (feat_info) || feat_info[id].data_sz == 0)
39 return feat_info + id;
43 ena_aq_free (vlib_main_t *vm, vnet_dev_t *dev)
45 ena_device_t *ed = vnet_dev_get_data (dev);
46 vnet_dev_dma_mem_free (vm, dev, ed->aq.cq_entries);
47 vnet_dev_dma_mem_free (vm, dev, ed->aq.sq_entries);
52 ena_aq_olloc (vlib_main_t *vm, vnet_dev_t *dev, u16 depth)
54 ena_device_t *ed = vnet_dev_get_data (dev);
55 vnet_dev_dma_mem_free (vm, dev, ed->aq.cq_entries);
56 vnet_dev_dma_mem_free (vm, dev, ed->aq.sq_entries);
57 u32 sq_alloc_sz = sizeof (ena_aq_sq_entry_t) * depth;
58 u32 cq_alloc_sz = sizeof (ena_aq_cq_entry_t) * depth;
61 ASSERT (ed->aq.sq_entries == 0);
62 ASSERT (ed->aq.cq_entries == 0);
64 rv = vnet_dev_dma_mem_alloc (vm, dev, sq_alloc_sz, 0,
65 (void **) &ed->aq.sq_entries);
66 if (rv != VNET_DEV_OK)
69 rv = vnet_dev_dma_mem_alloc (vm, dev, cq_alloc_sz, 0,
70 (void **) &ed->aq.cq_entries);
71 if (rv != VNET_DEV_OK)
78 ena_aq_free (vm, dev);
83 ena_aq_start (vlib_main_t *vm, vnet_dev_t *dev)
85 ena_device_t *ed = vnet_dev_get_data (dev);
86 u16 depth = ed->aq.depth;
87 u32 sq_alloc_sz = sizeof (ena_aq_sq_entry_t) * depth;
88 u32 cq_alloc_sz = sizeof (ena_aq_cq_entry_t) * depth;
90 ASSERT (ed->aq_started == 0);
92 ena_reg_aq_caps_t aq_caps = {
94 .entry_size = sizeof (ena_aq_sq_entry_t),
97 ena_reg_acq_caps_t acq_caps = {
99 .entry_size = sizeof (ena_aq_cq_entry_t),
102 clib_memset (ed->aq.sq_entries, 0, sq_alloc_sz);
103 clib_memset (ed->aq.cq_entries, 0, cq_alloc_sz);
108 ena_reg_set_dma_addr (vm, dev, ENA_REG_AQ_BASE_LO, ENA_REG_AQ_BASE_HI,
110 ena_reg_set_dma_addr (vm, dev, ENA_REG_ACQ_BASE_LO, ENA_REG_ACQ_BASE_HI,
113 ena_reg_write (dev, ENA_REG_AQ_CAPS, &aq_caps);
114 ena_reg_write (dev, ENA_REG_ACQ_CAPS, &acq_caps);
122 ena_aq_stop (vlib_main_t *vm, vnet_dev_t *dev)
124 ena_device_t *ed = vnet_dev_get_data (dev);
125 ena_reg_aq_caps_t aq_caps = {};
126 ena_reg_acq_caps_t acq_caps = {};
130 ena_reg_write (dev, ENA_REG_AQ_CAPS, &aq_caps);
131 ena_reg_write (dev, ENA_REG_ACQ_CAPS, &acq_caps);
136 ena_aq_req (vlib_main_t *vm, vnet_dev_t *dev, ena_aq_opcode_t opcode,
137 void *sqe_data, u8 sqe_data_sz, void *cqe_data, u8 cqe_data_sz)
139 ena_device_t *ed = vnet_dev_get_data (dev);
140 u32 next = ed->aq.sq_next++;
141 u32 index = next & pow2_mask (ENA_ADMIN_QUEUE_LOG2_DEPTH);
142 u8 phase = 1 & (~(next >> ENA_ADMIN_QUEUE_LOG2_DEPTH));
143 ena_aq_sq_entry_t *sqe = ed->aq.sq_entries + index;
144 ena_aq_cq_entry_t *cqe = ed->aq.cq_entries + index;
145 f64 suspend_time = 1e-6;
147 clib_memcpy_fast (&sqe->data, sqe_data, sqe_data_sz);
148 sqe->opcode = opcode;
149 sqe->command_id = index;
152 ena_reg_write (dev, ENA_REG_AQ_DB, &ed->aq.sq_next);
154 while (cqe->phase != phase)
156 vlib_process_suspend (vm, suspend_time);
158 if (suspend_time > 1e-3)
160 log_err (dev, "admin queue timeout (opcode %U)",
161 format_ena_aq_opcode, opcode);
162 return VNET_DEV_ERR_TIMEOUT;
166 if (cqe->status != ENA_ADMIN_COMPL_STATUS_SUCCESS)
169 "cqe[%u]: opcode %U status %U ext_status %u sq_head_idx %u",
170 cqe - ed->aq.cq_entries, format_ena_aq_opcode, opcode,
171 format_ena_aq_status, cqe->status, cqe->extended_status,
173 return VNET_DEV_ERR_DEVICE_NO_REPLY;
176 log_debug (dev, "cqe: status %u ext_status %u sq_head_idx %u", cqe->status,
177 cqe->extended_status, cqe->sq_head_indx);
179 if (cqe_data && cqe_data_sz)
180 clib_memcpy_fast (cqe_data, &cqe->data, cqe_data_sz);
185 ena_aq_set_feature (vlib_main_t *vm, vnet_dev_t *dev,
186 ena_aq_feature_id_t feat_id, void *data)
192 ena_aq_aq_ctrl_buff_info_t control_buffer;
193 ena_aq_get_set_feature_common_desc_t feat_common;
196 .feat_common.feature_id = feat_id,
197 .feat_common.feature_version = feat_info[feat_id].version,
200 log_debug (dev, "set_feature(%s):\n %U", feat_info[feat_id].name,
201 format_ena_aq_feat_desc, feat_id, data);
203 ASSERT (feat_info[feat_id].data_sz > 1);
204 clib_memcpy (&fd.data, data, feat_info[feat_id].data_sz);
206 rv = ena_aq_req (vm, dev, ENA_AQ_OPCODE_SET_FEATURE, &fd, sizeof (fd), 0, 0);
208 if (rv != VNET_DEV_OK)
209 log_err (dev, "get_feature(%U) failed", format_ena_aq_feat_name, feat_id);
215 ena_aq_get_feature (vlib_main_t *vm, vnet_dev_t *dev,
216 ena_aq_feature_id_t feat_id, void *data)
222 ena_aq_aq_ctrl_buff_info_t control_buffer;
223 ena_aq_get_set_feature_common_desc_t feat_common;
226 .feat_common.feature_id = feat_id,
227 .feat_common.feature_version = feat_info[feat_id].version,
230 rv = ena_aq_req (vm, dev, ENA_AQ_OPCODE_GET_FEATURE, &fd, sizeof (fd), data,
231 feat_info[feat_id].data_sz);
233 if (rv != VNET_DEV_OK)
235 log_err (dev, "get_feature(%U) failed", format_ena_aq_feat_name,
240 ASSERT (feat_info[feat_id].data_sz > 1);
242 log_debug (dev, "get_feature(%s):\n %U", feat_info[feat_id].name,
243 format_ena_aq_feat_desc, feat_id, data);
249 ena_aq_create_sq (vlib_main_t *vm, vnet_dev_t *dev,
250 ena_aq_create_sq_cmd_t *cmd, ena_aq_create_sq_resp_t *resp)
254 log_debug (dev, "create_sq_cmd_req:\n %U", format_ena_aq_create_sq_cmd,
257 rv = ena_aq_req (vm, dev, ENA_AQ_OPCODE_CREATE_SQ, cmd, sizeof (*cmd), resp,
260 if (rv != VNET_DEV_OK)
261 log_debug (dev, "create_sq_cmd_resp:\n %U", format_ena_aq_create_sq_resp,
267 ena_aq_create_cq (vlib_main_t *vm, vnet_dev_t *dev,
268 ena_aq_create_cq_cmd_t *cmd, ena_aq_create_cq_resp_t *resp)
272 log_debug (dev, "create_cq_cmd_req:\n %U", format_ena_aq_create_cq_cmd,
275 rv = ena_aq_req (vm, dev, ENA_AQ_OPCODE_CREATE_CQ, cmd, sizeof (*cmd), resp,
278 if (rv != VNET_DEV_OK)
279 log_debug (dev, "create_cq_cmd_resp:\n %U", format_ena_aq_create_cq_resp,
286 ena_aq_destroy_sq (vlib_main_t *vm, vnet_dev_t *dev,
287 ena_aq_destroy_sq_cmd_t *cmd)
289 log_debug (dev, "destroy_sq_cmd_req:\n %U", format_ena_aq_destroy_sq_cmd,
292 return ena_aq_req (vm, dev, ENA_AQ_OPCODE_DESTROY_SQ, cmd, sizeof (*cmd), 0,
297 ena_aq_destroy_cq (vlib_main_t *vm, vnet_dev_t *dev,
298 ena_aq_destroy_cq_cmd_t *cmd)
300 log_debug (dev, "destroy_cq_cmd_req:\n %U", format_ena_aq_destroy_cq_cmd,
303 return ena_aq_req (vm, dev, ENA_AQ_OPCODE_DESTROY_CQ, cmd, sizeof (*cmd), 0,
308 ena_aq_get_stats (vlib_main_t *vm, vnet_dev_t *dev, ena_aq_stats_type_t type,
309 ena_aq_stats_scope_t scope, u16 queue_idx, void *data)
312 format_function_t *ff = 0;
314 [ENA_ADMIN_STATS_TYPE_BASIC] = sizeof (ena_aq_basic_stats_t),
315 [ENA_ADMIN_STATS_TYPE_EXTENDED] = 0,
316 [ENA_ADMIN_STATS_TYPE_ENI] = sizeof (ena_aq_eni_stats_t),
320 #define _(n, s) [n] = #s,
321 foreach_ena_aq_stats_type
325 char *scope_str[] = {
326 #define _(n, s) [n] = #s,
327 foreach_ena_aq_stats_scope
331 ena_aq_get_stats_cmd_t cmd = {
334 .queue_idx = scope == ENA_ADMIN_STATS_SCOPE_SPECIFIC_QUEUE ? queue_idx : 0,
338 if ((rv = ena_aq_req (vm, dev, ENA_AQ_OPCODE_GET_STATS, &cmd, sizeof (cmd),
339 data, data_sz[type])))
341 ena_stats_log_err (dev, "get_stats(%s, %s) failed", type_str[type],
346 if (type == ENA_ADMIN_STATS_TYPE_BASIC)
347 ff = format_ena_aq_basic_stats;
348 else if (type == ENA_ADMIN_STATS_TYPE_ENI)
349 ff = format_ena_aq_eni_stats;
352 ena_stats_log_debug (dev, "get_stats(%s, %s, %u):\n %U", type_str[type],
353 scope_str[scope], queue_idx, ff, data);
355 ena_stats_log_debug (dev, "get_stats(%s, %s, %u): unknown data",
356 type_str[type], scope_str[scope], queue_idx);