Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2020 Mellanox Technologies, Ltd
3 : : */
4 : :
5 : : #include <stddef.h>
6 : : #include <errno.h>
7 : : #include <stdbool.h>
8 : : #include <string.h>
9 : : #include <stdint.h>
10 : : #include <sys/queue.h>
11 : :
12 : : #include <rte_malloc.h>
13 : : #include <rte_common.h>
14 : : #include <rte_eal_paging.h>
15 : :
16 : : #include <mlx5_glue.h>
17 : : #include <mlx5_devx_cmds.h>
18 : : #include <mlx5_common_devx.h>
19 : : #include <mlx5_malloc.h>
20 : :
21 : : #include "mlx5.h"
22 : : #include "mlx5_common_os.h"
23 : : #include "mlx5_tx.h"
24 : : #include "mlx5_rx.h"
25 : : #include "mlx5_utils.h"
26 : : #include "mlx5_devx.h"
27 : : #include "mlx5_flow.h"
28 : : #include "mlx5_flow_os.h"
29 : :
30 : : /**
31 : : * Validate given external queue's port is valid or not.
32 : : *
33 : : * @param[in] port_id
34 : : * The port identifier of the Ethernet device.
35 : : *
36 : : * @return
37 : : * 0 on success, non-0 otherwise
38 : : */
39 : : int
40 : 0 : mlx5_devx_extq_port_validate(uint16_t port_id)
41 : : {
42 : : struct rte_eth_dev *dev;
43 : : struct mlx5_priv *priv;
44 : :
45 [ # # ]: 0 : if (rte_eth_dev_is_valid_port(port_id) < 0) {
46 : 0 : DRV_LOG(ERR, "There is no Ethernet device for port %u.",
47 : : port_id);
48 : 0 : rte_errno = ENODEV;
49 : 0 : return -rte_errno;
50 : : }
51 : : dev = &rte_eth_devices[port_id];
52 : 0 : priv = dev->data->dev_private;
53 [ # # # # ]: 0 : if (!mlx5_imported_pd_and_ctx(priv->sh->cdev)) {
54 : 0 : DRV_LOG(ERR, "Port %u "
55 : : "external queue isn't supported on local PD and CTX.",
56 : : port_id);
57 : 0 : rte_errno = ENOTSUP;
58 : 0 : return -rte_errno;
59 : : }
60 [ # # ]: 0 : if (!mlx5_devx_obj_ops_en(priv->sh)) {
61 : 0 : DRV_LOG(ERR,
62 : : "Port %u external queue isn't supported by Verbs API.",
63 : : port_id);
64 : 0 : rte_errno = ENOTSUP;
65 : 0 : return -rte_errno;
66 : : }
67 : : return 0;
68 : : }
69 : :
70 : : /**
71 : : * Modify RQ vlan stripping offload
72 : : *
73 : : * @param rxq
74 : : * Rx queue.
75 : : * @param on
76 : : * Enable/disable VLAN stripping.
77 : : *
78 : : * @return
79 : : * 0 on success, non-0 otherwise
80 : : */
81 : : static int
82 : 0 : mlx5_rxq_obj_modify_rq_vlan_strip(struct mlx5_rxq_priv *rxq, int on)
83 : : {
84 : : struct mlx5_devx_modify_rq_attr rq_attr;
85 : :
86 : : memset(&rq_attr, 0, sizeof(rq_attr));
87 : 0 : rq_attr.rq_state = MLX5_RQC_STATE_RDY;
88 : 0 : rq_attr.state = MLX5_RQC_STATE_RDY;
89 : 0 : rq_attr.vsd = (on ? 0 : 1);
90 : 0 : rq_attr.modify_bitmask = MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_VSD;
91 : 0 : return mlx5_devx_cmd_modify_rq(rxq->devx_rq.rq, &rq_attr);
92 : : }
93 : :
94 : : /**
95 : : * Modify RQ using DevX API.
96 : : *
97 : : * @param rxq
98 : : * DevX rx queue.
99 : : * @param type
100 : : * Type of change queue state.
101 : : *
102 : : * @return
103 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
104 : : */
105 : : int
106 [ # # # # : 0 : mlx5_devx_modify_rq(struct mlx5_rxq_priv *rxq, uint8_t type)
# # ]
107 : : {
108 : : struct mlx5_devx_modify_rq_attr rq_attr;
109 : :
110 : : memset(&rq_attr, 0, sizeof(rq_attr));
111 [ # # # # : 0 : switch (type) {
# # ]
112 : 0 : case MLX5_RXQ_MOD_ERR2RST:
113 : 0 : rq_attr.rq_state = MLX5_RQC_STATE_ERR;
114 : : rq_attr.state = MLX5_RQC_STATE_RST;
115 : 0 : break;
116 : 0 : case MLX5_RXQ_MOD_RST2RDY:
117 : : rq_attr.rq_state = MLX5_RQC_STATE_RST;
118 : 0 : rq_attr.state = MLX5_RQC_STATE_RDY;
119 [ # # ]: 0 : if (rxq->lwm) {
120 : 0 : rq_attr.modify_bitmask |=
121 : : MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM;
122 : 0 : rq_attr.lwm = rxq->lwm;
123 : : }
124 : : break;
125 : 0 : case MLX5_RXQ_MOD_RDY2ERR:
126 : 0 : rq_attr.rq_state = MLX5_RQC_STATE_RDY;
127 : 0 : rq_attr.state = MLX5_RQC_STATE_ERR;
128 : 0 : break;
129 : 0 : case MLX5_RXQ_MOD_RDY2RST:
130 : 0 : rq_attr.rq_state = MLX5_RQC_STATE_RDY;
131 : : rq_attr.state = MLX5_RQC_STATE_RST;
132 : 0 : break;
133 : 0 : case MLX5_RXQ_MOD_RDY2RDY:
134 : 0 : rq_attr.rq_state = MLX5_RQC_STATE_RDY;
135 : 0 : rq_attr.state = MLX5_RQC_STATE_RDY;
136 : 0 : rq_attr.modify_bitmask |= MLX5_MODIFY_RQ_IN_MODIFY_BITMASK_WQ_LWM;
137 : 0 : rq_attr.lwm = rxq->lwm;
138 : 0 : break;
139 : : default:
140 : : break;
141 : : }
142 [ # # ]: 0 : if (rxq->ctrl->is_hairpin)
143 : 0 : return mlx5_devx_cmd_modify_rq(rxq->ctrl->obj->rq, &rq_attr);
144 : 0 : return mlx5_devx_cmd_modify_rq(rxq->devx_rq.rq, &rq_attr);
145 : : }
146 : :
147 : : /**
148 : : * Modify SQ using DevX API.
149 : : *
150 : : * @param txq_obj
151 : : * DevX Tx queue object.
152 : : * @param type
153 : : * Type of change queue state.
154 : : * @param dev_port
155 : : * Unnecessary.
156 : : *
157 : : * @return
158 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
159 : : */
160 : : int
161 : 0 : mlx5_txq_devx_modify(struct mlx5_txq_obj *obj, enum mlx5_txq_modify_type type,
162 : : uint8_t dev_port)
163 : : {
164 : 0 : struct mlx5_devx_modify_sq_attr msq_attr = { 0 };
165 : : int ret;
166 : :
167 [ # # ]: 0 : if (type != MLX5_TXQ_MOD_RST2RDY) {
168 : : /* Change queue state to reset. */
169 [ # # ]: 0 : if (type == MLX5_TXQ_MOD_ERR2RDY)
170 : 0 : msq_attr.sq_state = MLX5_SQC_STATE_ERR;
171 : : else
172 : 0 : msq_attr.sq_state = MLX5_SQC_STATE_RDY;
173 : : msq_attr.state = MLX5_SQC_STATE_RST;
174 : 0 : ret = mlx5_devx_cmd_modify_sq(obj->sq_obj.sq, &msq_attr);
175 [ # # ]: 0 : if (ret) {
176 : 0 : DRV_LOG(ERR, "Cannot change the Tx SQ state to RESET"
177 : : " %s", strerror(errno));
178 : 0 : rte_errno = errno;
179 : 0 : return ret;
180 : : }
181 : : }
182 [ # # ]: 0 : if (type != MLX5_TXQ_MOD_RDY2RST) {
183 : : /* Change queue state to ready. */
184 : 0 : msq_attr.sq_state = MLX5_SQC_STATE_RST;
185 : 0 : msq_attr.state = MLX5_SQC_STATE_RDY;
186 : 0 : ret = mlx5_devx_cmd_modify_sq(obj->sq_obj.sq, &msq_attr);
187 [ # # ]: 0 : if (ret) {
188 : 0 : DRV_LOG(ERR, "Cannot change the Tx SQ state to READY"
189 : : " %s", strerror(errno));
190 : 0 : rte_errno = errno;
191 : 0 : return ret;
192 : : }
193 : : }
194 : : /*
195 : : * The dev_port variable is relevant only in Verbs API, and there is a
196 : : * pointer that points to this function and a parallel function in verbs
197 : : * intermittently, so they should have the same parameters.
198 : : */
199 : : (void)dev_port;
200 : : return 0;
201 : : }
202 : :
203 : : /**
204 : : * Release an Rx DevX queue object.
205 : : *
206 : : * @param rxq
207 : : * DevX Rx queue.
208 : : */
209 : : static void
210 : 0 : mlx5_rxq_devx_obj_release(struct mlx5_rxq_priv *rxq)
211 : : {
212 : 0 : struct mlx5_rxq_obj *rxq_obj = rxq->ctrl->obj;
213 : :
214 [ # # ]: 0 : if (rxq_obj == NULL)
215 : : return;
216 [ # # ]: 0 : if (rxq_obj->rxq_ctrl->is_hairpin) {
217 [ # # ]: 0 : if (rxq_obj->rq == NULL)
218 : : return;
219 : 0 : mlx5_devx_modify_rq(rxq, MLX5_RXQ_MOD_RDY2RST);
220 : 0 : claim_zero(mlx5_devx_cmd_destroy(rxq_obj->rq));
221 : : } else {
222 [ # # ]: 0 : if (rxq->devx_rq.rq == NULL)
223 : : return;
224 : 0 : mlx5_devx_rq_destroy(&rxq->devx_rq);
225 [ # # # # ]: 0 : if (rxq->devx_rq.rmp != NULL && rxq->devx_rq.rmp->ref_cnt > 0)
226 : : return;
227 : 0 : mlx5_devx_cq_destroy(&rxq_obj->cq_obj);
228 : : memset(&rxq_obj->cq_obj, 0, sizeof(rxq_obj->cq_obj));
229 [ # # ]: 0 : if (rxq_obj->devx_channel) {
230 : : mlx5_os_devx_destroy_event_channel
231 : : (rxq_obj->devx_channel);
232 : 0 : rxq_obj->devx_channel = NULL;
233 : : }
234 : : }
235 : 0 : rxq->ctrl->started = false;
236 : : }
237 : :
238 : : /**
239 : : * Get event for an Rx DevX queue object.
240 : : *
241 : : * @param rxq_obj
242 : : * DevX Rx queue object.
243 : : *
244 : : * @return
245 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
246 : : */
247 : : static int
248 : 0 : mlx5_rx_devx_get_event(struct mlx5_rxq_obj *rxq_obj)
249 : : {
250 : : #ifdef HAVE_IBV_DEVX_EVENT
251 : : union {
252 : : struct mlx5dv_devx_async_event_hdr event_resp;
253 : : uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) + 128];
254 : : } out;
255 : 0 : int ret = mlx5_glue->devx_get_event(rxq_obj->devx_channel,
256 : : &out.event_resp,
257 : : sizeof(out.buf));
258 : :
259 [ # # ]: 0 : if (ret < 0) {
260 : 0 : rte_errno = errno;
261 : 0 : return -rte_errno;
262 : : }
263 [ # # ]: 0 : if (out.event_resp.cookie != (uint64_t)(uintptr_t)rxq_obj->cq_obj.cq) {
264 : 0 : rte_errno = EINVAL;
265 : 0 : return -rte_errno;
266 : : }
267 : : return 0;
268 : : #else
269 : : (void)rxq_obj;
270 : : rte_errno = ENOTSUP;
271 : : return -rte_errno;
272 : : #endif /* HAVE_IBV_DEVX_EVENT */
273 : : }
274 : :
275 : : /**
276 : : * Get LWM event for shared context, return the correct port/rxq for this event.
277 : : *
278 : : * @param priv
279 : : * Mlx5_priv object.
280 : : * @param rxq_idx [out]
281 : : * Which rxq gets this event.
282 : : * @param port_id [out]
283 : : * Which port gets this event.
284 : : *
285 : : * @return
286 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
287 : : */
288 : : static int
289 : 0 : mlx5_rx_devx_get_event_lwm(struct mlx5_priv *priv, int *rxq_idx, int *port_id)
290 : : {
291 : : #ifdef HAVE_IBV_DEVX_EVENT
292 : : union {
293 : : struct mlx5dv_devx_async_event_hdr event_resp;
294 : : uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) + 128];
295 : : } out;
296 : : int ret;
297 : :
298 : : memset(&out, 0, sizeof(out));
299 : 0 : ret = mlx5_glue->devx_get_event(priv->sh->devx_channel_lwm,
300 : : &out.event_resp,
301 : : sizeof(out.buf));
302 [ # # ]: 0 : if (ret < 0) {
303 : 0 : rte_errno = errno;
304 : 0 : DRV_LOG(WARNING, "%s err\n", __func__);
305 : 0 : return -rte_errno;
306 : : }
307 : 0 : *port_id = (((uint32_t)out.event_resp.cookie) >>
308 : 0 : LWM_COOKIE_PORTID_OFFSET) & LWM_COOKIE_PORTID_MASK;
309 : 0 : *rxq_idx = (((uint32_t)out.event_resp.cookie) >>
310 : 0 : LWM_COOKIE_RXQID_OFFSET) & LWM_COOKIE_RXQID_MASK;
311 : 0 : return 0;
312 : : #else
313 : : (void)priv;
314 : : (void)rxq_idx;
315 : : (void)port_id;
316 : : rte_errno = ENOTSUP;
317 : : return -rte_errno;
318 : : #endif /* HAVE_IBV_DEVX_EVENT */
319 : : }
320 : :
321 : : /**
322 : : * Create a RQ object using DevX.
323 : : *
324 : : * @param rxq
325 : : * Pointer to Rx queue.
326 : : *
327 : : * @return
328 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
329 : : */
330 : : static int
331 : 0 : mlx5_rxq_create_devx_rq_resources(struct mlx5_rxq_priv *rxq)
332 : : {
333 : 0 : struct mlx5_priv *priv = rxq->priv;
334 : 0 : struct mlx5_common_device *cdev = priv->sh->cdev;
335 : 0 : struct mlx5_rxq_ctrl *rxq_ctrl = rxq->ctrl;
336 : : struct mlx5_rxq_data *rxq_data = &rxq->ctrl->rxq;
337 : 0 : struct mlx5_devx_create_rq_attr rq_attr = { 0 };
338 : 0 : uint16_t log_desc_n = rxq_data->elts_n - rxq_data->sges_n;
339 : : uint32_t wqe_size, log_wqe_size;
340 : :
341 : : /* Fill RQ attributes. */
342 : : rq_attr.mem_rq_type = MLX5_RQC_MEM_RQ_TYPE_MEMORY_RQ_INLINE;
343 : 0 : rq_attr.flush_in_error_en = 1;
344 : 0 : rq_attr.vsd = (rxq_data->vlan_strip) ? 0 : 1;
345 : 0 : rq_attr.cqn = rxq_ctrl->obj->cq_obj.cq->id;
346 : 0 : rq_attr.scatter_fcs = (rxq_data->crc_present) ? 1 : 0;
347 [ # # ]: 0 : rq_attr.ts_format =
348 [ # # ]: 0 : mlx5_ts_format_conv(cdev->config.hca_attr.rq_ts_format);
349 : : /* Fill WQ attributes for this RQ. */
350 [ # # ]: 0 : if (mlx5_rxq_mprq_enabled(rxq_data)) {
351 : 0 : rq_attr.wq_attr.wq_type = MLX5_WQ_TYPE_CYCLIC_STRIDING_RQ;
352 : : /*
353 : : * Number of strides in each WQE:
354 : : * 512*2^single_wqe_log_num_of_strides.
355 : : */
356 : 0 : rq_attr.wq_attr.single_wqe_log_num_of_strides =
357 : 0 : rxq_data->log_strd_num -
358 : : MLX5_MIN_SINGLE_WQE_LOG_NUM_STRIDES;
359 : : /* Stride size = (2^single_stride_log_num_of_bytes)*64B. */
360 : 0 : rq_attr.wq_attr.single_stride_log_num_of_bytes =
361 : 0 : rxq_data->log_strd_sz -
362 : : MLX5_MIN_SINGLE_STRIDE_LOG_NUM_BYTES;
363 : : wqe_size = sizeof(struct mlx5_wqe_mprq);
364 : : } else {
365 : 0 : rq_attr.wq_attr.wq_type = MLX5_WQ_TYPE_CYCLIC;
366 : : wqe_size = sizeof(struct mlx5_wqe_data_seg);
367 : : }
368 : 0 : log_wqe_size = log2above(wqe_size) + rxq_data->sges_n;
369 : 0 : wqe_size = 1 << log_wqe_size; /* round up power of two.*/
370 : 0 : rq_attr.wq_attr.log_wq_stride = log_wqe_size;
371 : 0 : rq_attr.wq_attr.log_wq_sz = log_desc_n;
372 : 0 : rq_attr.wq_attr.end_padding_mode = priv->config.hw_padding ?
373 : 0 : MLX5_WQ_END_PAD_MODE_ALIGN :
374 : : MLX5_WQ_END_PAD_MODE_NONE;
375 : 0 : rq_attr.wq_attr.pd = cdev->pdn;
376 : 0 : rq_attr.counter_set_id = priv->counter_set_id;
377 : 0 : rq_attr.delay_drop_en = rxq_data->delay_drop;
378 [ # # ]: 0 : rq_attr.user_index = rte_cpu_to_be_16(priv->dev_data->port_id);
379 [ # # ]: 0 : if (rxq_data->shared) /* Create RMP based RQ. */
380 : 0 : rxq->devx_rq.rmp = &rxq_ctrl->obj->devx_rmp;
381 : : /* Create RQ using DevX API. */
382 : 0 : return mlx5_devx_rq_create(cdev->ctx, &rxq->devx_rq, wqe_size,
383 : 0 : log_desc_n, &rq_attr, rxq_ctrl->socket);
384 : : }
385 : :
386 : : /**
387 : : * Create a DevX CQ object for an Rx queue.
388 : : *
389 : : * @param rxq
390 : : * Pointer to Rx queue.
391 : : *
392 : : * @return
393 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
394 : : */
395 : : static int
396 : 0 : mlx5_rxq_create_devx_cq_resources(struct mlx5_rxq_priv *rxq)
397 : : {
398 : : struct mlx5_devx_cq *cq_obj = 0;
399 : 0 : struct mlx5_devx_cq_attr cq_attr = { 0 };
400 : 0 : struct mlx5_priv *priv = rxq->priv;
401 : 0 : struct mlx5_dev_ctx_shared *sh = priv->sh;
402 : 0 : uint16_t port_id = priv->dev_data->port_id;
403 : 0 : struct mlx5_rxq_ctrl *rxq_ctrl = rxq->ctrl;
404 : 0 : struct mlx5_rxq_data *rxq_data = &rxq_ctrl->rxq;
405 : 0 : unsigned int cqe_n = mlx5_rxq_cqe_num(rxq_data);
406 : : uint32_t log_cqe_n;
407 : 0 : uint16_t event_nums[1] = { 0 };
408 : : int ret = 0;
409 : :
410 [ # # ]: 0 : if (rxq_ctrl->started)
411 : : return 0;
412 [ # # # # ]: 0 : if (priv->config.cqe_comp && !rxq_data->hw_timestamp &&
413 : : !rxq_data->lro) {
414 : 0 : cq_attr.cqe_comp_en = 1u;
415 : 0 : cq_attr.cqe_comp_layout = priv->config.enh_cqe_comp;
416 : 0 : rxq_data->cqe_comp_layout = cq_attr.cqe_comp_layout;
417 : 0 : rxq_data->mcqe_format = priv->config.cqe_comp_fmt;
418 : 0 : rxq_data->byte_mask = UINT32_MAX;
419 [ # # # # : 0 : switch (priv->config.cqe_comp_fmt) {
# ]
420 : 0 : case MLX5_CQE_RESP_FORMAT_HASH:
421 : : /* fallthrough */
422 : : case MLX5_CQE_RESP_FORMAT_CSUM:
423 : : /*
424 : : * Select CSUM miniCQE format only for non-vectorized
425 : : * MPRQ Rx burst, use HASH miniCQE format for others.
426 : : */
427 [ # # # # ]: 0 : if (mlx5_rxq_check_vec_support(rxq_data) < 0 &&
428 : : mlx5_rxq_mprq_enabled(rxq_data))
429 : 0 : cq_attr.mini_cqe_res_format =
430 : : MLX5_CQE_RESP_FORMAT_CSUM_STRIDX;
431 : : else
432 : 0 : cq_attr.mini_cqe_res_format =
433 : : MLX5_CQE_RESP_FORMAT_HASH;
434 : 0 : rxq_data->mcqe_format = cq_attr.mini_cqe_res_format;
435 : 0 : break;
436 : 0 : case MLX5_CQE_RESP_FORMAT_FTAG_STRIDX:
437 : 0 : rxq_data->byte_mask = MLX5_LEN_WITH_MARK_MASK;
438 : : /* fallthrough */
439 : 0 : case MLX5_CQE_RESP_FORMAT_CSUM_STRIDX:
440 : 0 : cq_attr.mini_cqe_res_format = priv->config.cqe_comp_fmt;
441 : 0 : break;
442 : 0 : case MLX5_CQE_RESP_FORMAT_L34H_STRIDX:
443 : 0 : cq_attr.mini_cqe_res_format = 0;
444 : 0 : cq_attr.mini_cqe_res_format_ext = 1;
445 : 0 : break;
446 : : }
447 : 0 : DRV_LOG(DEBUG,
448 : : "Port %u Rx CQE compression is enabled, format %d.",
449 : : port_id, priv->config.cqe_comp_fmt);
450 : : /*
451 : : * For vectorized Rx, it must not be doubled in order to
452 : : * make cq_ci and rq_ci aligned.
453 : : */
454 [ # # ]: 0 : if (mlx5_rxq_check_vec_support(rxq_data) < 0)
455 : 0 : cqe_n *= 2;
456 [ # # # # ]: 0 : } else if (priv->config.cqe_comp && rxq_data->hw_timestamp) {
457 : 0 : DRV_LOG(DEBUG,
458 : : "Port %u Rx CQE compression is disabled for HW timestamp.",
459 : : port_id);
460 [ # # # # ]: 0 : } else if (priv->config.cqe_comp && rxq_data->lro) {
461 : 0 : DRV_LOG(DEBUG,
462 : : "Port %u Rx CQE compression is disabled for LRO.",
463 : : port_id);
464 : : }
465 [ # # ]: 0 : cq_attr.uar_page_id = mlx5_os_get_devx_uar_page_id(sh->rx_uar.obj);
466 : : log_cqe_n = log2above(cqe_n);
467 : : /* Create CQ using DevX API. */
468 : 0 : ret = mlx5_devx_cq_create(sh->cdev->ctx, &rxq_ctrl->obj->cq_obj,
469 : : log_cqe_n, &cq_attr, sh->numa_node);
470 [ # # ]: 0 : if (ret)
471 : : return ret;
472 : 0 : cq_obj = &rxq_ctrl->obj->cq_obj;
473 : 0 : rxq_data->cqes = (volatile struct mlx5_cqe (*)[])
474 : 0 : (uintptr_t)cq_obj->cqes;
475 : 0 : rxq_data->cq_db = cq_obj->db_rec;
476 : 0 : rxq_data->uar_data = sh->rx_uar.cq_db;
477 : 0 : rxq_data->cqe_n = log_cqe_n;
478 : 0 : rxq_data->cqn = cq_obj->cq->id;
479 : 0 : rxq_data->cq_ci = 0;
480 [ # # ]: 0 : if (rxq_ctrl->obj->devx_channel) {
481 : 0 : ret = mlx5_os_devx_subscribe_devx_event
482 : : (rxq_ctrl->obj->devx_channel,
483 : : cq_obj->cq->obj,
484 : : sizeof(event_nums),
485 : : event_nums,
486 : : (uint64_t)(uintptr_t)cq_obj->cq);
487 [ # # ]: 0 : if (ret) {
488 : 0 : DRV_LOG(ERR, "Fail to subscribe CQ to event channel.");
489 : 0 : ret = errno;
490 : 0 : mlx5_devx_cq_destroy(cq_obj);
491 : : memset(cq_obj, 0, sizeof(*cq_obj));
492 : 0 : rte_errno = ret;
493 : 0 : return -ret;
494 : : }
495 : : }
496 : : return 0;
497 : : }
498 : :
499 : : /**
500 : : * Create a global queue counter for all the port hairpin queues.
501 : : *
502 : : * @param priv
503 : : * Device private data.
504 : : *
505 : : * @return
506 : : * The counter_set_id of the queue counter object, 0 otherwise.
507 : : */
508 : : static uint32_t
509 : 0 : mlx5_set_hairpin_queue_counter_obj(struct mlx5_priv *priv)
510 : : {
511 [ # # ]: 0 : if (priv->q_counters_hairpin != NULL)
512 : 0 : return priv->q_counters_hairpin->id;
513 : :
514 : : /* Queue counter allocation failed in the past - don't try again. */
515 [ # # ]: 0 : if (priv->q_counters_allocation_failure != 0)
516 : : return 0;
517 : :
518 [ # # ]: 0 : if (priv->pci_dev == NULL) {
519 : 0 : DRV_LOG(DEBUG, "Hairpin out of buffer counter is "
520 : : "only supported on PCI device.");
521 : 0 : priv->q_counters_allocation_failure = 1;
522 : 0 : return 0;
523 : : }
524 : :
525 [ # # ]: 0 : switch (priv->pci_dev->id.device_id) {
526 : : /* Counting out of buffer drops on hairpin queues is supported only on CX7 and up. */
527 : 0 : case PCI_DEVICE_ID_MELLANOX_CONNECTX7:
528 : : case PCI_DEVICE_ID_MELLANOX_CONNECTXVF:
529 : : case PCI_DEVICE_ID_MELLANOX_BLUEFIELD3:
530 : : case PCI_DEVICE_ID_MELLANOX_BLUEFIELDVF:
531 : :
532 : 0 : priv->q_counters_hairpin = mlx5_devx_cmd_queue_counter_alloc(priv->sh->cdev->ctx);
533 [ # # ]: 0 : if (priv->q_counters_hairpin == NULL) {
534 : : /* Failed to allocate */
535 : 0 : DRV_LOG(DEBUG, "Some of the statistics of port %d "
536 : : "will not be available.", priv->dev_data->port_id);
537 : 0 : priv->q_counters_allocation_failure = 1;
538 : 0 : return 0;
539 : : }
540 : 0 : return priv->q_counters_hairpin->id;
541 : 0 : default:
542 : 0 : DRV_LOG(DEBUG, "Hairpin out of buffer counter "
543 : : "is not available on this NIC.");
544 : 0 : priv->q_counters_allocation_failure = 1;
545 : 0 : return 0;
546 : : }
547 : : }
548 : :
549 : : /**
550 : : * Create the Rx hairpin queue object.
551 : : *
552 : : * @param rxq
553 : : * Pointer to Rx queue.
554 : : *
555 : : * @return
556 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
557 : : */
558 : : static int
559 : 0 : mlx5_rxq_obj_hairpin_new(struct mlx5_rxq_priv *rxq)
560 : : {
561 : 0 : uint16_t idx = rxq->idx;
562 : 0 : struct mlx5_priv *priv = rxq->priv;
563 : 0 : struct mlx5_hca_attr *hca_attr __rte_unused = &priv->sh->cdev->config.hca_attr;
564 : 0 : struct mlx5_rxq_ctrl *rxq_ctrl = rxq->ctrl;
565 : 0 : struct mlx5_devx_create_rq_attr unlocked_attr = { 0 };
566 : 0 : struct mlx5_devx_create_rq_attr locked_attr = { 0 };
567 : 0 : struct mlx5_rxq_obj *tmpl = rxq_ctrl->obj;
568 : : uint32_t max_wq_data;
569 : :
570 : : MLX5_ASSERT(rxq != NULL && rxq->ctrl != NULL && tmpl != NULL);
571 : 0 : tmpl->rxq_ctrl = rxq_ctrl;
572 : 0 : unlocked_attr.hairpin = 1;
573 : 0 : max_wq_data =
574 : 0 : priv->sh->cdev->config.hca_attr.log_max_hairpin_wq_data_sz;
575 : : /* Jumbo frames > 9KB should be supported, and more packets. */
576 [ # # ]: 0 : if (priv->config.log_hp_size != (uint32_t)MLX5_ARG_UNSET) {
577 [ # # ]: 0 : if (priv->config.log_hp_size > max_wq_data) {
578 : 0 : DRV_LOG(ERR, "Total data size %u power of 2 is "
579 : : "too large for hairpin.",
580 : : priv->config.log_hp_size);
581 : 0 : rte_errno = ERANGE;
582 : 0 : return -rte_errno;
583 : : }
584 : 0 : unlocked_attr.wq_attr.log_hairpin_data_sz = priv->config.log_hp_size;
585 : : } else {
586 : 0 : unlocked_attr.wq_attr.log_hairpin_data_sz =
587 : : (max_wq_data < MLX5_HAIRPIN_JUMBO_LOG_SIZE) ?
588 : 0 : max_wq_data : MLX5_HAIRPIN_JUMBO_LOG_SIZE;
589 : : }
590 : : /* Set the packets number to the maximum value for performance. */
591 : 0 : unlocked_attr.wq_attr.log_hairpin_num_packets =
592 : 0 : unlocked_attr.wq_attr.log_hairpin_data_sz -
593 : : MLX5_HAIRPIN_QUEUE_STRIDE;
594 : :
595 : 0 : unlocked_attr.counter_set_id = mlx5_set_hairpin_queue_counter_obj(priv);
596 : :
597 : 0 : rxq_ctrl->rxq.delay_drop = priv->config.hp_delay_drop;
598 : 0 : unlocked_attr.delay_drop_en = priv->config.hp_delay_drop;
599 : 0 : unlocked_attr.hairpin_data_buffer_type =
600 : : MLX5_RQC_HAIRPIN_DATA_BUFFER_TYPE_UNLOCKED_INTERNAL_BUFFER;
601 [ # # ]: 0 : if (rxq->hairpin_conf.use_locked_device_memory) {
602 : : /*
603 : : * It is assumed that configuration is verified against capabilities
604 : : * during queue setup.
605 : : */
606 : : MLX5_ASSERT(hca_attr->hairpin_data_buffer_locked);
607 : : rte_memcpy(&locked_attr, &unlocked_attr, sizeof(locked_attr));
608 : 0 : locked_attr.hairpin_data_buffer_type =
609 : : MLX5_RQC_HAIRPIN_DATA_BUFFER_TYPE_LOCKED_INTERNAL_BUFFER;
610 : 0 : tmpl->rq = mlx5_devx_cmd_create_rq(priv->sh->cdev->ctx, &locked_attr,
611 : 0 : rxq_ctrl->socket);
612 [ # # # # ]: 0 : if (!tmpl->rq && rxq->hairpin_conf.force_memory) {
613 : 0 : DRV_LOG(ERR, "Port %u Rx hairpin queue %u can't create RQ object"
614 : : " with locked memory buffer",
615 : : priv->dev_data->port_id, idx);
616 : 0 : return -rte_errno;
617 [ # # # # ]: 0 : } else if (!tmpl->rq && !rxq->hairpin_conf.force_memory) {
618 : 0 : DRV_LOG(WARNING, "Port %u Rx hairpin queue %u can't create RQ object"
619 : : " with locked memory buffer. Falling back to unlocked"
620 : : " device memory.",
621 : : priv->dev_data->port_id, idx);
622 : 0 : rte_errno = 0;
623 : 0 : goto create_rq_unlocked;
624 : : }
625 : 0 : goto create_rq_set_state;
626 : : }
627 : :
628 : 0 : create_rq_unlocked:
629 : 0 : tmpl->rq = mlx5_devx_cmd_create_rq(priv->sh->cdev->ctx, &unlocked_attr,
630 : 0 : rxq_ctrl->socket);
631 [ # # ]: 0 : if (!tmpl->rq) {
632 : 0 : DRV_LOG(ERR,
633 : : "Port %u Rx hairpin queue %u can't create rq object.",
634 : : priv->dev_data->port_id, idx);
635 : 0 : rte_errno = errno;
636 : 0 : return -rte_errno;
637 : : }
638 : 0 : create_rq_set_state:
639 : 0 : priv->dev_data->rx_queue_state[idx] = RTE_ETH_QUEUE_STATE_HAIRPIN;
640 : 0 : return 0;
641 : : }
642 : :
643 : : /**
644 : : * Create the Rx queue DevX object.
645 : : *
646 : : * @param rxq
647 : : * Pointer to Rx queue.
648 : : *
649 : : * @return
650 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
651 : : */
652 : : static int
653 : 0 : mlx5_rxq_devx_obj_new(struct mlx5_rxq_priv *rxq)
654 : : {
655 : 0 : struct mlx5_priv *priv = rxq->priv;
656 : 0 : struct mlx5_rxq_ctrl *rxq_ctrl = rxq->ctrl;
657 : 0 : struct mlx5_rxq_data *rxq_data = &rxq_ctrl->rxq;
658 : 0 : struct mlx5_rxq_obj *tmpl = rxq_ctrl->obj;
659 : : int ret = 0;
660 : :
661 : : MLX5_ASSERT(rxq_data);
662 : : MLX5_ASSERT(tmpl);
663 [ # # ]: 0 : if (rxq_ctrl->is_hairpin)
664 : 0 : return mlx5_rxq_obj_hairpin_new(rxq);
665 : 0 : tmpl->rxq_ctrl = rxq_ctrl;
666 [ # # ]: 0 : if (rxq_ctrl->irq && !rxq_ctrl->started) {
667 : : int devx_ev_flag =
668 : : MLX5DV_DEVX_CREATE_EVENT_CHANNEL_FLAGS_OMIT_EV_DATA;
669 : :
670 : 0 : tmpl->devx_channel = mlx5_os_devx_create_event_channel
671 : 0 : (priv->sh->cdev->ctx,
672 : : devx_ev_flag);
673 [ # # ]: 0 : if (!tmpl->devx_channel) {
674 : 0 : rte_errno = errno;
675 : 0 : DRV_LOG(ERR, "Failed to create event channel %d.",
676 : : rte_errno);
677 : 0 : goto error;
678 : : }
679 : 0 : tmpl->fd = mlx5_os_get_devx_channel_fd(tmpl->devx_channel);
680 : : }
681 : : /* Create CQ using DevX API. */
682 : 0 : ret = mlx5_rxq_create_devx_cq_resources(rxq);
683 [ # # ]: 0 : if (ret) {
684 : 0 : DRV_LOG(ERR, "Failed to create CQ.");
685 : 0 : goto error;
686 : : }
687 [ # # # # ]: 0 : if (!rxq_data->shared || !rxq_ctrl->started)
688 : 0 : rxq_data->delay_drop = priv->config.std_delay_drop;
689 : : /* Create RQ using DevX API. */
690 : 0 : ret = mlx5_rxq_create_devx_rq_resources(rxq);
691 [ # # ]: 0 : if (ret) {
692 : 0 : DRV_LOG(ERR, "Port %u Rx queue %u RQ creation failure.",
693 : : priv->dev_data->port_id, rxq->idx);
694 : 0 : rte_errno = ENOMEM;
695 : 0 : goto error;
696 : : }
697 : : /* Change queue state to ready. */
698 : 0 : ret = mlx5_devx_modify_rq(rxq, MLX5_RXQ_MOD_RST2RDY);
699 [ # # ]: 0 : if (ret)
700 : 0 : goto error;
701 [ # # ]: 0 : if (!rxq_data->shared) {
702 : 0 : rxq_data->wqes = (void *)(uintptr_t)rxq->devx_rq.wq.umem_buf;
703 : 0 : rxq_data->rq_db = (uint32_t *)(uintptr_t)rxq->devx_rq.wq.db_rec;
704 [ # # ]: 0 : } else if (!rxq_ctrl->started) {
705 : 0 : rxq_data->wqes = (void *)(uintptr_t)tmpl->devx_rmp.wq.umem_buf;
706 : 0 : rxq_data->rq_db =
707 : 0 : (uint32_t *)(uintptr_t)tmpl->devx_rmp.wq.db_rec;
708 : : }
709 [ # # ]: 0 : if (!rxq_ctrl->started) {
710 : 0 : mlx5_rxq_initialize(rxq_data);
711 : 0 : rxq_ctrl->wqn = rxq->devx_rq.rq->id;
712 : : }
713 : 0 : priv->dev_data->rx_queue_state[rxq->idx] = RTE_ETH_QUEUE_STATE_STARTED;
714 : 0 : return 0;
715 : 0 : error:
716 : 0 : ret = rte_errno; /* Save rte_errno before cleanup. */
717 : 0 : mlx5_rxq_devx_obj_release(rxq);
718 : 0 : rte_errno = ret; /* Restore rte_errno. */
719 : 0 : return -rte_errno;
720 : : }
721 : :
722 : : /**
723 : : * Prepare RQT attribute structure for DevX RQT API.
724 : : *
725 : : * @param dev
726 : : * Pointer to Ethernet device.
727 : : * @param log_n
728 : : * Log of number of queues in the array.
729 : : * @param queues
730 : : * List of RX queue indices or NULL, in which case
731 : : * the attribute will be filled by drop queue ID.
732 : : * @param queues_n
733 : : * Size of @p queues array or 0 if it is NULL.
734 : : * @param ind_tbl
735 : : * DevX indirection table object.
736 : : *
737 : : * @return
738 : : * The RQT attr object initialized, NULL otherwise and rte_errno is set.
739 : : */
740 : : static struct mlx5_devx_rqt_attr *
741 : 0 : mlx5_devx_ind_table_create_rqt_attr(struct rte_eth_dev *dev,
742 : : const unsigned int log_n,
743 : : const uint16_t *queues,
744 : : const uint32_t queues_n)
745 : : {
746 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
747 : : struct mlx5_devx_rqt_attr *rqt_attr = NULL;
748 : 0 : const unsigned int rqt_n = 1 << log_n;
749 : : unsigned int i, j;
750 : :
751 : 0 : rqt_attr = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*rqt_attr) +
752 : : rqt_n * sizeof(uint32_t), 0, SOCKET_ID_ANY);
753 [ # # ]: 0 : if (!rqt_attr) {
754 : 0 : DRV_LOG(ERR, "Port %u cannot allocate RQT resources.",
755 : : dev->data->port_id);
756 : 0 : rte_errno = ENOMEM;
757 : 0 : return NULL;
758 : : }
759 : 0 : rqt_attr->rqt_max_size = priv->sh->dev_cap.ind_table_max_size;
760 : 0 : rqt_attr->rqt_actual_size = rqt_n;
761 [ # # ]: 0 : if (queues == NULL) {
762 [ # # ]: 0 : for (i = 0; i < rqt_n; i++)
763 : 0 : rqt_attr->rq_list[i] =
764 : 0 : priv->drop_queue.rxq->devx_rq.rq->id;
765 : : return rqt_attr;
766 : : }
767 [ # # ]: 0 : for (i = 0; i != queues_n; ++i) {
768 [ # # # # ]: 0 : if (mlx5_is_external_rxq(dev, queues[i])) {
769 : : struct mlx5_external_q *ext_rxq =
770 : 0 : mlx5_ext_rxq_get(dev, queues[i]);
771 : :
772 : 0 : rqt_attr->rq_list[i] = ext_rxq->hw_id;
773 : : } else {
774 : : struct mlx5_rxq_priv *rxq =
775 : 0 : mlx5_rxq_get(dev, queues[i]);
776 : :
777 : : MLX5_ASSERT(rxq != NULL);
778 [ # # ]: 0 : if (rxq->ctrl->is_hairpin)
779 : 0 : rqt_attr->rq_list[i] = rxq->ctrl->obj->rq->id;
780 : : else
781 : 0 : rqt_attr->rq_list[i] = rxq->devx_rq.rq->id;
782 : : }
783 : : }
784 : : MLX5_ASSERT(i > 0);
785 [ # # ]: 0 : for (j = 0; i != rqt_n; ++j, ++i)
786 : 0 : rqt_attr->rq_list[i] = rqt_attr->rq_list[j];
787 : : return rqt_attr;
788 : : }
789 : :
790 : : /**
791 : : * Create RQT using DevX API as a filed of indirection table.
792 : : *
793 : : * @param dev
794 : : * Pointer to Ethernet device.
795 : : * @param log_n
796 : : * Log of number of queues in the array.
797 : : * @param ind_tbl
798 : : * DevX indirection table object.
799 : : *
800 : : * @return
801 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
802 : : */
803 : : static int
804 : 0 : mlx5_devx_ind_table_new(struct rte_eth_dev *dev, const unsigned int log_n,
805 : : struct mlx5_ind_table_obj *ind_tbl)
806 : : {
807 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
808 : : struct mlx5_devx_rqt_attr *rqt_attr = NULL;
809 [ # # ]: 0 : const uint16_t *queues = dev->data->dev_started ? ind_tbl->queues :
810 : : NULL;
811 : :
812 : : MLX5_ASSERT(ind_tbl);
813 : 0 : rqt_attr = mlx5_devx_ind_table_create_rqt_attr(dev, log_n, queues,
814 : : ind_tbl->queues_n);
815 [ # # ]: 0 : if (!rqt_attr)
816 : 0 : return -rte_errno;
817 : 0 : ind_tbl->rqt = mlx5_devx_cmd_create_rqt(priv->sh->cdev->ctx, rqt_attr);
818 : 0 : mlx5_free(rqt_attr);
819 [ # # ]: 0 : if (!ind_tbl->rqt) {
820 : 0 : DRV_LOG(ERR, "Port %u cannot create DevX RQT.",
821 : : dev->data->port_id);
822 : 0 : rte_errno = errno;
823 : 0 : return -rte_errno;
824 : : }
825 : : return 0;
826 : : }
827 : :
828 : : /**
829 : : * Modify RQT using DevX API as a filed of indirection table.
830 : : *
831 : : * @param dev
832 : : * Pointer to Ethernet device.
833 : : * @param log_n
834 : : * Log of number of queues in the array.
835 : : * @param ind_tbl
836 : : * DevX indirection table object.
837 : : *
838 : : * @return
839 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
840 : : */
841 : : static int
842 : 0 : mlx5_devx_ind_table_modify(struct rte_eth_dev *dev, const unsigned int log_n,
843 : : const uint16_t *queues, const uint32_t queues_n,
844 : : struct mlx5_ind_table_obj *ind_tbl)
845 : : {
846 : : int ret = 0;
847 : : struct mlx5_devx_rqt_attr *rqt_attr = NULL;
848 : :
849 : : MLX5_ASSERT(ind_tbl);
850 : 0 : rqt_attr = mlx5_devx_ind_table_create_rqt_attr(dev, log_n,
851 : : queues,
852 : : queues_n);
853 [ # # ]: 0 : if (!rqt_attr)
854 : 0 : return -rte_errno;
855 : 0 : ret = mlx5_devx_cmd_modify_rqt(ind_tbl->rqt, rqt_attr);
856 : 0 : mlx5_free(rqt_attr);
857 [ # # ]: 0 : if (ret)
858 : 0 : DRV_LOG(ERR, "Port %u cannot modify DevX RQT.",
859 : : dev->data->port_id);
860 : : return ret;
861 : : }
862 : :
863 : : /**
864 : : * Destroy the DevX RQT object.
865 : : *
866 : : * @param ind_table
867 : : * Indirection table to release.
868 : : */
869 : : static void
870 : 0 : mlx5_devx_ind_table_destroy(struct mlx5_ind_table_obj *ind_tbl)
871 : : {
872 : 0 : claim_zero(mlx5_devx_cmd_destroy(ind_tbl->rqt));
873 : 0 : }
874 : :
875 : : /**
876 : : * Set TIR attribute struct with relevant input values.
877 : : *
878 : : * @param[in] dev
879 : : * Pointer to Ethernet device.
880 : : * @param[in] rss_key
881 : : * RSS key for the Rx hash queue.
882 : : * @param[in] hash_fields
883 : : * Verbs protocol hash field to make the RSS on.
884 : : * @param[in] ind_tbl
885 : : * Indirection table for TIR. If table queues array is NULL,
886 : : * a TIR for drop queue is assumed.
887 : : * @param[in] tunnel
888 : : * Tunnel type.
889 : : * @param[out] tir_attr
890 : : * Parameters structure for TIR creation/modification.
891 : : *
892 : : * @return
893 : : * The Verbs/DevX object initialised index, 0 otherwise and rte_errno is set.
894 : : */
895 : : static void
896 : 0 : mlx5_devx_tir_attr_set(struct rte_eth_dev *dev, const uint8_t *rss_key,
897 : : uint64_t hash_fields,
898 : : const struct mlx5_ind_table_obj *ind_tbl,
899 : : int tunnel, bool symmetric_hash_function,
900 : : struct mlx5_devx_tir_attr *tir_attr)
901 : : {
902 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
903 : : bool is_hairpin;
904 : : bool lro = false;
905 : : uint32_t i;
906 : :
907 : : /* NULL queues designate drop queue. */
908 [ # # ]: 0 : if (ind_tbl->queues == NULL) {
909 : 0 : is_hairpin = priv->drop_queue.rxq->ctrl->is_hairpin;
910 [ # # # # ]: 0 : } else if (mlx5_is_external_rxq(dev, ind_tbl->queues[0])) {
911 : : /* External RxQ supports neither Hairpin nor LRO. */
912 : : is_hairpin = false;
913 : : } else {
914 : 0 : is_hairpin = mlx5_rxq_is_hairpin(dev, ind_tbl->queues[0]);
915 : : lro = true;
916 : : /* Enable TIR LRO only if all the queues were configured for. */
917 [ # # ]: 0 : for (i = 0; i < ind_tbl->queues_n; ++i) {
918 : : struct mlx5_rxq_data *rxq_i =
919 : 0 : mlx5_rxq_data_get(dev, ind_tbl->queues[i]);
920 : :
921 [ # # # # ]: 0 : if (rxq_i != NULL && !rxq_i->lro) {
922 : : lro = false;
923 : : break;
924 : : }
925 : : }
926 : : }
927 : : memset(tir_attr, 0, sizeof(*tir_attr));
928 : 0 : tir_attr->disp_type = MLX5_TIRC_DISP_TYPE_INDIRECT;
929 : 0 : tir_attr->rx_hash_fn = MLX5_RX_HASH_FN_TOEPLITZ;
930 : 0 : tir_attr->tunneled_offload_en = !!tunnel;
931 : 0 : tir_attr->rx_hash_symmetric = symmetric_hash_function;
932 : : /* If needed, translate hash_fields bitmap to PRM format. */
933 [ # # ]: 0 : if (hash_fields) {
934 : : struct mlx5_rx_hash_field_select *rx_hash_field_select =
935 : : #ifdef HAVE_IBV_DEVICE_TUNNEL_SUPPORT
936 : 0 : hash_fields & IBV_RX_HASH_INNER ?
937 [ # # ]: 0 : &tir_attr->rx_hash_field_selector_inner :
938 : : #endif
939 : : &tir_attr->rx_hash_field_selector_outer;
940 : : /* 1 bit: 0: IPv4, 1: IPv6. */
941 : 0 : rx_hash_field_select->l3_prot_type =
942 : 0 : !!(hash_fields & MLX5_IPV6_IBV_RX_HASH);
943 : : /* 1 bit: 0: TCP, 1: UDP. */
944 : 0 : rx_hash_field_select->l4_prot_type =
945 : 0 : !!(hash_fields & MLX5_UDP_IBV_RX_HASH);
946 : : /* Bitmask which sets which fields to use in RX Hash. */
947 : 0 : rx_hash_field_select->selected_fields =
948 : 0 : ((!!(hash_fields & MLX5_L3_SRC_IBV_RX_HASH)) <<
949 : 0 : MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_SRC_IP) |
950 [ # # ]: 0 : (!!(hash_fields & MLX5_L3_DST_IBV_RX_HASH)) <<
951 : 0 : MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_DST_IP |
952 [ # # ]: 0 : (!!(hash_fields & MLX5_L4_SRC_IBV_RX_HASH)) <<
953 : 0 : MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_SPORT |
954 [ # # ]: 0 : (!!(hash_fields & MLX5_L4_DST_IBV_RX_HASH)) <<
955 : 0 : MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_L4_DPORT |
956 : 0 : (!!(hash_fields & IBV_RX_HASH_IPSEC_SPI)) <<
957 : : MLX5_RX_HASH_FIELD_SELECT_SELECTED_FIELDS_IPSEC_SPI;
958 : : }
959 [ # # ]: 0 : if (is_hairpin)
960 : 0 : tir_attr->transport_domain = priv->sh->td->id;
961 : : else
962 : 0 : tir_attr->transport_domain = priv->sh->tdn;
963 [ # # ]: 0 : memcpy(tir_attr->rx_hash_toeplitz_key, rss_key, MLX5_RSS_HASH_KEY_LEN);
964 : 0 : tir_attr->indirect_table = ind_tbl->rqt->id;
965 [ # # ]: 0 : if (dev->data->dev_conf.lpbk_mode)
966 : 0 : tir_attr->self_lb_block = MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST;
967 [ # # ]: 0 : if (lro) {
968 : : MLX5_ASSERT(priv->sh->config.lro_allowed);
969 : 0 : tir_attr->lro_timeout_period_usecs = priv->config.lro_timeout;
970 : 0 : tir_attr->lro_max_msg_sz =
971 : 0 : priv->max_lro_msg_size / MLX5_LRO_SEG_CHUNK_SIZE;
972 : 0 : tir_attr->lro_enable_mask =
973 : : MLX5_TIRC_LRO_ENABLE_MASK_IPV4_LRO |
974 : : MLX5_TIRC_LRO_ENABLE_MASK_IPV6_LRO;
975 : : }
976 : 0 : }
977 : :
978 : : /**
979 : : * Create an Rx Hash queue.
980 : : *
981 : : * @param dev
982 : : * Pointer to Ethernet device.
983 : : * @param hrxq
984 : : * Pointer to Rx Hash queue.
985 : : * @param tunnel
986 : : * Tunnel type.
987 : : *
988 : : * @return
989 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
990 : : */
991 : : static int
992 : 0 : mlx5_devx_hrxq_new(struct rte_eth_dev *dev, struct mlx5_hrxq *hrxq,
993 : : int tunnel __rte_unused)
994 : : {
995 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
996 : 0 : struct mlx5_devx_tir_attr tir_attr = {0};
997 : : int err;
998 : :
999 : 0 : mlx5_devx_tir_attr_set(dev, hrxq->rss_key, hrxq->hash_fields,
1000 : 0 : hrxq->ind_table, tunnel, hrxq->symmetric_hash_function,
1001 : : &tir_attr);
1002 : 0 : hrxq->tir = mlx5_devx_cmd_create_tir(priv->sh->cdev->ctx, &tir_attr);
1003 [ # # ]: 0 : if (!hrxq->tir) {
1004 : 0 : DRV_LOG(ERR, "Port %u cannot create DevX TIR.",
1005 : : dev->data->port_id);
1006 : 0 : rte_errno = errno;
1007 : 0 : goto error;
1008 : : }
1009 : : #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
1010 : : #ifdef HAVE_MLX5_HWS_SUPPORT
1011 [ # # ]: 0 : if (hrxq->hws_flags) {
1012 : 0 : hrxq->action = mlx5dr_action_create_dest_tir
1013 : : (priv->dr_ctx,
1014 : : (struct mlx5dr_devx_obj *)hrxq->tir, hrxq->hws_flags, true);
1015 [ # # ]: 0 : if (!hrxq->action)
1016 : 0 : goto error;
1017 : : return 0;
1018 : : }
1019 : : #endif
1020 : : if (mlx5_flow_os_create_flow_action_dest_devx_tir(hrxq->tir,
1021 : : &hrxq->action)) {
1022 : 0 : rte_errno = errno;
1023 : 0 : goto error;
1024 : : }
1025 : : #endif
1026 : : return 0;
1027 : 0 : error:
1028 : 0 : err = rte_errno; /* Save rte_errno before cleanup. */
1029 [ # # ]: 0 : if (hrxq->tir)
1030 : 0 : claim_zero(mlx5_devx_cmd_destroy(hrxq->tir));
1031 : 0 : rte_errno = err; /* Restore rte_errno. */
1032 : 0 : return -rte_errno;
1033 : : }
1034 : :
1035 : : /**
1036 : : * Destroy a DevX TIR object.
1037 : : *
1038 : : * @param hrxq
1039 : : * Hash Rx queue to release its tir.
1040 : : */
1041 : : static void
1042 : 0 : mlx5_devx_tir_destroy(struct mlx5_hrxq *hrxq)
1043 : : {
1044 : 0 : claim_zero(mlx5_devx_cmd_destroy(hrxq->tir));
1045 : 0 : }
1046 : :
1047 : : /**
1048 : : * Modify an Rx Hash queue configuration.
1049 : : *
1050 : : * @param dev
1051 : : * Pointer to Ethernet device.
1052 : : * @param hrxq
1053 : : * Hash Rx queue to modify.
1054 : : * @param rss_key
1055 : : * RSS key for the Rx hash queue.
1056 : : * @param hash_fields
1057 : : * Verbs protocol hash field to make the RSS on.
1058 : : * @param[in] ind_tbl
1059 : : * Indirection table for TIR.
1060 : : *
1061 : : * @return
1062 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1063 : : */
1064 : : static int
1065 : 0 : mlx5_devx_hrxq_modify(struct rte_eth_dev *dev, struct mlx5_hrxq *hrxq,
1066 : : const uint8_t *rss_key,
1067 : : uint64_t hash_fields,
1068 : : bool symmetric_hash_function,
1069 : : const struct mlx5_ind_table_obj *ind_tbl)
1070 : : {
1071 : 0 : struct mlx5_devx_modify_tir_attr modify_tir = {0};
1072 : :
1073 : : /*
1074 : : * untested for modification fields:
1075 : : * - rx_hash_fn set hard-coded in hrxq_new(),
1076 : : * - lro_xxx not set after rxq setup
1077 : : */
1078 [ # # ]: 0 : if (ind_tbl != hrxq->ind_table)
1079 : 0 : modify_tir.modify_bitmask |=
1080 : : MLX5_MODIFY_TIR_IN_MODIFY_BITMASK_INDIRECT_TABLE;
1081 [ # # ]: 0 : if (hash_fields != hrxq->hash_fields ||
1082 [ # # ]: 0 : symmetric_hash_function != hrxq->symmetric_hash_function ||
1083 [ # # ]: 0 : memcmp(hrxq->rss_key, rss_key, MLX5_RSS_HASH_KEY_LEN))
1084 : 0 : modify_tir.modify_bitmask |=
1085 : : MLX5_MODIFY_TIR_IN_MODIFY_BITMASK_HASH;
1086 : 0 : mlx5_devx_tir_attr_set(dev, rss_key, hash_fields, ind_tbl,
1087 : : 0, /* N/A - tunnel modification unsupported */
1088 : : symmetric_hash_function,
1089 : : &modify_tir.tir);
1090 : 0 : modify_tir.tirn = hrxq->tir->id;
1091 [ # # ]: 0 : if (mlx5_devx_cmd_modify_tir(hrxq->tir, &modify_tir)) {
1092 : 0 : DRV_LOG(ERR, "port %u cannot modify DevX TIR",
1093 : : dev->data->port_id);
1094 : 0 : rte_errno = errno;
1095 : 0 : return -rte_errno;
1096 : : }
1097 : : return 0;
1098 : : }
1099 : :
1100 : : /**
1101 : : * Create a DevX drop Rx queue.
1102 : : *
1103 : : * @param dev
1104 : : * Pointer to Ethernet device.
1105 : : *
1106 : : * @return
1107 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1108 : : */
1109 : : static int
1110 : 0 : mlx5_rxq_devx_obj_drop_create(struct rte_eth_dev *dev)
1111 : : {
1112 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1113 : 0 : int socket_id = dev->device->numa_node;
1114 : : struct mlx5_rxq_priv *rxq;
1115 : : struct mlx5_rxq_ctrl *rxq_ctrl = NULL;
1116 : : struct mlx5_rxq_obj *rxq_obj = NULL;
1117 : : int ret;
1118 : :
1119 : : /*
1120 : : * Initialize dummy control structures.
1121 : : * They are required to hold pointers for cleanup
1122 : : * and are only accessible via drop queue DevX objects.
1123 : : */
1124 : 0 : rxq = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*rxq), 0, socket_id);
1125 [ # # ]: 0 : if (rxq == NULL) {
1126 : 0 : DRV_LOG(ERR, "Port %u could not allocate drop queue private",
1127 : : dev->data->port_id);
1128 : 0 : rte_errno = ENOMEM;
1129 : 0 : goto error;
1130 : : }
1131 : 0 : rxq_ctrl = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*rxq_ctrl),
1132 : : 0, socket_id);
1133 [ # # ]: 0 : if (rxq_ctrl == NULL) {
1134 : 0 : DRV_LOG(ERR, "Port %u could not allocate drop queue control",
1135 : : dev->data->port_id);
1136 : 0 : rte_errno = ENOMEM;
1137 : 0 : goto error;
1138 : : }
1139 : 0 : rxq_obj = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*rxq_obj), 0, socket_id);
1140 [ # # ]: 0 : if (rxq_obj == NULL) {
1141 : 0 : DRV_LOG(ERR, "Port %u could not allocate drop queue object",
1142 : : dev->data->port_id);
1143 : 0 : rte_errno = ENOMEM;
1144 : 0 : goto error;
1145 : : }
1146 : : /* set the CPU socket ID where the rxq_ctrl was allocated */
1147 : 0 : rxq_ctrl->socket = socket_id;
1148 : 0 : rxq_obj->rxq_ctrl = rxq_ctrl;
1149 : 0 : rxq_ctrl->is_hairpin = false;
1150 : 0 : rxq_ctrl->sh = priv->sh;
1151 : 0 : rxq_ctrl->obj = rxq_obj;
1152 : 0 : rxq->ctrl = rxq_ctrl;
1153 : 0 : rxq->priv = priv;
1154 [ # # ]: 0 : LIST_INSERT_HEAD(&rxq_ctrl->owners, rxq, owner_entry);
1155 : : /* Create CQ using DevX API. */
1156 : 0 : ret = mlx5_rxq_create_devx_cq_resources(rxq);
1157 [ # # ]: 0 : if (ret != 0) {
1158 : 0 : DRV_LOG(ERR, "Port %u drop queue CQ creation failed.",
1159 : : dev->data->port_id);
1160 : 0 : goto error;
1161 : : }
1162 : 0 : rxq_ctrl->rxq.delay_drop = 0;
1163 : : /* Create RQ using DevX API. */
1164 : 0 : ret = mlx5_rxq_create_devx_rq_resources(rxq);
1165 [ # # ]: 0 : if (ret != 0) {
1166 : 0 : DRV_LOG(ERR, "Port %u drop queue RQ creation failed.",
1167 : : dev->data->port_id);
1168 : 0 : rte_errno = ENOMEM;
1169 : 0 : goto error;
1170 : : }
1171 : : /* Change queue state to ready. */
1172 : 0 : ret = mlx5_devx_modify_rq(rxq, MLX5_RXQ_MOD_RST2RDY);
1173 [ # # ]: 0 : if (ret != 0)
1174 : 0 : goto error;
1175 : : /* Initialize drop queue. */
1176 : 0 : priv->drop_queue.rxq = rxq;
1177 : 0 : return 0;
1178 : 0 : error:
1179 : 0 : ret = rte_errno; /* Save rte_errno before cleanup. */
1180 [ # # # # ]: 0 : if (rxq != NULL && rxq->devx_rq.rq != NULL)
1181 : 0 : mlx5_devx_rq_destroy(&rxq->devx_rq);
1182 [ # # ]: 0 : if (rxq_obj != NULL) {
1183 [ # # ]: 0 : if (rxq_obj->cq_obj.cq != NULL)
1184 : 0 : mlx5_devx_cq_destroy(&rxq_obj->cq_obj);
1185 [ # # ]: 0 : if (rxq_obj->devx_channel)
1186 : : mlx5_os_devx_destroy_event_channel
1187 : : (rxq_obj->devx_channel);
1188 : 0 : mlx5_free(rxq_obj);
1189 : : }
1190 [ # # ]: 0 : if (rxq_ctrl != NULL)
1191 : 0 : mlx5_free(rxq_ctrl);
1192 [ # # ]: 0 : if (rxq != NULL)
1193 : 0 : mlx5_free(rxq);
1194 : 0 : rte_errno = ret; /* Restore rte_errno. */
1195 : 0 : return -rte_errno;
1196 : : }
1197 : :
1198 : : /**
1199 : : * Release drop Rx queue resources.
1200 : : *
1201 : : * @param dev
1202 : : * Pointer to Ethernet device.
1203 : : */
1204 : : static void
1205 : 0 : mlx5_rxq_devx_obj_drop_release(struct rte_eth_dev *dev)
1206 : : {
1207 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1208 : 0 : struct mlx5_rxq_priv *rxq = priv->drop_queue.rxq;
1209 : 0 : struct mlx5_rxq_ctrl *rxq_ctrl = rxq->ctrl;
1210 : :
1211 : 0 : mlx5_rxq_devx_obj_release(rxq);
1212 : 0 : mlx5_free(rxq_ctrl->obj);
1213 : 0 : mlx5_free(rxq_ctrl);
1214 : 0 : mlx5_free(rxq);
1215 : 0 : priv->drop_queue.rxq = NULL;
1216 : 0 : }
1217 : :
1218 : : /**
1219 : : * Release a drop hash Rx queue.
1220 : : *
1221 : : * @param dev
1222 : : * Pointer to Ethernet device.
1223 : : */
1224 : : static void
1225 : 0 : mlx5_devx_drop_action_destroy(struct rte_eth_dev *dev)
1226 : : {
1227 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1228 : 0 : struct mlx5_hrxq *hrxq = priv->drop_queue.hrxq;
1229 : :
1230 : : #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
1231 [ # # ]: 0 : if (hrxq->action != NULL)
1232 : : mlx5_flow_os_destroy_flow_action(hrxq->action);
1233 : : #endif
1234 [ # # ]: 0 : if (hrxq->tir != NULL)
1235 : : mlx5_devx_tir_destroy(hrxq);
1236 [ # # ]: 0 : if (hrxq->ind_table->ind_table != NULL)
1237 : : mlx5_devx_ind_table_destroy(hrxq->ind_table);
1238 [ # # ]: 0 : if (priv->drop_queue.rxq->devx_rq.rq != NULL)
1239 : 0 : mlx5_rxq_devx_obj_drop_release(dev);
1240 : 0 : }
1241 : :
1242 : : /**
1243 : : * Create a DevX drop action for Rx Hash queue.
1244 : : *
1245 : : * @param dev
1246 : : * Pointer to Ethernet device.
1247 : : *
1248 : : * @return
1249 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1250 : : */
1251 : : static int
1252 : 0 : mlx5_devx_drop_action_create(struct rte_eth_dev *dev)
1253 : : {
1254 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1255 : 0 : struct mlx5_hrxq *hrxq = priv->drop_queue.hrxq;
1256 : : int ret;
1257 : :
1258 : 0 : ret = mlx5_rxq_devx_obj_drop_create(dev);
1259 [ # # ]: 0 : if (ret != 0) {
1260 : 0 : DRV_LOG(ERR, "Cannot create drop RX queue");
1261 : 0 : return ret;
1262 : : }
1263 [ # # ]: 0 : if (priv->sh->config.dv_flow_en == 2)
1264 : : return 0;
1265 : : /* hrxq->ind_table queues are NULL, drop RX queue ID will be used */
1266 : 0 : ret = mlx5_devx_ind_table_new(dev, 0, hrxq->ind_table);
1267 [ # # ]: 0 : if (ret != 0) {
1268 : 0 : DRV_LOG(ERR, "Cannot create drop hash RX queue indirection table");
1269 : 0 : goto error;
1270 : : }
1271 : 0 : ret = mlx5_devx_hrxq_new(dev, hrxq, /* tunnel */ false);
1272 [ # # ]: 0 : if (ret != 0) {
1273 : 0 : DRV_LOG(ERR, "Cannot create drop hash RX queue");
1274 : 0 : goto error;
1275 : : }
1276 : : return 0;
1277 : 0 : error:
1278 : 0 : mlx5_devx_drop_action_destroy(dev);
1279 : 0 : return ret;
1280 : : }
1281 : :
1282 : : /**
1283 : : * Select TXQ TIS number.
1284 : : *
1285 : : * @param dev
1286 : : * Pointer to Ethernet device.
1287 : : * @param queue_idx
1288 : : * Queue index in DPDK Tx queue array.
1289 : : *
1290 : : * @return
1291 : : * > 0 on success, a negative errno value otherwise.
1292 : : */
1293 : : static uint32_t
1294 : 0 : mlx5_get_txq_tis_num(struct rte_eth_dev *dev, uint16_t queue_idx)
1295 : : {
1296 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1297 : 0 : struct mlx5_txq_data *txq_data = (*priv->txqs)[queue_idx];
1298 : : int tis_idx = 0;
1299 : :
1300 [ # # ]: 0 : if (priv->sh->bond.n_port) {
1301 [ # # ]: 0 : if (txq_data->tx_aggr_affinity) {
1302 : 0 : tis_idx = txq_data->tx_aggr_affinity;
1303 [ # # ]: 0 : } else if (priv->sh->lag.affinity_mode == MLX5_LAG_MODE_TIS) {
1304 : 0 : tis_idx = (priv->lag_affinity_idx + queue_idx) %
1305 : 0 : priv->sh->bond.n_port + 1;
1306 : 0 : DRV_LOG(INFO, "port %d txq %d gets affinity %d and maps to PF %d.",
1307 : : dev->data->port_id, queue_idx, tis_idx,
1308 : : priv->sh->lag.tx_remap_affinity[tis_idx - 1]);
1309 : : }
1310 : : }
1311 : : MLX5_ASSERT(priv->sh->tis[tis_idx]);
1312 : 0 : return priv->sh->tis[tis_idx]->id;
1313 : : }
1314 : :
1315 : : /**
1316 : : * Create the Tx hairpin queue object.
1317 : : *
1318 : : * @param dev
1319 : : * Pointer to Ethernet device.
1320 : : * @param idx
1321 : : * Queue index in DPDK Tx queue array.
1322 : : *
1323 : : * @return
1324 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1325 : : */
1326 : : static int
1327 : 0 : mlx5_txq_obj_hairpin_new(struct rte_eth_dev *dev, uint16_t idx)
1328 : : {
1329 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1330 : 0 : struct mlx5_hca_attr *hca_attr = &priv->sh->cdev->config.hca_attr;
1331 : 0 : struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
1332 : : struct mlx5_txq_ctrl *txq_ctrl =
1333 : 0 : container_of(txq_data, struct mlx5_txq_ctrl, txq);
1334 : 0 : struct mlx5_devx_create_sq_attr dev_mem_attr = { 0 };
1335 : 0 : struct mlx5_devx_create_sq_attr host_mem_attr = { 0 };
1336 : 0 : struct mlx5_txq_obj *tmpl = txq_ctrl->obj;
1337 : : void *umem_buf = NULL;
1338 : : void *umem_obj = NULL;
1339 : : uint32_t max_wq_data;
1340 : :
1341 : : MLX5_ASSERT(txq_data);
1342 : : MLX5_ASSERT(tmpl);
1343 : 0 : tmpl->txq_ctrl = txq_ctrl;
1344 : 0 : dev_mem_attr.hairpin = 1;
1345 : 0 : dev_mem_attr.tis_lst_sz = 1;
1346 : 0 : dev_mem_attr.tis_num = mlx5_get_txq_tis_num(dev, idx);
1347 : 0 : max_wq_data =
1348 : 0 : priv->sh->cdev->config.hca_attr.log_max_hairpin_wq_data_sz;
1349 : : /* Jumbo frames > 9KB should be supported, and more packets. */
1350 [ # # ]: 0 : if (priv->config.log_hp_size != (uint32_t)MLX5_ARG_UNSET) {
1351 [ # # ]: 0 : if (priv->config.log_hp_size > max_wq_data) {
1352 : 0 : DRV_LOG(ERR, "Total data size %u power of 2 is "
1353 : : "too large for hairpin.",
1354 : : priv->config.log_hp_size);
1355 : 0 : rte_errno = ERANGE;
1356 : 0 : return -rte_errno;
1357 : : }
1358 : 0 : dev_mem_attr.wq_attr.log_hairpin_data_sz = priv->config.log_hp_size;
1359 : : } else {
1360 : 0 : dev_mem_attr.wq_attr.log_hairpin_data_sz =
1361 : : (max_wq_data < MLX5_HAIRPIN_JUMBO_LOG_SIZE) ?
1362 : 0 : max_wq_data : MLX5_HAIRPIN_JUMBO_LOG_SIZE;
1363 : : }
1364 : : /* Set the packets number to the maximum value for performance. */
1365 : 0 : dev_mem_attr.wq_attr.log_hairpin_num_packets =
1366 : 0 : dev_mem_attr.wq_attr.log_hairpin_data_sz -
1367 : : MLX5_HAIRPIN_QUEUE_STRIDE;
1368 : 0 : dev_mem_attr.hairpin_wq_buffer_type = MLX5_SQC_HAIRPIN_WQ_BUFFER_TYPE_INTERNAL_BUFFER;
1369 [ # # ]: 0 : if (txq_ctrl->hairpin_conf.use_rte_memory) {
1370 : : uint32_t umem_size;
1371 : : uint32_t umem_dbrec;
1372 : 0 : size_t alignment = MLX5_WQE_BUF_ALIGNMENT;
1373 : :
1374 [ # # ]: 0 : if (alignment == (size_t)-1) {
1375 : 0 : DRV_LOG(ERR, "Failed to get WQE buf alignment.");
1376 : 0 : rte_errno = ENOMEM;
1377 : 0 : return -rte_errno;
1378 : : }
1379 : : /*
1380 : : * It is assumed that configuration is verified against capabilities
1381 : : * during queue setup.
1382 : : */
1383 : : MLX5_ASSERT(hca_attr->hairpin_sq_wq_in_host_mem);
1384 : : MLX5_ASSERT(hca_attr->hairpin_sq_wqe_bb_size > 0);
1385 : : rte_memcpy(&host_mem_attr, &dev_mem_attr, sizeof(host_mem_attr));
1386 : 0 : umem_size = MLX5_WQE_SIZE *
1387 : 0 : RTE_BIT32(host_mem_attr.wq_attr.log_hairpin_num_packets);
1388 : 0 : umem_dbrec = RTE_ALIGN(umem_size, MLX5_DBR_SIZE);
1389 : 0 : umem_size += MLX5_DBR_SIZE;
1390 : 0 : umem_buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, umem_size,
1391 : 0 : alignment, priv->sh->numa_node);
1392 [ # # # # ]: 0 : if (umem_buf == NULL && txq_ctrl->hairpin_conf.force_memory) {
1393 : 0 : DRV_LOG(ERR, "Failed to allocate memory for hairpin TX queue");
1394 : 0 : rte_errno = ENOMEM;
1395 : 0 : return -rte_errno;
1396 [ # # # # ]: 0 : } else if (umem_buf == NULL && !txq_ctrl->hairpin_conf.force_memory) {
1397 : 0 : DRV_LOG(WARNING, "Failed to allocate memory for hairpin TX queue."
1398 : : " Falling back to TX queue located on the device.");
1399 : 0 : goto create_sq_on_device;
1400 : : }
1401 : 0 : umem_obj = mlx5_os_umem_reg(priv->sh->cdev->ctx,
1402 : : (void *)(uintptr_t)umem_buf,
1403 : : umem_size,
1404 : : IBV_ACCESS_LOCAL_WRITE);
1405 [ # # # # ]: 0 : if (umem_obj == NULL && txq_ctrl->hairpin_conf.force_memory) {
1406 : 0 : DRV_LOG(ERR, "Failed to register UMEM for hairpin TX queue");
1407 : 0 : mlx5_free(umem_buf);
1408 : 0 : return -rte_errno;
1409 [ # # # # ]: 0 : } else if (umem_obj == NULL && !txq_ctrl->hairpin_conf.force_memory) {
1410 : 0 : DRV_LOG(WARNING, "Failed to register UMEM for hairpin TX queue."
1411 : : " Falling back to TX queue located on the device.");
1412 : 0 : rte_errno = 0;
1413 : 0 : mlx5_free(umem_buf);
1414 : 0 : goto create_sq_on_device;
1415 : : }
1416 : 0 : host_mem_attr.wq_attr.wq_type = MLX5_WQ_TYPE_CYCLIC;
1417 [ # # ]: 0 : host_mem_attr.wq_attr.wq_umem_valid = 1;
1418 : 0 : host_mem_attr.wq_attr.wq_umem_id = mlx5_os_get_umem_id(umem_obj);
1419 : 0 : host_mem_attr.wq_attr.wq_umem_offset = 0;
1420 : 0 : host_mem_attr.wq_attr.dbr_umem_valid = 1;
1421 : 0 : host_mem_attr.wq_attr.dbr_umem_id = host_mem_attr.wq_attr.wq_umem_id;
1422 : 0 : host_mem_attr.wq_attr.dbr_addr = umem_dbrec;
1423 : 0 : host_mem_attr.wq_attr.log_wq_stride = rte_log2_u32(MLX5_WQE_SIZE);
1424 : 0 : host_mem_attr.wq_attr.log_wq_sz =
1425 : 0 : host_mem_attr.wq_attr.log_hairpin_num_packets *
1426 : 0 : hca_attr->hairpin_sq_wqe_bb_size;
1427 : 0 : host_mem_attr.wq_attr.log_wq_pg_sz = MLX5_LOG_PAGE_SIZE;
1428 : 0 : host_mem_attr.hairpin_wq_buffer_type = MLX5_SQC_HAIRPIN_WQ_BUFFER_TYPE_HOST_MEMORY;
1429 : 0 : tmpl->sq = mlx5_devx_cmd_create_sq(priv->sh->cdev->ctx, &host_mem_attr);
1430 [ # # # # ]: 0 : if (!tmpl->sq && txq_ctrl->hairpin_conf.force_memory) {
1431 : 0 : DRV_LOG(ERR,
1432 : : "Port %u tx hairpin queue %u can't create SQ object.",
1433 : : dev->data->port_id, idx);
1434 : : claim_zero(mlx5_os_umem_dereg(umem_obj));
1435 : 0 : mlx5_free(umem_buf);
1436 : 0 : return -rte_errno;
1437 [ # # # # ]: 0 : } else if (!tmpl->sq && !txq_ctrl->hairpin_conf.force_memory) {
1438 : 0 : DRV_LOG(WARNING,
1439 : : "Port %u tx hairpin queue %u failed to allocate SQ object"
1440 : : " using host memory. Falling back to TX queue located"
1441 : : " on the device",
1442 : : dev->data->port_id, idx);
1443 : 0 : rte_errno = 0;
1444 : : claim_zero(mlx5_os_umem_dereg(umem_obj));
1445 : 0 : mlx5_free(umem_buf);
1446 : 0 : goto create_sq_on_device;
1447 : : }
1448 : 0 : tmpl->umem_buf_wq_buffer = umem_buf;
1449 : 0 : tmpl->umem_obj_wq_buffer = umem_obj;
1450 : 0 : return 0;
1451 : : }
1452 : :
1453 : 0 : create_sq_on_device:
1454 : 0 : tmpl->sq = mlx5_devx_cmd_create_sq(priv->sh->cdev->ctx, &dev_mem_attr);
1455 [ # # ]: 0 : if (!tmpl->sq) {
1456 : 0 : DRV_LOG(ERR,
1457 : : "Port %u tx hairpin queue %u can't create SQ object.",
1458 : : dev->data->port_id, idx);
1459 : 0 : rte_errno = errno;
1460 : 0 : return -rte_errno;
1461 : : }
1462 : : return 0;
1463 : : }
1464 : :
1465 : : #if defined(HAVE_MLX5DV_DEVX_UAR_OFFSET) || !defined(HAVE_INFINIBAND_VERBS_H)
1466 : : /**
1467 : : * Destroy the Tx queue DevX object.
1468 : : *
1469 : : * @param txq_obj
1470 : : * Txq object to destroy.
1471 : : */
1472 : : static void
1473 : 0 : mlx5_txq_release_devx_resources(struct mlx5_txq_obj *txq_obj)
1474 : : {
1475 : 0 : mlx5_devx_sq_destroy(&txq_obj->sq_obj);
1476 : : memset(&txq_obj->sq_obj, 0, sizeof(txq_obj->sq_obj));
1477 : 0 : mlx5_devx_cq_destroy(&txq_obj->cq_obj);
1478 : : memset(&txq_obj->cq_obj, 0, sizeof(txq_obj->cq_obj));
1479 : 0 : }
1480 : :
1481 : : /**
1482 : : * Create a SQ object and its resources using DevX.
1483 : : *
1484 : : * @param dev
1485 : : * Pointer to Ethernet device.
1486 : : * @param idx
1487 : : * Queue index in DPDK Tx queue array.
1488 : : * @param[in] log_desc_n
1489 : : * Log of number of descriptors in queue.
1490 : : *
1491 : : * @return
1492 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1493 : : */
1494 : : static int
1495 : 0 : mlx5_txq_create_devx_sq_resources(struct rte_eth_dev *dev, uint16_t idx,
1496 : : uint16_t log_desc_n)
1497 : : {
1498 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1499 : 0 : struct mlx5_common_device *cdev = priv->sh->cdev;
1500 : : struct mlx5_uar *uar = &priv->sh->tx_uar;
1501 : 0 : struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
1502 : : struct mlx5_txq_ctrl *txq_ctrl =
1503 : 0 : container_of(txq_data, struct mlx5_txq_ctrl, txq);
1504 : 0 : struct mlx5_txq_obj *txq_obj = txq_ctrl->obj;
1505 : 0 : struct mlx5_devx_create_sq_attr sq_attr = {
1506 : : .flush_in_error_en = 1,
1507 : 0 : .allow_multi_pkt_send_wqe = !!priv->config.mps,
1508 : 0 : .min_wqe_inline_mode = cdev->config.hca_attr.vport_inline_mode,
1509 : 0 : .allow_swp = !!priv->sh->dev_cap.swp,
1510 : 0 : .cqn = txq_obj->cq_obj.cq->id,
1511 : : .tis_lst_sz = 1,
1512 : : .wq_attr = (struct mlx5_devx_wq_attr){
1513 : 0 : .pd = cdev->pdn,
1514 : 0 : .uar_page = mlx5_os_get_devx_uar_page_id(uar->obj),
1515 : : },
1516 : : .ts_format =
1517 : 0 : mlx5_ts_format_conv(cdev->config.hca_attr.sq_ts_format),
1518 [ # # ]: 0 : .tis_num = mlx5_get_txq_tis_num(dev, idx),
1519 : : };
1520 : :
1521 : : /* Create Send Queue object with DevX. */
1522 : 0 : return mlx5_devx_sq_create(cdev->ctx, &txq_obj->sq_obj,
1523 : 0 : log_desc_n, &sq_attr, priv->sh->numa_node);
1524 : : }
1525 : : #endif
1526 : :
1527 : : /**
1528 : : * Create the Tx queue DevX object.
1529 : : *
1530 : : * @param dev
1531 : : * Pointer to Ethernet device.
1532 : : * @param idx
1533 : : * Queue index in DPDK Tx queue array.
1534 : : *
1535 : : * @return
1536 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1537 : : */
1538 : : int
1539 : 0 : mlx5_txq_devx_obj_new(struct rte_eth_dev *dev, uint16_t idx)
1540 : : {
1541 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1542 : 0 : struct mlx5_txq_data *txq_data = (*priv->txqs)[idx];
1543 : : struct mlx5_txq_ctrl *txq_ctrl =
1544 : 0 : container_of(txq_data, struct mlx5_txq_ctrl, txq);
1545 : :
1546 [ # # ]: 0 : if (txq_ctrl->is_hairpin)
1547 : 0 : return mlx5_txq_obj_hairpin_new(dev, idx);
1548 : : #if !defined(HAVE_MLX5DV_DEVX_UAR_OFFSET) && defined(HAVE_INFINIBAND_VERBS_H)
1549 : : DRV_LOG(ERR, "Port %u Tx queue %u cannot create with DevX, no UAR.",
1550 : : dev->data->port_id, idx);
1551 : : rte_errno = ENOMEM;
1552 : : return -rte_errno;
1553 : : #else
1554 : 0 : struct mlx5_proc_priv *ppriv = MLX5_PROC_PRIV(PORT_ID(priv));
1555 : 0 : struct mlx5_dev_ctx_shared *sh = priv->sh;
1556 : 0 : struct mlx5_txq_obj *txq_obj = txq_ctrl->obj;
1557 : 0 : struct mlx5_devx_cq_attr cq_attr = {
1558 [ # # ]: 0 : .uar_page_id = mlx5_os_get_devx_uar_page_id(sh->tx_uar.obj),
1559 : : };
1560 : : uint32_t cqe_n, log_desc_n;
1561 : : uint32_t wqe_n, wqe_size;
1562 : : int ret = 0;
1563 : :
1564 : : MLX5_ASSERT(txq_data);
1565 : : MLX5_ASSERT(txq_obj);
1566 : : MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
1567 : : MLX5_ASSERT(ppriv);
1568 : 0 : txq_obj->txq_ctrl = txq_ctrl;
1569 : 0 : txq_obj->dev = dev;
1570 : : if (__rte_trace_point_fp_is_enabled() &&
1571 : : txq_data->offloads & RTE_ETH_TX_OFFLOAD_SEND_ON_TIMESTAMP)
1572 : : cqe_n = UINT16_MAX / 2 - 1;
1573 : : else
1574 : 0 : cqe_n = (1UL << txq_data->elts_n) / MLX5_TX_COMP_THRESH +
1575 : 0 : 1 + MLX5_TX_COMP_THRESH_INLINE_DIV;
1576 : : log_desc_n = log2above(cqe_n);
1577 : 0 : cqe_n = 1UL << log_desc_n;
1578 [ # # ]: 0 : if (cqe_n > UINT16_MAX) {
1579 : 0 : DRV_LOG(ERR, "Port %u Tx queue %u requests to many CQEs %u.",
1580 : : dev->data->port_id, txq_data->idx, cqe_n);
1581 : 0 : rte_errno = EINVAL;
1582 : 0 : return 0;
1583 : : }
1584 : : /* Create completion queue object with DevX. */
1585 : 0 : ret = mlx5_devx_cq_create(sh->cdev->ctx, &txq_obj->cq_obj, log_desc_n,
1586 : : &cq_attr, priv->sh->numa_node);
1587 [ # # ]: 0 : if (ret) {
1588 : 0 : DRV_LOG(ERR, "Port %u Tx queue %u CQ creation failure.",
1589 : : dev->data->port_id, idx);
1590 : 0 : goto error;
1591 : : }
1592 : 0 : txq_data->cqe_n = log_desc_n;
1593 : 0 : txq_data->cqe_s = cqe_n;
1594 : 0 : txq_data->cqe_m = txq_data->cqe_s - 1;
1595 : 0 : txq_data->cqes = txq_obj->cq_obj.cqes;
1596 : 0 : txq_data->cq_ci = 0;
1597 : 0 : txq_data->cq_pi = 0;
1598 : 0 : txq_data->cq_db = txq_obj->cq_obj.db_rec;
1599 : 0 : *txq_data->cq_db = 0;
1600 : : /*
1601 : : * Adjust the amount of WQEs depending on inline settings.
1602 : : * The number of descriptors should be enough to handle
1603 : : * the specified number of packets. If queue is being created
1604 : : * with Verbs the rdma-core does queue size adjustment
1605 : : * internally in the mlx5_calc_sq_size(), we do the same
1606 : : * for the queue being created with DevX at this point.
1607 : : */
1608 : 0 : wqe_size = txq_data->tso_en ?
1609 [ # # ]: 0 : RTE_ALIGN(txq_ctrl->max_tso_header, MLX5_WSEG_SIZE) : 0;
1610 : 0 : wqe_size += sizeof(struct mlx5_wqe_cseg) +
1611 : : sizeof(struct mlx5_wqe_eseg) +
1612 : : sizeof(struct mlx5_wqe_dseg);
1613 [ # # ]: 0 : if (txq_data->inlen_send)
1614 : 0 : wqe_size = RTE_MAX(wqe_size, sizeof(struct mlx5_wqe_cseg) +
1615 : : sizeof(struct mlx5_wqe_eseg) +
1616 : : RTE_ALIGN(txq_data->inlen_send +
1617 : : sizeof(uint32_t),
1618 : : MLX5_WSEG_SIZE));
1619 : 0 : wqe_size = RTE_ALIGN(wqe_size, MLX5_WQE_SIZE) / MLX5_WQE_SIZE;
1620 : : /* Create Send Queue object with DevX. */
1621 : 0 : wqe_n = RTE_MIN((1UL << txq_data->elts_n) * wqe_size,
1622 : : (uint32_t)priv->sh->dev_cap.max_qp_wr);
1623 : : log_desc_n = log2above(wqe_n);
1624 : 0 : ret = mlx5_txq_create_devx_sq_resources(dev, idx, log_desc_n);
1625 [ # # ]: 0 : if (ret) {
1626 : 0 : DRV_LOG(ERR, "Port %u Tx queue %u SQ creation failure.",
1627 : : dev->data->port_id, idx);
1628 : 0 : rte_errno = errno;
1629 : 0 : goto error;
1630 : : }
1631 : : /* Create the Work Queue. */
1632 : 0 : txq_data->wqe_n = log_desc_n;
1633 : 0 : txq_data->wqe_s = 1 << txq_data->wqe_n;
1634 : 0 : txq_data->wqe_m = txq_data->wqe_s - 1;
1635 : 0 : txq_data->wqes = (struct mlx5_wqe *)(uintptr_t)txq_obj->sq_obj.wqes;
1636 : 0 : txq_data->wqes_end = txq_data->wqes + txq_data->wqe_s;
1637 : 0 : txq_data->wqe_ci = 0;
1638 : 0 : txq_data->wqe_pi = 0;
1639 : 0 : txq_data->wqe_comp = 0;
1640 : 0 : txq_data->wqe_thres = txq_data->wqe_s / MLX5_TX_COMP_THRESH_INLINE_DIV;
1641 : 0 : txq_data->qp_db = &txq_obj->sq_obj.db_rec[MLX5_SND_DBR];
1642 : 0 : *txq_data->qp_db = 0;
1643 : 0 : txq_data->qp_num_8s = txq_obj->sq_obj.sq->id << 8;
1644 : 0 : txq_data->db_heu = sh->cdev->config.dbnc == MLX5_SQ_DB_HEURISTIC;
1645 : 0 : txq_data->db_nc = sh->tx_uar.dbnc;
1646 [ # # # # ]: 0 : txq_data->wait_on_time = !!(!sh->config.tx_pp &&
1647 : : sh->cdev->config.hca_attr.wait_on_time);
1648 : : /* Change Send Queue state to Ready-to-Send. */
1649 : 0 : ret = mlx5_txq_devx_modify(txq_obj, MLX5_TXQ_MOD_RST2RDY, 0);
1650 [ # # ]: 0 : if (ret) {
1651 : 0 : rte_errno = errno;
1652 : 0 : DRV_LOG(ERR,
1653 : : "Port %u Tx queue %u SQ state to SQC_STATE_RDY failed.",
1654 : : dev->data->port_id, idx);
1655 : 0 : goto error;
1656 : : }
1657 : : #ifdef HAVE_IBV_FLOW_DV_SUPPORT
1658 : : /*
1659 : : * If using DevX need to query and store TIS transport domain value.
1660 : : * This is done once per port.
1661 : : * Will use this value on Rx, when creating matching TIR.
1662 : : */
1663 [ # # ]: 0 : if (!priv->sh->tdn)
1664 : 0 : priv->sh->tdn = priv->sh->td->id;
1665 : : #endif
1666 : 0 : txq_ctrl->uar_mmap_offset =
1667 [ # # ]: 0 : mlx5_os_get_devx_uar_mmap_offset(sh->tx_uar.obj);
1668 : 0 : ppriv->uar_table[txq_data->idx] = sh->tx_uar.bf_db;
1669 : 0 : dev->data->tx_queue_state[idx] = RTE_ETH_QUEUE_STATE_STARTED;
1670 : 0 : return 0;
1671 : 0 : error:
1672 : 0 : ret = rte_errno; /* Save rte_errno before cleanup. */
1673 : 0 : mlx5_txq_release_devx_resources(txq_obj);
1674 : 0 : rte_errno = ret; /* Restore rte_errno. */
1675 : 0 : return -rte_errno;
1676 : : #endif
1677 : : }
1678 : :
1679 : : /**
1680 : : * Release an Tx DevX queue object.
1681 : : *
1682 : : * @param txq_obj
1683 : : * DevX Tx queue object.
1684 : : */
1685 : : void
1686 : 0 : mlx5_txq_devx_obj_release(struct mlx5_txq_obj *txq_obj)
1687 : : {
1688 : : MLX5_ASSERT(txq_obj);
1689 [ # # ]: 0 : if (txq_obj->txq_ctrl->is_hairpin) {
1690 [ # # ]: 0 : if (txq_obj->sq) {
1691 : 0 : claim_zero(mlx5_devx_cmd_destroy(txq_obj->sq));
1692 : 0 : txq_obj->sq = NULL;
1693 : : }
1694 [ # # ]: 0 : if (txq_obj->tis)
1695 : 0 : claim_zero(mlx5_devx_cmd_destroy(txq_obj->tis));
1696 [ # # ]: 0 : if (txq_obj->umem_obj_wq_buffer) {
1697 : : claim_zero(mlx5_os_umem_dereg(txq_obj->umem_obj_wq_buffer));
1698 : 0 : txq_obj->umem_obj_wq_buffer = NULL;
1699 : : }
1700 [ # # ]: 0 : if (txq_obj->umem_buf_wq_buffer) {
1701 : 0 : mlx5_free(txq_obj->umem_buf_wq_buffer);
1702 : 0 : txq_obj->umem_buf_wq_buffer = NULL;
1703 : : }
1704 : : #if defined(HAVE_MLX5DV_DEVX_UAR_OFFSET) || !defined(HAVE_INFINIBAND_VERBS_H)
1705 : : } else {
1706 : 0 : mlx5_txq_release_devx_resources(txq_obj);
1707 : : #endif
1708 : : }
1709 : 0 : }
1710 : :
1711 : : struct mlx5_obj_ops devx_obj_ops = {
1712 : : .rxq_obj_modify_vlan_strip = mlx5_rxq_obj_modify_rq_vlan_strip,
1713 : : .rxq_obj_new = mlx5_rxq_devx_obj_new,
1714 : : .rxq_event_get = mlx5_rx_devx_get_event,
1715 : : .rxq_obj_modify = mlx5_devx_modify_rq,
1716 : : .rxq_obj_release = mlx5_rxq_devx_obj_release,
1717 : : .rxq_event_get_lwm = mlx5_rx_devx_get_event_lwm,
1718 : : .ind_table_new = mlx5_devx_ind_table_new,
1719 : : .ind_table_modify = mlx5_devx_ind_table_modify,
1720 : : .ind_table_destroy = mlx5_devx_ind_table_destroy,
1721 : : .hrxq_new = mlx5_devx_hrxq_new,
1722 : : .hrxq_destroy = mlx5_devx_tir_destroy,
1723 : : .hrxq_modify = mlx5_devx_hrxq_modify,
1724 : : .drop_action_create = mlx5_devx_drop_action_create,
1725 : : .drop_action_destroy = mlx5_devx_drop_action_destroy,
1726 : : .txq_obj_new = mlx5_txq_devx_obj_new,
1727 : : .txq_obj_modify = mlx5_txq_devx_modify,
1728 : : .txq_obj_release = mlx5_txq_devx_obj_release,
1729 : : .lb_dummy_queue_create = NULL,
1730 : : .lb_dummy_queue_release = NULL,
1731 : : };
|