Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2020 Mellanox Technologies, Ltd
3 : : */
4 : : #include <mlx5_prm.h>
5 : : #include <rte_malloc.h>
6 : : #include <rte_cycles.h>
7 : : #include <rte_eal_paging.h>
8 : :
9 : : #include <mlx5_malloc.h>
10 : : #include <mlx5_common_os.h>
11 : : #include <mlx5_common_devx.h>
12 : :
13 : : #include "mlx5.h"
14 : : #include "mlx5_flow.h"
15 : : #include "mlx5_hws_cnt.h"
16 : :
17 : : #define MLX5_ASO_CNT_QUEUE_LOG_DESC 14
18 : :
19 : : /**
20 : : * Free MR resources.
21 : : *
22 : : * @param[in] cdev
23 : : * Pointer to the mlx5 common device.
24 : : * @param[in] mr
25 : : * MR to free.
26 : : */
27 : : static void
28 : 0 : mlx5_aso_dereg_mr(struct mlx5_common_device *cdev, struct mlx5_pmd_mr *mr)
29 : : {
30 : 0 : void *addr = mr->addr;
31 : :
32 : 0 : cdev->mr_scache.dereg_mr_cb(mr);
33 : 0 : mlx5_free(addr);
34 : : memset(mr, 0, sizeof(*mr));
35 : 0 : }
36 : :
37 : : /**
38 : : * Register Memory Region.
39 : : *
40 : : * @param[in] cdev
41 : : * Pointer to the mlx5 common device.
42 : : * @param[in] length
43 : : * Size of MR buffer.
44 : : * @param[in/out] mr
45 : : * Pointer to MR to create.
46 : : *
47 : : * @return
48 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
49 : : */
50 : : static int
51 : 0 : mlx5_aso_reg_mr(struct mlx5_common_device *cdev, size_t length,
52 : : struct mlx5_pmd_mr *mr)
53 : : {
54 : : int ret;
55 : :
56 : 0 : mr->addr = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, length, 4096,
57 : : SOCKET_ID_ANY);
58 [ # # ]: 0 : if (!mr->addr) {
59 : 0 : DRV_LOG(ERR, "Failed to create ASO bits mem for MR.");
60 : 0 : return -1;
61 : : }
62 : 0 : ret = cdev->mr_scache.reg_mr_cb(cdev->pd, mr->addr, length, mr);
63 [ # # ]: 0 : if (ret) {
64 : 0 : DRV_LOG(ERR, "Failed to create direct Mkey.");
65 : 0 : mlx5_free(mr->addr);
66 : 0 : return -1;
67 : : }
68 : : return 0;
69 : : }
70 : :
71 : : /**
72 : : * Destroy Send Queue used for ASO access.
73 : : *
74 : : * @param[in] sq
75 : : * ASO SQ to destroy.
76 : : */
77 : : void
78 : 0 : mlx5_aso_destroy_sq(struct mlx5_aso_sq *sq)
79 : : {
80 : 0 : mlx5_devx_sq_destroy(&sq->sq_obj);
81 : 0 : mlx5_devx_cq_destroy(&sq->cq.cq_obj);
82 : : memset(sq, 0, sizeof(*sq));
83 : 0 : }
84 : :
85 : : /**
86 : : * Initialize Send Queue used for ASO access counter.
87 : : *
88 : : * @param[in] sq
89 : : * ASO SQ to initialize.
90 : : */
91 : : static void
92 : 0 : mlx5_aso_cnt_init_sq(struct mlx5_aso_sq *sq)
93 : : {
94 : : volatile struct mlx5_aso_wqe *restrict wqe;
95 : : int i;
96 : 0 : int size = 1 << sq->log_desc_n;
97 : :
98 : : /* All the next fields state should stay constant. */
99 [ # # ]: 0 : for (i = 0, wqe = &sq->sq_obj.aso_wqes[0]; i < size; ++i, ++wqe) {
100 [ # # ]: 0 : wqe->general_cseg.sq_ds = rte_cpu_to_be_32((sq->sqn << 8) |
101 : : (sizeof(*wqe) >> 4));
102 : 0 : wqe->aso_cseg.operand_masks = rte_cpu_to_be_32
103 : : (0u |
104 : : (ASO_OPER_LOGICAL_OR << ASO_CSEG_COND_OPER_OFFSET) |
105 : : (ASO_OP_ALWAYS_FALSE << ASO_CSEG_COND_1_OPER_OFFSET) |
106 : : (ASO_OP_ALWAYS_FALSE << ASO_CSEG_COND_0_OPER_OFFSET) |
107 : : (BYTEWISE_64BYTE << ASO_CSEG_DATA_MASK_MODE_OFFSET));
108 : 0 : wqe->aso_cseg.data_mask = RTE_BE64(UINT64_MAX);
109 : : }
110 : 0 : }
111 : :
112 : : /**
113 : : * Initialize Send Queue used for ASO access.
114 : : *
115 : : * @param[in] sq
116 : : * ASO SQ to initialize.
117 : : */
118 : : static void
119 : 0 : mlx5_aso_age_init_sq(struct mlx5_aso_sq *sq)
120 : : {
121 : : volatile struct mlx5_aso_wqe *restrict wqe;
122 : : int i;
123 : 0 : int size = 1 << sq->log_desc_n;
124 : : uint64_t addr;
125 : :
126 : : /* All the next fields state should stay constant. */
127 [ # # ]: 0 : for (i = 0, wqe = &sq->sq_obj.aso_wqes[0]; i < size; ++i, ++wqe) {
128 [ # # ]: 0 : wqe->general_cseg.sq_ds = rte_cpu_to_be_32((sq->sqn << 8) |
129 : : (sizeof(*wqe) >> 4));
130 [ # # ]: 0 : wqe->aso_cseg.lkey = rte_cpu_to_be_32(sq->mr.lkey);
131 : 0 : addr = (uint64_t)((uint64_t *)sq->mr.addr + i *
132 : 0 : MLX5_ASO_AGE_ACTIONS_PER_POOL / 64);
133 [ # # ]: 0 : wqe->aso_cseg.va_h = rte_cpu_to_be_32((uint32_t)(addr >> 32));
134 [ # # ]: 0 : wqe->aso_cseg.va_l_r = rte_cpu_to_be_32((uint32_t)addr | 1u);
135 : 0 : wqe->aso_cseg.operand_masks = rte_cpu_to_be_32
136 : : (0u |
137 : : (ASO_OPER_LOGICAL_OR << ASO_CSEG_COND_OPER_OFFSET) |
138 : : (ASO_OP_ALWAYS_TRUE << ASO_CSEG_COND_1_OPER_OFFSET) |
139 : : (ASO_OP_ALWAYS_TRUE << ASO_CSEG_COND_0_OPER_OFFSET) |
140 : : (BYTEWISE_64BYTE << ASO_CSEG_DATA_MASK_MODE_OFFSET));
141 : 0 : wqe->aso_cseg.data_mask = RTE_BE64(UINT64_MAX);
142 : : }
143 : 0 : }
144 : :
145 : : /**
146 : : * Initialize Send Queue used for ASO flow meter access.
147 : : *
148 : : * @param[in] sq
149 : : * ASO SQ to initialize.
150 : : */
151 : : void
152 : 0 : mlx5_aso_mtr_init_sq(struct mlx5_aso_sq *sq)
153 : : {
154 : : volatile struct mlx5_aso_wqe *restrict wqe;
155 : : int i;
156 : 0 : int size = 1 << sq->log_desc_n;
157 : :
158 : : /* All the next fields state should stay constant. */
159 [ # # ]: 0 : for (i = 0, wqe = &sq->sq_obj.aso_wqes[0]; i < size; ++i, ++wqe) {
160 [ # # ]: 0 : wqe->general_cseg.sq_ds = rte_cpu_to_be_32((sq->sqn << 8) |
161 : : (sizeof(*wqe) >> 4));
162 : 0 : wqe->aso_cseg.operand_masks = RTE_BE32(0u |
163 : : (ASO_OPER_LOGICAL_OR << ASO_CSEG_COND_OPER_OFFSET) |
164 : : (ASO_OP_ALWAYS_TRUE << ASO_CSEG_COND_1_OPER_OFFSET) |
165 : : (ASO_OP_ALWAYS_TRUE << ASO_CSEG_COND_0_OPER_OFFSET) |
166 : : (BYTEWISE_64BYTE << ASO_CSEG_DATA_MASK_MODE_OFFSET));
167 : 0 : wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ALWAYS <<
168 : : MLX5_COMP_MODE_OFFSET);
169 : : }
170 : 0 : }
171 : :
172 : : /*
173 : : * Initialize Send Queue used for ASO connection tracking.
174 : : *
175 : : * @param[in] sq
176 : : * ASO SQ to initialize.
177 : : */
178 : : static void
179 : 0 : mlx5_aso_ct_init_sq(struct mlx5_aso_sq *sq)
180 : : {
181 : : volatile struct mlx5_aso_wqe *restrict wqe;
182 : : int i;
183 : 0 : int size = 1 << sq->log_desc_n;
184 : : uint64_t addr;
185 : :
186 : : /* All the next fields state should stay constant. */
187 [ # # ]: 0 : for (i = 0, wqe = &sq->sq_obj.aso_wqes[0]; i < size; ++i, ++wqe) {
188 [ # # ]: 0 : wqe->general_cseg.sq_ds = rte_cpu_to_be_32((sq->sqn << 8) |
189 : : (sizeof(*wqe) >> 4));
190 : : /* One unique MR for the query data. */
191 [ # # ]: 0 : wqe->aso_cseg.lkey = rte_cpu_to_be_32(sq->mr.lkey);
192 : : /* Magic number 64 represents the length of a ASO CT obj. */
193 : 0 : addr = (uint64_t)((uintptr_t)sq->mr.addr + i * 64);
194 [ # # ]: 0 : wqe->aso_cseg.va_h = rte_cpu_to_be_32((uint32_t)(addr >> 32));
195 [ # # ]: 0 : wqe->aso_cseg.va_l_r = rte_cpu_to_be_32((uint32_t)addr | 1u);
196 : : /*
197 : : * The values of operand_masks are different for modify
198 : : * and query.
199 : : * And data_mask may be different for each modification. In
200 : : * query, it could be zero and ignored.
201 : : * CQE generation is always needed, in order to decide when
202 : : * it is available to create the flow or read the data.
203 : : */
204 : 0 : wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ALWAYS <<
205 : : MLX5_COMP_MODE_OFFSET);
206 : : }
207 : 0 : }
208 : :
209 : : /**
210 : : * Create Send Queue used for ASO access.
211 : : *
212 : : * @param[in] cdev
213 : : * Pointer to the mlx5 common device.
214 : : * @param[in/out] sq
215 : : * Pointer to SQ to create.
216 : : * @param[in] uar
217 : : * User Access Region object.
218 : : *
219 : : * @return
220 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
221 : : */
222 : : int
223 : 0 : mlx5_aso_sq_create(struct mlx5_common_device *cdev, struct mlx5_aso_sq *sq,
224 : : void *uar, uint16_t log_desc_n)
225 : : {
226 [ # # ]: 0 : struct mlx5_devx_cq_attr cq_attr = {
227 : : .uar_page_id = mlx5_os_get_devx_uar_page_id(uar),
228 : : };
229 : 0 : struct mlx5_devx_create_sq_attr sq_attr = {
230 : : .user_index = 0xFFFF,
231 : : .wq_attr = (struct mlx5_devx_wq_attr){
232 : 0 : .pd = cdev->pdn,
233 : 0 : .uar_page = mlx5_os_get_devx_uar_page_id(uar),
234 : : },
235 : : .ts_format =
236 : 0 : mlx5_ts_format_conv(cdev->config.hca_attr.sq_ts_format),
237 : : };
238 : 0 : struct mlx5_devx_modify_sq_attr modify_attr = {
239 : : .state = MLX5_SQC_STATE_RDY,
240 : : };
241 : : uint16_t log_wqbb_n;
242 : : int ret;
243 : :
244 [ # # ]: 0 : if (mlx5_devx_cq_create(cdev->ctx, &sq->cq.cq_obj,
245 : : log_desc_n, &cq_attr,
246 : : SOCKET_ID_ANY))
247 : 0 : goto error;
248 : 0 : sq->cq.cq_ci = 0;
249 : 0 : sq->cq.log_desc_n = log_desc_n;
250 : 0 : sq->log_desc_n = log_desc_n;
251 : 0 : sq_attr.cqn = sq->cq.cq_obj.cq->id;
252 : : /* for mlx5_aso_wqe that is twice the size of mlx5_wqe */
253 : 0 : log_wqbb_n = sq->log_desc_n + 1;
254 : 0 : ret = mlx5_devx_sq_create(cdev->ctx, &sq->sq_obj, log_wqbb_n, &sq_attr,
255 : : SOCKET_ID_ANY);
256 [ # # ]: 0 : if (ret) {
257 : 0 : DRV_LOG(ERR, "Can't create SQ object.");
258 : 0 : rte_errno = ENOMEM;
259 : 0 : goto error;
260 : : }
261 : 0 : ret = mlx5_devx_cmd_modify_sq(sq->sq_obj.sq, &modify_attr);
262 [ # # ]: 0 : if (ret) {
263 : 0 : DRV_LOG(ERR, "Can't change SQ state to ready.");
264 : 0 : rte_errno = ENOMEM;
265 : 0 : goto error;
266 : : }
267 : 0 : sq->pi = 0;
268 : 0 : sq->head = 0;
269 : 0 : sq->tail = 0;
270 : 0 : sq->sqn = sq->sq_obj.sq->id;
271 : : rte_spinlock_init(&sq->sqsl);
272 : 0 : return 0;
273 : 0 : error:
274 : 0 : mlx5_aso_destroy_sq(sq);
275 : 0 : return -1;
276 : : }
277 : :
278 : : void
279 : 0 : mlx5_aso_mtr_queue_uninit(struct mlx5_dev_ctx_shared *sh __rte_unused,
280 : : struct mlx5_aso_mtr_pool *hws_pool,
281 : : struct mlx5_aso_mtr_pools_mng *pool_mng)
282 : : {
283 : : uint32_t i;
284 : :
285 [ # # ]: 0 : if (hws_pool) {
286 [ # # ]: 0 : for (i = 0; i < hws_pool->nb_sq; i++)
287 : 0 : mlx5_aso_destroy_sq(hws_pool->sq + i);
288 : 0 : mlx5_free(hws_pool->sq);
289 : 0 : return;
290 : : }
291 [ # # ]: 0 : if (pool_mng)
292 : 0 : mlx5_aso_destroy_sq(&pool_mng->sq);
293 : : }
294 : :
295 : : int
296 : 0 : mlx5_aso_mtr_queue_init(struct mlx5_dev_ctx_shared *sh,
297 : : struct mlx5_aso_mtr_pool *hws_pool,
298 : : struct mlx5_aso_mtr_pools_mng *pool_mng,
299 : : uint32_t nb_queues)
300 : : {
301 : 0 : struct mlx5_common_device *cdev = sh->cdev;
302 : : struct mlx5_aso_sq *sq;
303 : : uint32_t i;
304 : :
305 [ # # ]: 0 : if (hws_pool) {
306 : 0 : sq = mlx5_malloc(MLX5_MEM_ZERO,
307 : : sizeof(struct mlx5_aso_sq) * nb_queues,
308 : : RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
309 [ # # ]: 0 : if (!sq)
310 : : return -1;
311 : 0 : hws_pool->sq = sq;
312 [ # # ]: 0 : for (i = 0; i < nb_queues; i++) {
313 [ # # ]: 0 : if (mlx5_aso_sq_create(cdev, hws_pool->sq + i,
314 : : sh->tx_uar.obj,
315 : : MLX5_ASO_QUEUE_LOG_DESC))
316 : 0 : goto error;
317 : 0 : mlx5_aso_mtr_init_sq(hws_pool->sq + i);
318 : : }
319 : 0 : hws_pool->nb_sq = nb_queues;
320 : : }
321 [ # # ]: 0 : if (pool_mng) {
322 [ # # ]: 0 : if (mlx5_aso_sq_create(cdev, &pool_mng->sq,
323 : : sh->tx_uar.obj,
324 : : MLX5_ASO_QUEUE_LOG_DESC))
325 : : return -1;
326 : 0 : mlx5_aso_mtr_init_sq(&pool_mng->sq);
327 : : }
328 : : return 0;
329 : : error:
330 : : do {
331 : 0 : mlx5_aso_destroy_sq(hws_pool->sq + i);
332 [ # # ]: 0 : } while (i--);
333 : : return -1;
334 : : }
335 : :
336 : : /**
337 : : * API to create and initialize Send Queue used for ASO access.
338 : : *
339 : : * @param[in] sh
340 : : * Pointer to shared device context.
341 : : * @param[in] aso_opc_mod
342 : : * Mode of ASO feature.
343 : : * @param[in] nb_queues
344 : : * Number of Send Queues to create.
345 : : *
346 : : * @return
347 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
348 : : */
349 : : int
350 : 0 : mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh,
351 : : enum mlx5_access_aso_opc_mod aso_opc_mod,
352 : : uint32_t nb_queues)
353 : : {
354 : : uint32_t sq_desc_n = 1 << MLX5_ASO_QUEUE_LOG_DESC;
355 : 0 : struct mlx5_common_device *cdev = sh->cdev;
356 : :
357 [ # # # # ]: 0 : switch (aso_opc_mod) {
358 : 0 : case ASO_OPC_MOD_FLOW_HIT:
359 [ # # ]: 0 : if (mlx5_aso_reg_mr(cdev, (MLX5_ASO_AGE_ACTIONS_PER_POOL / 8) *
360 : 0 : sq_desc_n, &sh->aso_age_mng->aso_sq.mr))
361 : : return -1;
362 [ # # ]: 0 : if (mlx5_aso_sq_create(cdev, &sh->aso_age_mng->aso_sq,
363 : : sh->tx_uar.obj,
364 : : MLX5_ASO_QUEUE_LOG_DESC)) {
365 : 0 : mlx5_aso_dereg_mr(cdev, &sh->aso_age_mng->aso_sq.mr);
366 : 0 : return -1;
367 : : }
368 : 0 : mlx5_aso_age_init_sq(&sh->aso_age_mng->aso_sq);
369 : 0 : break;
370 : 0 : case ASO_OPC_MOD_POLICER:
371 [ # # ]: 0 : if (mlx5_aso_mtr_queue_init(sh, NULL,
372 : 0 : &sh->mtrmng->pools_mng, nb_queues))
373 : 0 : return -1;
374 : : break;
375 : 0 : case ASO_OPC_MOD_CONNECTION_TRACKING:
376 [ # # ]: 0 : if (mlx5_aso_ct_queue_init(sh, sh->ct_mng, MLX5_ASO_CT_SQ_NUM))
377 : 0 : return -1;
378 : : break;
379 : 0 : default:
380 : 0 : DRV_LOG(ERR, "Unknown ASO operation mode");
381 : 0 : return -1;
382 : : }
383 : : return 0;
384 : : }
385 : :
386 : : /**
387 : : * API to destroy Send Queue used for ASO access.
388 : : *
389 : : * @param[in] sh
390 : : * Pointer to shared device context.
391 : : * @param[in] aso_opc_mod
392 : : * Mode of ASO feature.
393 : : */
394 : : void
395 : 0 : mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh,
396 : : enum mlx5_access_aso_opc_mod aso_opc_mod)
397 : : {
398 : : struct mlx5_aso_sq *sq = NULL;
399 : :
400 [ # # # # ]: 0 : switch (aso_opc_mod) {
401 : 0 : case ASO_OPC_MOD_FLOW_HIT:
402 : 0 : mlx5_aso_dereg_mr(sh->cdev, &sh->aso_age_mng->aso_sq.mr);
403 : 0 : sq = &sh->aso_age_mng->aso_sq;
404 : : break;
405 : 0 : case ASO_OPC_MOD_POLICER:
406 : 0 : mlx5_aso_mtr_queue_uninit(sh, NULL, &sh->mtrmng->pools_mng);
407 : : break;
408 : 0 : case ASO_OPC_MOD_CONNECTION_TRACKING:
409 : 0 : mlx5_aso_ct_queue_uninit(sh, sh->ct_mng);
410 : : break;
411 : 0 : default:
412 : 0 : DRV_LOG(ERR, "Unknown ASO operation mode");
413 : 0 : return;
414 : : }
415 : : if (sq)
416 : 0 : mlx5_aso_destroy_sq(sq);
417 : : }
418 : :
419 : : /**
420 : : * Write a burst of WQEs to ASO SQ.
421 : : *
422 : : * @param[in] sh
423 : : * Pointer to shared device context.
424 : : * @param[in] n
425 : : * Index of the last valid pool.
426 : : *
427 : : * @return
428 : : * Number of WQEs in burst.
429 : : */
430 : : static uint16_t
431 : 0 : mlx5_aso_sq_enqueue_burst(struct mlx5_dev_ctx_shared *sh, uint16_t n)
432 : : {
433 : 0 : struct mlx5_aso_age_mng *mng = sh->aso_age_mng;
434 : : volatile struct mlx5_aso_wqe *wqe;
435 : : struct mlx5_aso_sq *sq = &mng->aso_sq;
436 : : struct mlx5_aso_age_pool *pool;
437 : 0 : uint16_t size = 1 << sq->log_desc_n;
438 : 0 : uint16_t mask = size - 1;
439 : : uint16_t max;
440 : 0 : uint16_t start_head = sq->head;
441 : :
442 : 0 : max = RTE_MIN(size - (uint16_t)(sq->head - sq->tail), n - sq->next);
443 [ # # ]: 0 : if (unlikely(!max))
444 : : return 0;
445 : 0 : sq->elts[start_head & mask].burst_size = max;
446 : : do {
447 : 0 : wqe = &sq->sq_obj.aso_wqes[sq->head & mask];
448 : 0 : rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]);
449 : : /* Fill next WQE. */
450 : 0 : rte_rwlock_read_lock(&mng->resize_rwl);
451 [ # # ]: 0 : pool = mng->pools[sq->next];
452 : : rte_rwlock_read_unlock(&mng->resize_rwl);
453 : 0 : sq->elts[sq->head & mask].pool = pool;
454 : 0 : wqe->general_cseg.misc =
455 [ # # ]: 0 : rte_cpu_to_be_32(((struct mlx5_devx_obj *)
456 : : (pool->flow_hit_aso_obj))->id);
457 : 0 : wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ONLY_FIRST_ERR <<
458 : : MLX5_COMP_MODE_OFFSET);
459 [ # # ]: 0 : wqe->general_cseg.opcode = rte_cpu_to_be_32
460 : : (MLX5_OPCODE_ACCESS_ASO |
461 : : (ASO_OPC_MOD_FLOW_HIT <<
462 : : WQE_CSEG_OPC_MOD_OFFSET) |
463 : : (sq->pi <<
464 : : WQE_CSEG_WQE_INDEX_OFFSET));
465 : 0 : sq->pi += 2; /* Each WQE contains 2 WQEBB's. */
466 : 0 : sq->head++;
467 : 0 : sq->next++;
468 : 0 : max--;
469 [ # # ]: 0 : } while (max);
470 : 0 : wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ALWAYS <<
471 : : MLX5_COMP_MODE_OFFSET);
472 : 0 : mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe,
473 : 0 : sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR],
474 : 0 : !sh->tx_uar.dbnc);
475 : 0 : return sq->elts[start_head & mask].burst_size;
476 : : }
477 : :
478 : : /**
479 : : * Debug utility function. Dump contents of error CQE and WQE.
480 : : *
481 : : * @param[in] cqe
482 : : * Error CQE to dump.
483 : : * @param[in] wqe
484 : : * Error WQE to dump.
485 : : */
486 : : static void
487 : 0 : mlx5_aso_dump_err_objs(volatile uint32_t *cqe, volatile uint32_t *wqe)
488 : : {
489 : : int i;
490 : :
491 : 0 : DRV_LOG(ERR, "Error cqe:");
492 [ # # ]: 0 : for (i = 0; i < 16; i += 4)
493 : 0 : DRV_LOG(ERR, "%08X %08X %08X %08X", cqe[i], cqe[i + 1],
494 : : cqe[i + 2], cqe[i + 3]);
495 : 0 : DRV_LOG(ERR, "\nError wqe:");
496 [ # # ]: 0 : for (i = 0; i < (int)sizeof(struct mlx5_aso_wqe) / 4; i += 4)
497 : 0 : DRV_LOG(ERR, "%08X %08X %08X %08X", wqe[i], wqe[i + 1],
498 : : wqe[i + 2], wqe[i + 3]);
499 : 0 : }
500 : :
501 : : /**
502 : : * Handle case of error CQE.
503 : : *
504 : : * @param[in] sq
505 : : * ASO SQ to use.
506 : : */
507 : : void
508 : 0 : mlx5_aso_cqe_err_handle(struct mlx5_aso_sq *sq)
509 : : {
510 : : struct mlx5_aso_cq *cq = &sq->cq;
511 : 0 : uint32_t idx = cq->cq_ci & ((1 << cq->log_desc_n) - 1);
512 : 0 : volatile struct mlx5_err_cqe *cqe =
513 : 0 : (volatile struct mlx5_err_cqe *)&cq->cq_obj.cqes[idx];
514 : :
515 : 0 : cq->errors++;
516 : 0 : idx = rte_be_to_cpu_16(cqe->wqe_counter) & (1u << sq->log_desc_n);
517 : 0 : mlx5_aso_dump_err_objs((volatile uint32_t *)cqe,
518 : 0 : (volatile uint32_t *)&sq->sq_obj.aso_wqes[idx]);
519 : 0 : }
520 : :
521 : : int
522 : 0 : mlx5_aso_pull_completion(struct mlx5_aso_sq *sq,
523 : : struct rte_flow_op_result res[],
524 : : uint16_t n_res)
525 : : {
526 : : struct mlx5_aso_cq *cq = &sq->cq;
527 : : volatile struct mlx5_cqe *restrict cqe;
528 : 0 : const uint32_t cq_size = 1 << cq->log_desc_n;
529 : 0 : const uint32_t mask = cq_size - 1;
530 : : uint32_t idx;
531 : : uint32_t next_idx;
532 : : uint16_t max;
533 : : uint16_t n = 0;
534 : : int ret;
535 : :
536 : 0 : max = (uint16_t)(sq->head - sq->tail);
537 [ # # ]: 0 : if (unlikely(!max || !n_res))
538 : : return 0;
539 : 0 : next_idx = cq->cq_ci & mask;
540 : : do {
541 : : idx = next_idx;
542 : 0 : next_idx = (cq->cq_ci + 1) & mask;
543 : : /* Need to confirm the position of the prefetch. */
544 : 0 : rte_prefetch0(&cq->cq_obj.cqes[next_idx]);
545 : 0 : cqe = &cq->cq_obj.cqes[idx];
546 [ # # ]: 0 : ret = check_cqe(cqe, cq_size, cq->cq_ci);
547 : : /*
548 : : * Be sure owner read is done before any other cookie field or
549 : : * opaque field.
550 : : */
551 : 0 : rte_io_rmb();
552 : : if (ret == MLX5_CQE_STATUS_HW_OWN)
553 : : break;
554 : 0 : res[n].user_data = sq->elts[(uint16_t)((sq->tail + n) & mask)].user_data;
555 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
556 : 0 : mlx5_aso_cqe_err_handle(sq);
557 : 0 : res[n].status = RTE_FLOW_OP_ERROR;
558 : : } else {
559 : 0 : res[n].status = RTE_FLOW_OP_SUCCESS;
560 : : }
561 : 0 : cq->cq_ci++;
562 [ # # ]: 0 : if (++n == n_res)
563 : : break;
564 : : } while (1);
565 [ # # ]: 0 : if (likely(n)) {
566 : 0 : sq->tail += n;
567 : 0 : rte_io_wmb();
568 [ # # ]: 0 : cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
569 : : }
570 : 0 : return n;
571 : : }
572 : :
573 : : void
574 : 0 : mlx5_aso_push_wqe(struct mlx5_dev_ctx_shared *sh,
575 : : struct mlx5_aso_sq *sq)
576 : : {
577 [ # # ]: 0 : if (sq->db_pi == sq->pi)
578 : : return;
579 : 0 : mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)sq->db,
580 : 0 : sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR],
581 : 0 : !sh->tx_uar.dbnc);
582 : 0 : sq->db_pi = sq->pi;
583 : : }
584 : :
585 : : /**
586 : : * Update ASO objects upon completion.
587 : : *
588 : : * @param[in] sh
589 : : * Shared device context.
590 : : * @param[in] n
591 : : * Number of completed ASO objects.
592 : : */
593 : : static void
594 : 0 : mlx5_aso_age_action_update(struct mlx5_dev_ctx_shared *sh, uint16_t n)
595 : : {
596 : 0 : struct mlx5_aso_age_mng *mng = sh->aso_age_mng;
597 : : struct mlx5_aso_sq *sq = &mng->aso_sq;
598 : : struct mlx5_age_info *age_info;
599 : 0 : const uint16_t size = 1 << sq->log_desc_n;
600 : 0 : const uint16_t mask = size - 1;
601 : 0 : const uint64_t curr = MLX5_CURR_TIME_SEC;
602 : : uint16_t expected = AGE_CANDIDATE;
603 : : uint16_t i;
604 : :
605 [ # # ]: 0 : for (i = 0; i < n; ++i) {
606 : 0 : uint16_t idx = (sq->tail + i) & mask;
607 : 0 : struct mlx5_aso_age_pool *pool = sq->elts[idx].pool;
608 : 0 : uint64_t diff = curr - pool->time_of_last_age_check;
609 : 0 : uint64_t *addr = sq->mr.addr;
610 : : int j;
611 : :
612 : 0 : addr += idx * MLX5_ASO_AGE_ACTIONS_PER_POOL / 64;
613 : 0 : pool->time_of_last_age_check = curr;
614 [ # # ]: 0 : for (j = 0; j < MLX5_ASO_AGE_ACTIONS_PER_POOL; j++) {
615 : 0 : struct mlx5_aso_age_action *act = &pool->actions[j];
616 : : struct mlx5_age_param *ap = &act->age_params;
617 : : uint8_t byte;
618 : : uint8_t offset;
619 : : uint8_t *u8addr;
620 : : uint8_t hit;
621 : :
622 [ # # ]: 0 : if (__atomic_load_n(&ap->state, __ATOMIC_RELAXED) !=
623 : : AGE_CANDIDATE)
624 : 0 : continue;
625 : 0 : byte = 63 - (j / 8);
626 : 0 : offset = j % 8;
627 : : u8addr = (uint8_t *)addr;
628 : 0 : hit = (u8addr[byte] >> offset) & 0x1;
629 [ # # ]: 0 : if (hit) {
630 : 0 : __atomic_store_n(&ap->sec_since_last_hit, 0,
631 : : __ATOMIC_RELAXED);
632 : : } else {
633 : : struct mlx5_priv *priv;
634 : :
635 : 0 : __atomic_fetch_add(&ap->sec_since_last_hit,
636 : : diff, __ATOMIC_RELAXED);
637 : : /* If timeout passed add to aged-out list. */
638 [ # # ]: 0 : if (ap->sec_since_last_hit <= ap->timeout)
639 : 0 : continue;
640 : 0 : priv =
641 : 0 : rte_eth_devices[ap->port_id].data->dev_private;
642 : 0 : age_info = GET_PORT_AGE_INFO(priv);
643 : 0 : rte_spinlock_lock(&age_info->aged_sl);
644 [ # # ]: 0 : if (__atomic_compare_exchange_n(&ap->state,
645 : : &expected,
646 : : AGE_TMOUT,
647 : : false,
648 : : __ATOMIC_RELAXED,
649 : : __ATOMIC_RELAXED)) {
650 [ # # ]: 0 : LIST_INSERT_HEAD(&age_info->aged_aso,
651 : : act, next);
652 : 0 : MLX5_AGE_SET(age_info,
653 : : MLX5_AGE_EVENT_NEW);
654 : : }
655 : : rte_spinlock_unlock(&age_info->aged_sl);
656 : : }
657 : : }
658 : : }
659 : 0 : mlx5_age_event_prepare(sh);
660 : 0 : }
661 : :
662 : : /**
663 : : * Handle completions from WQEs sent to ASO SQ.
664 : : *
665 : : * @param[in] sh
666 : : * Shared device context.
667 : : *
668 : : * @return
669 : : * Number of CQEs handled.
670 : : */
671 : : static uint16_t
672 : 0 : mlx5_aso_completion_handle(struct mlx5_dev_ctx_shared *sh)
673 : : {
674 : 0 : struct mlx5_aso_age_mng *mng = sh->aso_age_mng;
675 : 0 : struct mlx5_aso_sq *sq = &mng->aso_sq;
676 : : struct mlx5_aso_cq *cq = &sq->cq;
677 : : volatile struct mlx5_cqe *restrict cqe;
678 : 0 : const unsigned int cq_size = 1 << cq->log_desc_n;
679 : 0 : const unsigned int mask = cq_size - 1;
680 : : uint32_t idx;
681 : 0 : uint32_t next_idx = cq->cq_ci & mask;
682 : 0 : const uint16_t max = (uint16_t)(sq->head - sq->tail);
683 : : uint16_t i = 0;
684 : : int ret;
685 [ # # ]: 0 : if (unlikely(!max))
686 : : return 0;
687 : : do {
688 : 0 : idx = next_idx;
689 : 0 : next_idx = (cq->cq_ci + 1) & mask;
690 : 0 : rte_prefetch0(&cq->cq_obj.cqes[next_idx]);
691 : 0 : cqe = &cq->cq_obj.cqes[idx];
692 [ # # ]: 0 : ret = check_cqe(cqe, cq_size, cq->cq_ci);
693 : : /*
694 : : * Be sure owner read is done before any other cookie field or
695 : : * opaque field.
696 : : */
697 : 0 : rte_io_rmb();
698 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
699 [ # # ]: 0 : if (likely(ret == MLX5_CQE_STATUS_HW_OWN))
700 : : break;
701 : 0 : mlx5_aso_cqe_err_handle(sq);
702 : : } else {
703 : 0 : i += sq->elts[(sq->tail + i) & mask].burst_size;
704 : : }
705 : 0 : cq->cq_ci++;
706 : : } while (1);
707 [ # # ]: 0 : if (likely(i)) {
708 : 0 : mlx5_aso_age_action_update(sh, i);
709 : 0 : sq->tail += i;
710 : 0 : rte_io_wmb();
711 [ # # ]: 0 : cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
712 : : }
713 : : return i;
714 : : }
715 : :
716 : : /**
717 : : * Periodically read CQEs and send WQEs to ASO SQ.
718 : : *
719 : : * @param[in] arg
720 : : * Shared device context containing the ASO SQ.
721 : : */
722 : : static void
723 : 0 : mlx5_flow_aso_alarm(void *arg)
724 : : {
725 : : struct mlx5_dev_ctx_shared *sh = arg;
726 : 0 : struct mlx5_aso_sq *sq = &sh->aso_age_mng->aso_sq;
727 : : uint32_t us = 100u;
728 : : uint16_t n;
729 : :
730 : 0 : rte_rwlock_read_lock(&sh->aso_age_mng->resize_rwl);
731 : 0 : n = sh->aso_age_mng->next;
732 : : rte_rwlock_read_unlock(&sh->aso_age_mng->resize_rwl);
733 : 0 : mlx5_aso_completion_handle(sh);
734 [ # # ]: 0 : if (sq->next == n) {
735 : : /* End of loop: wait 1 second. */
736 : : us = US_PER_S;
737 : 0 : sq->next = 0;
738 : : }
739 : 0 : mlx5_aso_sq_enqueue_burst(sh, n);
740 [ # # ]: 0 : if (rte_eal_alarm_set(us, mlx5_flow_aso_alarm, sh))
741 : 0 : DRV_LOG(ERR, "Cannot reinitialize aso alarm.");
742 : 0 : }
743 : :
744 : : /**
745 : : * API to start ASO access using ASO SQ.
746 : : *
747 : : * @param[in] sh
748 : : * Pointer to shared device context.
749 : : *
750 : : * @return
751 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
752 : : */
753 : : int
754 : 0 : mlx5_aso_flow_hit_queue_poll_start(struct mlx5_dev_ctx_shared *sh)
755 : : {
756 [ # # ]: 0 : if (rte_eal_alarm_set(US_PER_S, mlx5_flow_aso_alarm, sh)) {
757 : 0 : DRV_LOG(ERR, "Cannot reinitialize ASO age alarm.");
758 : 0 : return -rte_errno;
759 : : }
760 : : return 0;
761 : : }
762 : :
763 : : /**
764 : : * API to stop ASO access using ASO SQ.
765 : : *
766 : : * @param[in] sh
767 : : * Pointer to shared device context.
768 : : *
769 : : * @return
770 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
771 : : */
772 : : int
773 : 0 : mlx5_aso_flow_hit_queue_poll_stop(struct mlx5_dev_ctx_shared *sh)
774 : : {
775 : : int retries = 1024;
776 : :
777 [ # # ]: 0 : if (!sh->aso_age_mng->aso_sq.sq_obj.sq)
778 : : return -EINVAL;
779 : 0 : rte_errno = 0;
780 [ # # ]: 0 : while (--retries) {
781 : 0 : rte_eal_alarm_cancel(mlx5_flow_aso_alarm, sh);
782 [ # # ]: 0 : if (rte_errno != EINPROGRESS)
783 : : break;
784 : : rte_pause();
785 : : }
786 : 0 : return -rte_errno;
787 : : }
788 : :
789 : : static uint16_t
790 : 0 : mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh,
791 : : struct mlx5_aso_sq *sq,
792 : : struct mlx5_aso_mtr *aso_mtr,
793 : : struct mlx5_mtr_bulk *bulk,
794 : : bool need_lock,
795 : : struct mlx5_hw_q_job *job,
796 : : bool push)
797 : : {
798 : : volatile struct mlx5_aso_wqe *wqe = NULL;
799 : : struct mlx5_flow_meter_info *fm = NULL;
800 : : struct mlx5_flow_meter_profile *fmp;
801 : 0 : uint16_t size = 1 << sq->log_desc_n;
802 : 0 : uint16_t mask = size - 1;
803 : : uint16_t res;
804 : : uint32_t dseg_idx = 0;
805 : : struct mlx5_aso_mtr_pool *pool = NULL;
806 : : uint32_t param_le;
807 : : int id;
808 : :
809 [ # # ]: 0 : if (need_lock)
810 : 0 : rte_spinlock_lock(&sq->sqsl);
811 : 0 : res = size - (uint16_t)(sq->head - sq->tail);
812 [ # # ]: 0 : if (unlikely(!res)) {
813 : 0 : DRV_LOG(ERR, "Fail: SQ is full and no free WQE to send");
814 [ # # ]: 0 : if (need_lock)
815 : 0 : rte_spinlock_unlock(&sq->sqsl);
816 : 0 : return 0;
817 : : }
818 : 0 : wqe = &sq->sq_obj.aso_wqes[sq->head & mask];
819 : 0 : rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]);
820 : : /* Fill next WQE. */
821 : : fm = &aso_mtr->fm;
822 [ # # ]: 0 : sq->elts[sq->head & mask].user_data = job ? job : (void *)aso_mtr;
823 [ # # ]: 0 : if (aso_mtr->type == ASO_METER_INDIRECT) {
824 [ # # ]: 0 : if (likely(sh->config.dv_flow_en == 2))
825 : 0 : pool = aso_mtr->pool;
826 : : else
827 : 0 : pool = container_of(aso_mtr, struct mlx5_aso_mtr_pool,
828 : : mtrs[aso_mtr->offset]);
829 : 0 : id = pool->devx_obj->id;
830 : : } else {
831 : 0 : id = bulk->devx_obj->id;
832 : : }
833 [ # # ]: 0 : wqe->general_cseg.misc = rte_cpu_to_be_32(id +
834 : : (aso_mtr->offset >> 1));
835 : 0 : wqe->general_cseg.opcode =
836 [ # # ]: 0 : rte_cpu_to_be_32(MLX5_OPCODE_ACCESS_ASO |
837 : : (ASO_OPC_MOD_POLICER << WQE_CSEG_OPC_MOD_OFFSET) |
838 : : sq->pi << WQE_CSEG_WQE_INDEX_OFFSET);
839 : : /* There are 2 meters in one ASO cache line. */
840 : 0 : dseg_idx = aso_mtr->offset & 0x1;
841 : 0 : wqe->aso_cseg.data_mask =
842 [ # # # # : 0 : RTE_BE64(MLX5_IFC_FLOW_METER_PARAM_MASK << (32 * !dseg_idx));
# # # # #
# # # # #
# # ]
843 [ # # ]: 0 : if (fm->is_enable) {
844 : 0 : wqe->aso_dseg.mtrs[dseg_idx].cbs_cir =
845 : 0 : fm->profile->srtcm_prm.cbs_cir;
846 : 0 : wqe->aso_dseg.mtrs[dseg_idx].ebs_eir =
847 : 0 : fm->profile->srtcm_prm.ebs_eir;
848 : : } else {
849 : 0 : wqe->aso_dseg.mtrs[dseg_idx].cbs_cir =
850 : : RTE_BE32(MLX5_IFC_FLOW_METER_DISABLE_CBS_CIR_VAL);
851 : 0 : wqe->aso_dseg.mtrs[dseg_idx].ebs_eir = 0;
852 : : }
853 : 0 : fmp = fm->profile;
854 : : param_le = (1 << ASO_DSEG_VALID_OFFSET);
855 [ # # ]: 0 : if (fm->color_aware)
856 : : param_le |= (MLX5_FLOW_COLOR_UNDEFINED << ASO_DSEG_SC_OFFSET);
857 : : else
858 : : param_le |= (MLX5_FLOW_COLOR_GREEN << ASO_DSEG_SC_OFFSET);
859 [ # # ]: 0 : if (fmp->profile.packet_mode)
860 : 0 : param_le |= (MLX5_METER_MODE_PKT << ASO_DSEG_MTR_MODE);
861 : 0 : wqe->aso_dseg.mtrs[dseg_idx].v_bo_sc_bbog_mm = RTE_BE32(param_le);
862 [ # # # # ]: 0 : switch (fmp->profile.alg) {
863 : 0 : case RTE_MTR_SRTCM_RFC2697:
864 : : /* Only needed for RFC2697. */
865 [ # # ]: 0 : if (fm->profile->srtcm_prm.ebs_eir)
866 : 0 : wqe->aso_dseg.mtrs[dseg_idx].v_bo_sc_bbog_mm |=
867 : : RTE_BE32(1 << ASO_DSEG_BO_OFFSET);
868 : : break;
869 : 0 : case RTE_MTR_TRTCM_RFC2698:
870 : 0 : wqe->aso_dseg.mtrs[dseg_idx].v_bo_sc_bbog_mm |=
871 : : RTE_BE32(1 << ASO_DSEG_BBOG_OFFSET);
872 : 0 : break;
873 : 0 : case RTE_MTR_TRTCM_RFC4115:
874 : 0 : wqe->aso_dseg.mtrs[dseg_idx].v_bo_sc_bbog_mm |=
875 : : RTE_BE32(1 << ASO_DSEG_BO_OFFSET);
876 : 0 : break;
877 : : default:
878 : : break;
879 : : }
880 : : /*
881 : : * Note:
882 : : * Due to software performance reason, the token fields will not be
883 : : * set when posting the WQE to ASO SQ. It will be filled by the HW
884 : : * automatically.
885 : : */
886 : 0 : sq->head++;
887 : 0 : sq->pi += 2;/* Each WQE contains 2 WQEBB's. */
888 [ # # ]: 0 : if (push) {
889 : 0 : mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe,
890 : 0 : sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR],
891 : 0 : !sh->tx_uar.dbnc);
892 : 0 : sq->db_pi = sq->pi;
893 : : }
894 : 0 : sq->db = wqe;
895 [ # # ]: 0 : if (need_lock)
896 : 0 : rte_spinlock_unlock(&sq->sqsl);
897 : : return 1;
898 : : }
899 : :
900 : : static void
901 : 0 : mlx5_aso_mtr_completion_handle(struct mlx5_aso_sq *sq, bool need_lock)
902 : : {
903 : : struct mlx5_aso_cq *cq = &sq->cq;
904 : : volatile struct mlx5_cqe *restrict cqe;
905 : 0 : const unsigned int cq_size = 1 << cq->log_desc_n;
906 : 0 : const unsigned int mask = cq_size - 1;
907 : : uint32_t idx;
908 : 0 : uint32_t next_idx = cq->cq_ci & mask;
909 : : uint16_t max;
910 : : uint16_t i, n = 0;
911 : : int ret;
912 : :
913 [ # # ]: 0 : if (need_lock)
914 : 0 : rte_spinlock_lock(&sq->sqsl);
915 : 0 : max = (uint16_t)(sq->head - sq->tail);
916 [ # # ]: 0 : if (unlikely(!max)) {
917 [ # # ]: 0 : if (need_lock)
918 : 0 : rte_spinlock_unlock(&sq->sqsl);
919 : 0 : return;
920 : : }
921 : : do {
922 : 0 : idx = next_idx;
923 : 0 : next_idx = (cq->cq_ci + 1) & mask;
924 : 0 : rte_prefetch0(&cq->cq_obj.cqes[next_idx]);
925 : 0 : cqe = &cq->cq_obj.cqes[idx];
926 [ # # ]: 0 : ret = check_cqe(cqe, cq_size, cq->cq_ci);
927 : : /*
928 : : * Be sure owner read is done before any other cookie field or
929 : : * opaque field.
930 : : */
931 : 0 : rte_io_rmb();
932 : : if (ret != MLX5_CQE_STATUS_SW_OWN) {
933 [ # # ]: 0 : if (likely(ret == MLX5_CQE_STATUS_HW_OWN))
934 : : break;
935 : 0 : mlx5_aso_cqe_err_handle(sq);
936 : : } else {
937 : 0 : n++;
938 : : }
939 : 0 : cq->cq_ci++;
940 : : } while (1);
941 [ # # ]: 0 : if (likely(n)) {
942 : : uint8_t exp_state = ASO_METER_WAIT;
943 : : struct mlx5_aso_mtr *aso_mtr;
944 : : __rte_unused bool verdict;
945 : :
946 [ # # ]: 0 : for (i = 0; i < n; ++i) {
947 : 0 : aso_mtr = sq->elts[(sq->tail + i) & mask].mtr;
948 : : MLX5_ASSERT(aso_mtr);
949 : 0 : verdict = __atomic_compare_exchange_n(&aso_mtr->state,
950 : : &exp_state, ASO_METER_READY,
951 : : false, __ATOMIC_RELAXED,
952 : : __ATOMIC_RELAXED);
953 : : MLX5_ASSERT(verdict);
954 : : }
955 : 0 : sq->tail += n;
956 : 0 : rte_io_wmb();
957 [ # # ]: 0 : cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
958 : : }
959 [ # # ]: 0 : if (need_lock)
960 : 0 : rte_spinlock_unlock(&sq->sqsl);
961 : : }
962 : :
963 : : static __rte_always_inline struct mlx5_aso_sq *
964 : : mlx5_aso_mtr_select_sq(struct mlx5_dev_ctx_shared *sh, uint32_t queue,
965 : : struct mlx5_aso_mtr *mtr, bool *need_lock)
966 : : {
967 : : struct mlx5_aso_sq *sq;
968 : :
969 [ # # ]: 0 : if (likely(sh->config.dv_flow_en == 2) &&
970 [ # # # # ]: 0 : mtr->type == ASO_METER_INDIRECT) {
971 [ # # ]: 0 : if (queue == MLX5_HW_INV_QUEUE) {
972 : 0 : sq = &mtr->pool->sq[mtr->pool->nb_sq - 1];
973 : : *need_lock = true;
974 : : } else {
975 : 0 : sq = &mtr->pool->sq[queue];
976 : : *need_lock = false;
977 : : }
978 : : } else {
979 : 0 : sq = &sh->mtrmng->pools_mng.sq;
980 : : *need_lock = true;
981 : : }
982 : : return sq;
983 : : }
984 : :
985 : : #if defined(HAVE_MLX5_HWS_SUPPORT)
986 : : static void
987 : 0 : mlx5_aso_poll_cq_mtr_hws(struct mlx5_priv *priv, struct mlx5_aso_sq *sq)
988 : : {
989 : : #define MLX5_HWS_MTR_CMPL_NUM 4
990 : :
991 : : int i, ret;
992 : : struct mlx5_aso_mtr *mtr;
993 : : uint8_t exp_state = ASO_METER_WAIT;
994 : : struct rte_flow_op_result res[MLX5_HWS_MTR_CMPL_NUM];
995 : : __rte_unused bool verdict;
996 : :
997 : 0 : rte_spinlock_lock(&sq->sqsl);
998 : 0 : repeat:
999 : 0 : ret = mlx5_aso_pull_completion(sq, res, MLX5_HWS_MTR_CMPL_NUM);
1000 [ # # ]: 0 : if (ret) {
1001 [ # # ]: 0 : for (i = 0; i < ret; i++) {
1002 : 0 : struct mlx5_hw_q_job *job = res[i].user_data;
1003 : :
1004 : : MLX5_ASSERT(job);
1005 : 0 : mtr = mlx5_ipool_get(priv->hws_mpool->idx_pool,
1006 : 0 : MLX5_INDIRECT_ACTION_IDX_GET(job->action));
1007 : : MLX5_ASSERT(mtr);
1008 : 0 : verdict = __atomic_compare_exchange_n(&mtr->state,
1009 : : &exp_state, ASO_METER_READY,
1010 : : false, __ATOMIC_RELAXED,
1011 : : __ATOMIC_RELAXED);
1012 : : MLX5_ASSERT(verdict);
1013 : 0 : flow_hw_job_put(priv, job, CTRL_QUEUE_ID(priv));
1014 : : }
1015 [ # # ]: 0 : if (ret == MLX5_HWS_MTR_CMPL_NUM)
1016 : 0 : goto repeat;
1017 : : }
1018 : : rte_spinlock_unlock(&sq->sqsl);
1019 : :
1020 : : #undef MLX5_HWS_MTR_CMPL_NUM
1021 : 0 : }
1022 : : #else
1023 : : static void
1024 : : mlx5_aso_poll_cq_mtr_hws(__rte_unused struct mlx5_priv *priv, __rte_unused struct mlx5_aso_sq *sq)
1025 : : {
1026 : : MLX5_ASSERT(false);
1027 : : }
1028 : : #endif
1029 : :
1030 : : static void
1031 : 0 : mlx5_aso_poll_cq_mtr_sws(__rte_unused struct mlx5_priv *priv,
1032 : : struct mlx5_aso_sq *sq)
1033 : : {
1034 : 0 : mlx5_aso_mtr_completion_handle(sq, true);
1035 : 0 : }
1036 : :
1037 : : typedef void (*poll_cq_t)(struct mlx5_priv *, struct mlx5_aso_sq *);
1038 : :
1039 : : /**
1040 : : * Update meter parameter by send WQE.
1041 : : *
1042 : : * @param[in] dev
1043 : : * Pointer to Ethernet device.
1044 : : * @param[in] priv
1045 : : * Pointer to mlx5 private data structure.
1046 : : * @param[in] fm
1047 : : * Pointer to flow meter to be modified.
1048 : : *
1049 : : * @return
1050 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1051 : : */
1052 : : int
1053 : 0 : mlx5_aso_meter_update_by_wqe(struct mlx5_priv *priv, uint32_t queue,
1054 : : struct mlx5_aso_mtr *mtr,
1055 : : struct mlx5_mtr_bulk *bulk,
1056 : : struct mlx5_hw_q_job *job, bool push)
1057 : : {
1058 : : bool need_lock;
1059 [ # # ]: 0 : struct mlx5_dev_ctx_shared *sh = priv->sh;
1060 : : struct mlx5_aso_sq *sq =
1061 : : mlx5_aso_mtr_select_sq(sh, queue, mtr, &need_lock);
1062 : : uint32_t poll_wqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
1063 : : poll_cq_t poll_mtr_cq =
1064 [ # # ]: 0 : job ? mlx5_aso_poll_cq_mtr_hws : mlx5_aso_poll_cq_mtr_sws;
1065 : : int ret;
1066 : :
1067 [ # # ]: 0 : if (queue != MLX5_HW_INV_QUEUE) {
1068 : 0 : ret = mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr, bulk,
1069 : : need_lock, job, push);
1070 [ # # ]: 0 : return ret > 0 ? 0 : -1;
1071 : : }
1072 : : do {
1073 : 0 : poll_mtr_cq(priv, sq);
1074 [ # # ]: 0 : if (mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr, bulk,
1075 : : need_lock, job, true))
1076 : : return 0;
1077 : : /* Waiting for wqe resource. */
1078 : 0 : rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
1079 [ # # ]: 0 : } while (--poll_wqe_times);
1080 : 0 : DRV_LOG(ERR, "Fail to send WQE for ASO meter offset %d",
1081 : : mtr->offset);
1082 : 0 : return -1;
1083 : : }
1084 : :
1085 : : /**
1086 : : * Wait for meter to be ready.
1087 : : *
1088 : : * @param[in] dev
1089 : : * Pointer to Ethernet device.
1090 : : * @param[in] priv
1091 : : * Pointer to mlx5 private data structure.
1092 : : * @param[in] fm
1093 : : * Pointer to flow meter to be modified.
1094 : : *
1095 : : * @return
1096 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1097 : : */
1098 : : int
1099 : 0 : mlx5_aso_mtr_wait(struct mlx5_priv *priv,
1100 : : struct mlx5_aso_mtr *mtr, bool is_tmpl_api)
1101 : : {
1102 : : bool need_lock;
1103 : : struct mlx5_aso_sq *sq;
1104 : 0 : struct mlx5_dev_ctx_shared *sh = priv->sh;
1105 : : uint32_t poll_cqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
1106 : 0 : uint8_t state = __atomic_load_n(&mtr->state, __ATOMIC_RELAXED);
1107 : : poll_cq_t poll_mtr_cq =
1108 [ # # ]: 0 : is_tmpl_api ? mlx5_aso_poll_cq_mtr_hws : mlx5_aso_poll_cq_mtr_sws;
1109 : :
1110 [ # # ]: 0 : if (state == ASO_METER_READY || state == ASO_METER_WAIT_ASYNC)
1111 : : return 0;
1112 : : sq = mlx5_aso_mtr_select_sq(sh, MLX5_HW_INV_QUEUE, mtr, &need_lock);
1113 : : do {
1114 : 0 : poll_mtr_cq(priv, sq);
1115 [ # # ]: 0 : if (__atomic_load_n(&mtr->state, __ATOMIC_RELAXED) ==
1116 : : ASO_METER_READY)
1117 : : return 0;
1118 : : /* Waiting for CQE ready. */
1119 : 0 : rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
1120 [ # # ]: 0 : } while (--poll_cqe_times);
1121 : 0 : DRV_LOG(ERR, "Fail to poll CQE ready for ASO meter offset %d",
1122 : : mtr->offset);
1123 : 0 : return -1;
1124 : : }
1125 : :
1126 : : static inline struct mlx5_aso_sq*
1127 : : __mlx5_aso_ct_get_sq_in_hws(uint32_t queue,
1128 : : struct mlx5_aso_ct_pool *pool)
1129 : : {
1130 : : return (queue == MLX5_HW_INV_QUEUE) ?
1131 [ # # # # : 0 : pool->shared_sq : &pool->sq[queue];
# # # # ]
1132 : : }
1133 : :
1134 : : static inline struct mlx5_aso_sq*
1135 : : __mlx5_aso_ct_get_sq_in_sws(struct mlx5_dev_ctx_shared *sh,
1136 : : struct mlx5_aso_ct_action *ct)
1137 : : {
1138 : 0 : return &sh->ct_mng->aso_sqs[ct->offset & (MLX5_ASO_CT_SQ_NUM - 1)];
1139 : : }
1140 : :
1141 : : static inline struct mlx5_aso_ct_pool*
1142 : : __mlx5_aso_ct_get_pool(struct mlx5_dev_ctx_shared *sh,
1143 : : struct mlx5_aso_ct_action *ct)
1144 : : {
1145 [ # # # # ]: 0 : if (likely(sh->config.dv_flow_en == 2))
1146 : 0 : return ct->pool;
1147 : 0 : return container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]);
1148 : : }
1149 : :
1150 : : int
1151 : 0 : mlx5_aso_ct_queue_uninit(struct mlx5_dev_ctx_shared *sh,
1152 : : struct mlx5_aso_ct_pools_mng *ct_mng)
1153 : : {
1154 : : uint32_t i;
1155 : :
1156 : : /* 64B per object for query. */
1157 [ # # ]: 0 : for (i = 0; i < ct_mng->nb_sq; i++) {
1158 [ # # ]: 0 : if (ct_mng->aso_sqs[i].mr.addr)
1159 : 0 : mlx5_aso_dereg_mr(sh->cdev, &ct_mng->aso_sqs[i].mr);
1160 : 0 : mlx5_aso_destroy_sq(&ct_mng->aso_sqs[i]);
1161 : : }
1162 : 0 : return 0;
1163 : : }
1164 : :
1165 : : /**
1166 : : * API to create and initialize CT Send Queue used for ASO access.
1167 : : *
1168 : : * @param[in] sh
1169 : : * Pointer to shared device context.
1170 : : * @param[in] ct_mng
1171 : : * Pointer to the CT management struct.
1172 : : * *param[in] nb_queues
1173 : : * Number of queues to be allocated.
1174 : : *
1175 : : * @return
1176 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1177 : : */
1178 : : int
1179 : 0 : mlx5_aso_ct_queue_init(struct mlx5_dev_ctx_shared *sh,
1180 : : struct mlx5_aso_ct_pools_mng *ct_mng,
1181 : : uint32_t nb_queues)
1182 : : {
1183 : : uint32_t i;
1184 : :
1185 : : /* 64B per object for query. */
1186 [ # # ]: 0 : for (i = 0; i < nb_queues; i++) {
1187 [ # # ]: 0 : if (mlx5_aso_reg_mr(sh->cdev, 64 * (1 << MLX5_ASO_QUEUE_LOG_DESC),
1188 : : &ct_mng->aso_sqs[i].mr))
1189 : 0 : goto error;
1190 [ # # ]: 0 : if (mlx5_aso_sq_create(sh->cdev, &ct_mng->aso_sqs[i],
1191 : : sh->tx_uar.obj,
1192 : : MLX5_ASO_QUEUE_LOG_DESC))
1193 : 0 : goto error;
1194 : 0 : mlx5_aso_ct_init_sq(&ct_mng->aso_sqs[i]);
1195 : : }
1196 : 0 : ct_mng->nb_sq = nb_queues;
1197 : 0 : return 0;
1198 : : error:
1199 : : do {
1200 [ # # ]: 0 : if (ct_mng->aso_sqs[i].mr.addr)
1201 : 0 : mlx5_aso_dereg_mr(sh->cdev, &ct_mng->aso_sqs[i].mr);
1202 : 0 : mlx5_aso_destroy_sq(&ct_mng->aso_sqs[i]);
1203 [ # # ]: 0 : } while (i--);
1204 : 0 : ct_mng->nb_sq = 0;
1205 : 0 : return -1;
1206 : : }
1207 : :
1208 : : /*
1209 : : * Post a WQE to the ASO CT SQ to modify the context.
1210 : : *
1211 : : * @param[in] sh
1212 : : * Pointer to shared device context.
1213 : : * @param[in] ct
1214 : : * Pointer to the generic CT structure related to the context.
1215 : : * @param[in] profile
1216 : : * Pointer to configuration profile.
1217 : : *
1218 : : * @return
1219 : : * 1 on success (WQE number), 0 on failure.
1220 : : */
1221 : : static uint16_t
1222 : 0 : mlx5_aso_ct_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh,
1223 : : struct mlx5_aso_sq *sq,
1224 : : struct mlx5_aso_ct_action *ct,
1225 : : const struct rte_flow_action_conntrack *profile,
1226 : : bool need_lock,
1227 : : void *user_data,
1228 : : bool push)
1229 : : {
1230 : : volatile struct mlx5_aso_wqe *wqe = NULL;
1231 : 0 : uint16_t size = 1 << sq->log_desc_n;
1232 : 0 : uint16_t mask = size - 1;
1233 : : uint16_t res;
1234 : : struct mlx5_aso_ct_pool *pool;
1235 : : void *desg;
1236 : : void *orig_dir;
1237 : : void *reply_dir;
1238 : :
1239 [ # # ]: 0 : if (need_lock)
1240 : 0 : rte_spinlock_lock(&sq->sqsl);
1241 : : /* Prevent other threads to update the index. */
1242 : 0 : res = size - (uint16_t)(sq->head - sq->tail);
1243 [ # # ]: 0 : if (unlikely(!res)) {
1244 [ # # ]: 0 : if (need_lock)
1245 : 0 : rte_spinlock_unlock(&sq->sqsl);
1246 : 0 : DRV_LOG(ERR, "Fail: SQ is full and no free WQE to send");
1247 : 0 : return 0;
1248 : : }
1249 : 0 : wqe = &sq->sq_obj.aso_wqes[sq->head & mask];
1250 : 0 : rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]);
1251 : : /* Fill next WQE. */
1252 [ # # ]: 0 : MLX5_ASO_CT_UPDATE_STATE(ct,
1253 : : user_data ? ASO_CONNTRACK_WAIT_ASYNC : ASO_CONNTRACK_WAIT);
1254 [ # # ]: 0 : if (user_data) {
1255 : 0 : sq->elts[sq->head & mask].user_data = user_data;
1256 : : } else {
1257 : 0 : sq->elts[sq->head & mask].ct = ct;
1258 : 0 : sq->elts[sq->head & mask].query_data = NULL;
1259 : : }
1260 : : pool = __mlx5_aso_ct_get_pool(sh, ct);
1261 : :
1262 : : /* Each WQE will have a single CT object. */
1263 [ # # ]: 0 : wqe->general_cseg.misc = rte_cpu_to_be_32(pool->devx_obj->id +
1264 : : ct->offset);
1265 [ # # ]: 0 : wqe->general_cseg.opcode = rte_cpu_to_be_32(MLX5_OPCODE_ACCESS_ASO |
1266 : : (ASO_OPC_MOD_CONNECTION_TRACKING <<
1267 : : WQE_CSEG_OPC_MOD_OFFSET) |
1268 : : sq->pi << WQE_CSEG_WQE_INDEX_OFFSET);
1269 : 0 : wqe->aso_cseg.operand_masks = rte_cpu_to_be_32
1270 : : (0u |
1271 : : (ASO_OPER_LOGICAL_OR << ASO_CSEG_COND_OPER_OFFSET) |
1272 : : (ASO_OP_ALWAYS_TRUE << ASO_CSEG_COND_1_OPER_OFFSET) |
1273 : : (ASO_OP_ALWAYS_TRUE << ASO_CSEG_COND_0_OPER_OFFSET) |
1274 : : (BYTEWISE_64BYTE << ASO_CSEG_DATA_MASK_MODE_OFFSET));
1275 : 0 : wqe->aso_cseg.data_mask = UINT64_MAX;
1276 : : /* To make compiler happy. */
1277 : : desg = (void *)(uintptr_t)wqe->aso_dseg.data;
1278 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, valid, 1);
1279 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, state, profile->state);
1280 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, freeze_track, !profile->enable);
1281 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, connection_assured,
1282 : : profile->live_connection);
1283 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, sack_permitted, profile->selective_ack);
1284 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, challenged_acked,
1285 : : profile->challenge_ack_passed);
1286 : : /* Heartbeat, retransmission_counter, retranmission_limit_exceeded: 0 */
1287 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, heartbeat, 0);
1288 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, max_ack_window,
1289 : : profile->max_ack_window);
1290 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, retransmission_counter, 0);
1291 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, retranmission_limit_exceeded, 0);
1292 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, retranmission_limit,
1293 : : profile->retransmission_limit);
1294 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_scale,
1295 : : profile->reply_dir.scale);
1296 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_close_initiated,
1297 : : profile->reply_dir.close_initiated);
1298 : : /* Both directions will use the same liberal mode. */
1299 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_liberal_enabled,
1300 : : profile->liberal_mode);
1301 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_data_unacked,
1302 : : profile->reply_dir.data_unacked);
1303 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_max_ack,
1304 : : profile->reply_dir.last_ack_seen);
1305 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_scale,
1306 : : profile->original_dir.scale);
1307 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_close_initiated,
1308 : : profile->original_dir.close_initiated);
1309 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_liberal_enabled,
1310 : : profile->liberal_mode);
1311 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_data_unacked,
1312 : : profile->original_dir.data_unacked);
1313 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_max_ack,
1314 : : profile->original_dir.last_ack_seen);
1315 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_win, profile->last_window);
1316 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_dir, profile->last_direction);
1317 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_index, profile->last_index);
1318 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_seq, profile->last_seq);
1319 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_ack, profile->last_ack);
1320 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_end, profile->last_end);
1321 : : orig_dir = MLX5_ADDR_OF(conn_track_aso, desg, original_dir);
1322 [ # # ]: 0 : MLX5_SET(tcp_window_params, orig_dir, sent_end,
1323 : : profile->original_dir.sent_end);
1324 [ # # ]: 0 : MLX5_SET(tcp_window_params, orig_dir, reply_end,
1325 : : profile->original_dir.reply_end);
1326 [ # # ]: 0 : MLX5_SET(tcp_window_params, orig_dir, max_win,
1327 : : profile->original_dir.max_win);
1328 [ # # ]: 0 : MLX5_SET(tcp_window_params, orig_dir, max_ack,
1329 : : profile->original_dir.max_ack);
1330 : : reply_dir = MLX5_ADDR_OF(conn_track_aso, desg, reply_dir);
1331 [ # # ]: 0 : MLX5_SET(tcp_window_params, reply_dir, sent_end,
1332 : : profile->reply_dir.sent_end);
1333 [ # # ]: 0 : MLX5_SET(tcp_window_params, reply_dir, reply_end,
1334 : : profile->reply_dir.reply_end);
1335 [ # # ]: 0 : MLX5_SET(tcp_window_params, reply_dir, max_win,
1336 : : profile->reply_dir.max_win);
1337 [ # # ]: 0 : MLX5_SET(tcp_window_params, reply_dir, max_ack,
1338 : : profile->reply_dir.max_ack);
1339 : 0 : sq->head++;
1340 : 0 : sq->pi += 2; /* Each WQE contains 2 WQEBB's. */
1341 [ # # ]: 0 : if (push) {
1342 : 0 : mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe,
1343 : 0 : sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR],
1344 : 0 : !sh->tx_uar.dbnc);
1345 : 0 : sq->db_pi = sq->pi;
1346 : : }
1347 : 0 : sq->db = wqe;
1348 [ # # ]: 0 : if (need_lock)
1349 : 0 : rte_spinlock_unlock(&sq->sqsl);
1350 : : return 1;
1351 : : }
1352 : :
1353 : : /*
1354 : : * Update the status field of CTs to indicate ready to be used by flows.
1355 : : * A continuous number of CTs since last update.
1356 : : *
1357 : : * @param[in] sq
1358 : : * Pointer to ASO CT SQ.
1359 : : * @param[in] num
1360 : : * Number of CT structures to be updated.
1361 : : *
1362 : : * @return
1363 : : * 0 on success, a negative value.
1364 : : */
1365 : : static void
1366 : 0 : mlx5_aso_ct_status_update(struct mlx5_aso_sq *sq, uint16_t num)
1367 : : {
1368 : 0 : uint16_t size = 1 << sq->log_desc_n;
1369 : 0 : uint16_t mask = size - 1;
1370 : : uint16_t i;
1371 : : struct mlx5_aso_ct_action *ct = NULL;
1372 : : uint16_t idx;
1373 : :
1374 [ # # ]: 0 : for (i = 0; i < num; i++) {
1375 : 0 : idx = (uint16_t)((sq->tail + i) & mask);
1376 : 0 : ct = sq->elts[idx].ct;
1377 : : MLX5_ASSERT(ct);
1378 : 0 : MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_READY);
1379 [ # # ]: 0 : if (sq->elts[idx].query_data)
1380 : 0 : rte_memcpy(sq->elts[idx].query_data,
1381 [ # # ]: 0 : (char *)((uintptr_t)sq->mr.addr + idx * 64),
1382 : : 64);
1383 : : }
1384 : 0 : }
1385 : :
1386 : : /*
1387 : : * Post a WQE to the ASO CT SQ to query the current context.
1388 : : *
1389 : : * @param[in] sh
1390 : : * Pointer to shared device context.
1391 : : * @param[in] ct
1392 : : * Pointer to the generic CT structure related to the context.
1393 : : * @param[in] data
1394 : : * Pointer to data area to be filled.
1395 : : *
1396 : : * @return
1397 : : * 1 on success (WQE number), 0 on failure.
1398 : : */
1399 : : static int
1400 : 0 : mlx5_aso_ct_sq_query_single(struct mlx5_dev_ctx_shared *sh,
1401 : : struct mlx5_aso_sq *sq,
1402 : : struct mlx5_aso_ct_action *ct, char *data,
1403 : : bool need_lock,
1404 : : void *user_data,
1405 : : bool push)
1406 : : {
1407 : : volatile struct mlx5_aso_wqe *wqe = NULL;
1408 : 0 : uint16_t size = 1 << sq->log_desc_n;
1409 : 0 : uint16_t mask = size - 1;
1410 : : uint16_t res;
1411 : : uint16_t wqe_idx;
1412 : : struct mlx5_aso_ct_pool *pool;
1413 : : enum mlx5_aso_ct_state state =
1414 : 0 : __atomic_load_n(&ct->state, __ATOMIC_RELAXED);
1415 : :
1416 [ # # ]: 0 : if (state == ASO_CONNTRACK_FREE) {
1417 : 0 : DRV_LOG(ERR, "Fail: No context to query");
1418 : 0 : return -1;
1419 [ # # ]: 0 : } else if (state == ASO_CONNTRACK_WAIT) {
1420 : : return 0;
1421 : : }
1422 [ # # ]: 0 : if (need_lock)
1423 : 0 : rte_spinlock_lock(&sq->sqsl);
1424 : 0 : res = size - (uint16_t)(sq->head - sq->tail);
1425 [ # # ]: 0 : if (unlikely(!res)) {
1426 [ # # ]: 0 : if (need_lock)
1427 : 0 : rte_spinlock_unlock(&sq->sqsl);
1428 : 0 : DRV_LOG(ERR, "Fail: SQ is full and no free WQE to send");
1429 : 0 : return 0;
1430 : : }
1431 [ # # ]: 0 : MLX5_ASO_CT_UPDATE_STATE(ct,
1432 : : user_data ? ASO_CONNTRACK_WAIT_ASYNC : ASO_CONNTRACK_QUERY);
1433 : 0 : wqe = &sq->sq_obj.aso_wqes[sq->head & mask];
1434 : : /* Confirm the location and address of the prefetch instruction. */
1435 : 0 : rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]);
1436 : : /* Fill next WQE. */
1437 : 0 : wqe_idx = sq->head & mask;
1438 : : /* Check if this is async mode. */
1439 [ # # ]: 0 : if (user_data) {
1440 : : struct mlx5_hw_q_job *job = (struct mlx5_hw_q_job *)user_data;
1441 : :
1442 : 0 : sq->elts[wqe_idx].ct = user_data;
1443 : 0 : job->query.hw = (char *)((uintptr_t)sq->mr.addr + wqe_idx * 64);
1444 : : } else {
1445 : 0 : sq->elts[wqe_idx].query_data = data;
1446 : 0 : sq->elts[wqe_idx].ct = ct;
1447 : : }
1448 : : pool = __mlx5_aso_ct_get_pool(sh, ct);
1449 : : /* Each WQE will have a single CT object. */
1450 [ # # ]: 0 : wqe->general_cseg.misc = rte_cpu_to_be_32(pool->devx_obj->id +
1451 : : ct->offset);
1452 [ # # ]: 0 : wqe->general_cseg.opcode = rte_cpu_to_be_32(MLX5_OPCODE_ACCESS_ASO |
1453 : : (ASO_OPC_MOD_CONNECTION_TRACKING <<
1454 : : WQE_CSEG_OPC_MOD_OFFSET) |
1455 : : sq->pi << WQE_CSEG_WQE_INDEX_OFFSET);
1456 : : /*
1457 : : * There is no write request is required.
1458 : : * ASO_OPER_LOGICAL_AND and ASO_OP_ALWAYS_FALSE are both 0.
1459 : : * "BYTEWISE_64BYTE" is needed for a whole context.
1460 : : * Set to 0 directly to reduce an endian swap. (Modify should rewrite.)
1461 : : * "data_mask" is ignored.
1462 : : * Buffer address was already filled during initialization.
1463 : : */
1464 : 0 : wqe->aso_cseg.operand_masks = rte_cpu_to_be_32(BYTEWISE_64BYTE <<
1465 : : ASO_CSEG_DATA_MASK_MODE_OFFSET);
1466 : 0 : wqe->aso_cseg.data_mask = 0;
1467 : 0 : sq->head++;
1468 : : /*
1469 : : * Each WQE contains 2 WQEBB's, even though
1470 : : * data segment is not used in this case.
1471 : : */
1472 : 0 : sq->pi += 2;
1473 [ # # ]: 0 : if (push) {
1474 : 0 : mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe,
1475 : 0 : sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR],
1476 : 0 : !sh->tx_uar.dbnc);
1477 : 0 : sq->db_pi = sq->pi;
1478 : : }
1479 : 0 : sq->db = wqe;
1480 [ # # ]: 0 : if (need_lock)
1481 : 0 : rte_spinlock_unlock(&sq->sqsl);
1482 : : return 1;
1483 : : }
1484 : :
1485 : : /*
1486 : : * Handle completions from WQEs sent to ASO CT.
1487 : : *
1488 : : * @param[in] mng
1489 : : * Pointer to the CT pools management structure.
1490 : : */
1491 : : static void
1492 : 0 : mlx5_aso_ct_completion_handle(struct mlx5_dev_ctx_shared *sh __rte_unused,
1493 : : struct mlx5_aso_sq *sq,
1494 : : bool need_lock)
1495 : : {
1496 : : struct mlx5_aso_cq *cq = &sq->cq;
1497 : : volatile struct mlx5_cqe *restrict cqe;
1498 : 0 : const uint32_t cq_size = 1 << cq->log_desc_n;
1499 : 0 : const uint32_t mask = cq_size - 1;
1500 : : uint32_t idx;
1501 : : uint32_t next_idx;
1502 : : uint16_t max;
1503 : : uint16_t n = 0;
1504 : : int ret;
1505 : :
1506 [ # # ]: 0 : if (need_lock)
1507 : 0 : rte_spinlock_lock(&sq->sqsl);
1508 : 0 : max = (uint16_t)(sq->head - sq->tail);
1509 [ # # ]: 0 : if (unlikely(!max)) {
1510 [ # # ]: 0 : if (need_lock)
1511 : 0 : rte_spinlock_unlock(&sq->sqsl);
1512 : 0 : return;
1513 : : }
1514 : 0 : next_idx = cq->cq_ci & mask;
1515 : : do {
1516 : 0 : idx = next_idx;
1517 : 0 : next_idx = (cq->cq_ci + 1) & mask;
1518 : : /* Need to confirm the position of the prefetch. */
1519 : 0 : rte_prefetch0(&cq->cq_obj.cqes[next_idx]);
1520 : 0 : cqe = &cq->cq_obj.cqes[idx];
1521 [ # # ]: 0 : ret = check_cqe(cqe, cq_size, cq->cq_ci);
1522 : : /*
1523 : : * Be sure owner read is done before any other cookie field or
1524 : : * opaque field.
1525 : : */
1526 : 0 : rte_io_rmb();
1527 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
1528 [ # # ]: 0 : if (likely(ret == MLX5_CQE_STATUS_HW_OWN))
1529 : : break;
1530 : 0 : mlx5_aso_cqe_err_handle(sq);
1531 : : } else {
1532 : 0 : n++;
1533 : : }
1534 : 0 : cq->cq_ci++;
1535 : : } while (1);
1536 [ # # ]: 0 : if (likely(n)) {
1537 : 0 : mlx5_aso_ct_status_update(sq, n);
1538 : 0 : sq->tail += n;
1539 : 0 : rte_io_wmb();
1540 [ # # ]: 0 : cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
1541 : : }
1542 [ # # ]: 0 : if (need_lock)
1543 : 0 : rte_spinlock_unlock(&sq->sqsl);
1544 : : }
1545 : :
1546 : : /*
1547 : : * Update connection tracking ASO context by sending WQE.
1548 : : *
1549 : : * @param[in] sh
1550 : : * Pointer to mlx5_dev_ctx_shared object.
1551 : : * @param[in] queue
1552 : : * The queue index.
1553 : : * @param[in] ct
1554 : : * Pointer to connection tracking offload object.
1555 : : * @param[in] profile
1556 : : * Pointer to connection tracking TCP parameter.
1557 : : *
1558 : : * @return
1559 : : * 0 on success, -1 on failure.
1560 : : */
1561 : : int
1562 [ # # ]: 0 : mlx5_aso_ct_update_by_wqe(struct mlx5_dev_ctx_shared *sh,
1563 : : uint32_t queue,
1564 : : struct mlx5_aso_ct_action *ct,
1565 : : const struct rte_flow_action_conntrack *profile,
1566 : : void *user_data,
1567 : : bool push)
1568 : : {
1569 : : uint32_t poll_wqe_times = MLX5_CT_POLL_WQE_CQE_TIMES;
1570 : : struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct);
1571 : : struct mlx5_aso_sq *sq;
1572 : 0 : bool need_lock = !!(queue == MLX5_HW_INV_QUEUE);
1573 : : int ret;
1574 : :
1575 [ # # ]: 0 : if (sh->config.dv_flow_en == 2)
1576 : : sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool);
1577 : : else
1578 : : sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct);
1579 [ # # ]: 0 : if (queue != MLX5_HW_INV_QUEUE) {
1580 : 0 : ret = mlx5_aso_ct_sq_enqueue_single(sh, sq, ct, profile,
1581 : : need_lock, user_data, push);
1582 [ # # ]: 0 : return ret > 0 ? 0 : -1;
1583 : : }
1584 : : do {
1585 : 0 : mlx5_aso_ct_completion_handle(sh, sq, need_lock);
1586 [ # # ]: 0 : if (mlx5_aso_ct_sq_enqueue_single(sh, sq, ct, profile,
1587 : : need_lock, NULL, true))
1588 : : return 0;
1589 : : /* Waiting for wqe resource. */
1590 : 0 : rte_delay_us_sleep(10u);
1591 [ # # ]: 0 : } while (--poll_wqe_times);
1592 : 0 : DRV_LOG(ERR, "Fail to send WQE for ASO CT %d in pool %d",
1593 : : ct->offset, pool->index);
1594 : 0 : return -1;
1595 : : }
1596 : :
1597 : : /*
1598 : : * The routine is used to wait for WQE completion to continue with queried data.
1599 : : *
1600 : : * @param[in] sh
1601 : : * Pointer to mlx5_dev_ctx_shared object.
1602 : : * @param[in] queue
1603 : : * The queue which CT works on..
1604 : : * @param[in] ct
1605 : : * Pointer to connection tracking offload object.
1606 : : *
1607 : : * @return
1608 : : * 0 on success, -1 on failure.
1609 : : */
1610 : : int
1611 [ # # ]: 0 : mlx5_aso_ct_wait_ready(struct mlx5_dev_ctx_shared *sh, uint32_t queue,
1612 : : struct mlx5_aso_ct_action *ct)
1613 : : {
1614 : : uint32_t poll_cqe_times = MLX5_CT_POLL_WQE_CQE_TIMES;
1615 : : struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct);
1616 : : struct mlx5_aso_sq *sq;
1617 : 0 : bool need_lock = !!(queue == MLX5_HW_INV_QUEUE);
1618 : :
1619 [ # # ]: 0 : if (sh->config.dv_flow_en == 2)
1620 : : sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool);
1621 : : else
1622 : : sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct);
1623 [ # # ]: 0 : if (__atomic_load_n(&ct->state, __ATOMIC_RELAXED) ==
1624 : : ASO_CONNTRACK_READY)
1625 : : return 0;
1626 : : do {
1627 : 0 : mlx5_aso_ct_completion_handle(sh, sq, need_lock);
1628 [ # # ]: 0 : if (__atomic_load_n(&ct->state, __ATOMIC_RELAXED) ==
1629 : : ASO_CONNTRACK_READY)
1630 : : return 0;
1631 : : /* Waiting for CQE ready, consider should block or sleep. */
1632 : 0 : rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
1633 [ # # ]: 0 : } while (--poll_cqe_times);
1634 : 0 : DRV_LOG(ERR, "Fail to poll CQE for ASO CT %d in pool %d",
1635 : : ct->offset, pool->index);
1636 : 0 : return -1;
1637 : : }
1638 : :
1639 : : /*
1640 : : * Convert the hardware conntrack data format into the profile.
1641 : : *
1642 : : * @param[in] profile
1643 : : * Pointer to conntrack profile to be filled after query.
1644 : : * @param[in] wdata
1645 : : * Pointer to data fetched from hardware.
1646 : : */
1647 : : void
1648 : 0 : mlx5_aso_ct_obj_analyze(struct rte_flow_action_conntrack *profile,
1649 : : char *wdata)
1650 : : {
1651 : : void *o_dir = MLX5_ADDR_OF(conn_track_aso, wdata, original_dir);
1652 : : void *r_dir = MLX5_ADDR_OF(conn_track_aso, wdata, reply_dir);
1653 : :
1654 : : /* MLX5_GET16 should be taken into consideration. */
1655 : 0 : profile->state = (enum rte_flow_conntrack_state)
1656 [ # # ]: 0 : MLX5_GET(conn_track_aso, wdata, state);
1657 [ # # ]: 0 : profile->enable = !MLX5_GET(conn_track_aso, wdata, freeze_track);
1658 [ # # ]: 0 : profile->selective_ack = MLX5_GET(conn_track_aso, wdata,
1659 : : sack_permitted);
1660 [ # # ]: 0 : profile->live_connection = MLX5_GET(conn_track_aso, wdata,
1661 : : connection_assured);
1662 [ # # ]: 0 : profile->challenge_ack_passed = MLX5_GET(conn_track_aso, wdata,
1663 : : challenged_acked);
1664 [ # # ]: 0 : profile->max_ack_window = MLX5_GET(conn_track_aso, wdata,
1665 : : max_ack_window);
1666 [ # # ]: 0 : profile->retransmission_limit = MLX5_GET(conn_track_aso, wdata,
1667 : : retranmission_limit);
1668 [ # # ]: 0 : profile->last_window = MLX5_GET(conn_track_aso, wdata, last_win);
1669 [ # # ]: 0 : profile->last_direction = MLX5_GET(conn_track_aso, wdata, last_dir);
1670 : 0 : profile->last_index = (enum rte_flow_conntrack_tcp_last_index)
1671 [ # # ]: 0 : MLX5_GET(conn_track_aso, wdata, last_index);
1672 [ # # ]: 0 : profile->last_seq = MLX5_GET(conn_track_aso, wdata, last_seq);
1673 [ # # ]: 0 : profile->last_ack = MLX5_GET(conn_track_aso, wdata, last_ack);
1674 [ # # ]: 0 : profile->last_end = MLX5_GET(conn_track_aso, wdata, last_end);
1675 : 0 : profile->liberal_mode = MLX5_GET(conn_track_aso, wdata,
1676 [ # # # # ]: 0 : reply_direction_tcp_liberal_enabled) |
1677 : 0 : MLX5_GET(conn_track_aso, wdata,
1678 : : original_direction_tcp_liberal_enabled);
1679 : : /* No liberal in the RTE structure profile. */
1680 [ # # ]: 0 : profile->reply_dir.scale = MLX5_GET(conn_track_aso, wdata,
1681 : : reply_direction_tcp_scale);
1682 [ # # ]: 0 : profile->reply_dir.close_initiated = MLX5_GET(conn_track_aso, wdata,
1683 : : reply_direction_tcp_close_initiated);
1684 [ # # ]: 0 : profile->reply_dir.data_unacked = MLX5_GET(conn_track_aso, wdata,
1685 : : reply_direction_tcp_data_unacked);
1686 [ # # ]: 0 : profile->reply_dir.last_ack_seen = MLX5_GET(conn_track_aso, wdata,
1687 : : reply_direction_tcp_max_ack);
1688 [ # # ]: 0 : profile->reply_dir.sent_end = MLX5_GET(tcp_window_params,
1689 : : r_dir, sent_end);
1690 [ # # ]: 0 : profile->reply_dir.reply_end = MLX5_GET(tcp_window_params,
1691 : : r_dir, reply_end);
1692 [ # # ]: 0 : profile->reply_dir.max_win = MLX5_GET(tcp_window_params,
1693 : : r_dir, max_win);
1694 [ # # ]: 0 : profile->reply_dir.max_ack = MLX5_GET(tcp_window_params,
1695 : : r_dir, max_ack);
1696 [ # # ]: 0 : profile->original_dir.scale = MLX5_GET(conn_track_aso, wdata,
1697 : : original_direction_tcp_scale);
1698 [ # # ]: 0 : profile->original_dir.close_initiated = MLX5_GET(conn_track_aso, wdata,
1699 : : original_direction_tcp_close_initiated);
1700 [ # # ]: 0 : profile->original_dir.data_unacked = MLX5_GET(conn_track_aso, wdata,
1701 : : original_direction_tcp_data_unacked);
1702 [ # # ]: 0 : profile->original_dir.last_ack_seen = MLX5_GET(conn_track_aso, wdata,
1703 : : original_direction_tcp_max_ack);
1704 [ # # ]: 0 : profile->original_dir.sent_end = MLX5_GET(tcp_window_params,
1705 : : o_dir, sent_end);
1706 [ # # ]: 0 : profile->original_dir.reply_end = MLX5_GET(tcp_window_params,
1707 : : o_dir, reply_end);
1708 [ # # ]: 0 : profile->original_dir.max_win = MLX5_GET(tcp_window_params,
1709 : : o_dir, max_win);
1710 [ # # ]: 0 : profile->original_dir.max_ack = MLX5_GET(tcp_window_params,
1711 : : o_dir, max_ack);
1712 : 0 : }
1713 : :
1714 : : /*
1715 : : * Query connection tracking information parameter by send WQE.
1716 : : *
1717 : : * @param[in] dev
1718 : : * Pointer to Ethernet device.
1719 : : * @param[in] ct
1720 : : * Pointer to connection tracking offload object.
1721 : : * @param[out] profile
1722 : : * Pointer to connection tracking TCP information.
1723 : : *
1724 : : * @return
1725 : : * 0 on success, -1 on failure.
1726 : : */
1727 : : int
1728 [ # # ]: 0 : mlx5_aso_ct_query_by_wqe(struct mlx5_dev_ctx_shared *sh,
1729 : : uint32_t queue,
1730 : : struct mlx5_aso_ct_action *ct,
1731 : : struct rte_flow_action_conntrack *profile,
1732 : : void *user_data, bool push)
1733 : : {
1734 : : uint32_t poll_wqe_times = MLX5_CT_POLL_WQE_CQE_TIMES;
1735 : : struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct);
1736 : : struct mlx5_aso_sq *sq;
1737 : 0 : bool need_lock = !!(queue == MLX5_HW_INV_QUEUE);
1738 : : char out_data[64 * 2];
1739 : : int ret;
1740 : :
1741 [ # # ]: 0 : if (sh->config.dv_flow_en == 2)
1742 : : sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool);
1743 : : else
1744 : : sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct);
1745 [ # # ]: 0 : if (queue != MLX5_HW_INV_QUEUE) {
1746 : 0 : ret = mlx5_aso_ct_sq_query_single(sh, sq, ct, out_data,
1747 : : need_lock, user_data, push);
1748 [ # # ]: 0 : return ret > 0 ? 0 : -1;
1749 : : }
1750 : : do {
1751 : 0 : mlx5_aso_ct_completion_handle(sh, sq, need_lock);
1752 : 0 : ret = mlx5_aso_ct_sq_query_single(sh, sq, ct, out_data,
1753 : : need_lock, NULL, true);
1754 [ # # ]: 0 : if (ret < 0)
1755 : 0 : return ret;
1756 [ # # ]: 0 : else if (ret > 0)
1757 : 0 : goto data_handle;
1758 : : /* Waiting for wqe resource or state. */
1759 : : else
1760 : 0 : rte_delay_us_sleep(10u);
1761 [ # # ]: 0 : } while (--poll_wqe_times);
1762 : 0 : DRV_LOG(ERR, "Fail to send WQE for ASO CT %d in pool %d",
1763 : : ct->offset, pool->index);
1764 : 0 : return -1;
1765 : : data_handle:
1766 : 0 : ret = mlx5_aso_ct_wait_ready(sh, queue, ct);
1767 [ # # ]: 0 : if (!ret)
1768 : 0 : mlx5_aso_ct_obj_analyze(profile, out_data);
1769 : : return ret;
1770 : : }
1771 : :
1772 : : /*
1773 : : * Make sure the conntrack context is synchronized with hardware before
1774 : : * creating a flow rule that uses it.
1775 : : *
1776 : : * @param[in] sh
1777 : : * Pointer to shared device context.
1778 : : * @param[in] ct
1779 : : * Pointer to connection tracking offload object.
1780 : : *
1781 : : * @return
1782 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1783 : : */
1784 : : int
1785 [ # # ]: 0 : mlx5_aso_ct_available(struct mlx5_dev_ctx_shared *sh,
1786 : : uint32_t queue,
1787 : : struct mlx5_aso_ct_action *ct)
1788 : : {
1789 : : struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct);
1790 : : struct mlx5_aso_sq *sq;
1791 : 0 : bool need_lock = !!(queue == MLX5_HW_INV_QUEUE);
1792 : : uint32_t poll_cqe_times = MLX5_CT_POLL_WQE_CQE_TIMES;
1793 : : enum mlx5_aso_ct_state state =
1794 : 0 : __atomic_load_n(&ct->state, __ATOMIC_RELAXED);
1795 : :
1796 [ # # ]: 0 : if (sh->config.dv_flow_en == 2)
1797 : : sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool);
1798 : : else
1799 : : sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct);
1800 [ # # ]: 0 : if (state == ASO_CONNTRACK_FREE) {
1801 : 0 : rte_errno = ENXIO;
1802 : 0 : return -rte_errno;
1803 : 0 : } else if (state == ASO_CONNTRACK_READY ||
1804 [ # # ]: 0 : state == ASO_CONNTRACK_QUERY ||
1805 : : state == ASO_CONNTRACK_WAIT_ASYNC) {
1806 : : return 0;
1807 : : }
1808 : : do {
1809 : 0 : mlx5_aso_ct_completion_handle(sh, sq, need_lock);
1810 : 0 : state = __atomic_load_n(&ct->state, __ATOMIC_RELAXED);
1811 [ # # ]: 0 : if (state == ASO_CONNTRACK_READY ||
1812 : : state == ASO_CONNTRACK_QUERY)
1813 : : return 0;
1814 : : /* Waiting for CQE ready, consider should block or sleep. */
1815 : 0 : rte_delay_us_block(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
1816 [ # # ]: 0 : } while (--poll_cqe_times);
1817 : 0 : rte_errno = EBUSY;
1818 : 0 : return -rte_errno;
1819 : : }
1820 : :
1821 : : int
1822 : 0 : mlx5_aso_cnt_queue_init(struct mlx5_dev_ctx_shared *sh)
1823 : : {
1824 : : struct mlx5_hws_aso_mng *aso_mng = NULL;
1825 : : uint8_t idx;
1826 : : struct mlx5_aso_sq *sq;
1827 : :
1828 : : MLX5_ASSERT(sh);
1829 : : MLX5_ASSERT(sh->cnt_svc);
1830 : 0 : aso_mng = &sh->cnt_svc->aso_mng;
1831 : 0 : aso_mng->sq_num = HWS_CNT_ASO_SQ_NUM;
1832 [ # # ]: 0 : for (idx = 0; idx < HWS_CNT_ASO_SQ_NUM; idx++) {
1833 : 0 : sq = &aso_mng->sqs[idx];
1834 [ # # ]: 0 : if (mlx5_aso_sq_create(sh->cdev, sq, sh->tx_uar.obj,
1835 : : MLX5_ASO_CNT_QUEUE_LOG_DESC))
1836 : 0 : goto error;
1837 : 0 : mlx5_aso_cnt_init_sq(sq);
1838 : : }
1839 : : return 0;
1840 : : error:
1841 : 0 : mlx5_aso_cnt_queue_uninit(sh);
1842 : 0 : return -1;
1843 : : }
1844 : :
1845 : : void
1846 : 0 : mlx5_aso_cnt_queue_uninit(struct mlx5_dev_ctx_shared *sh)
1847 : : {
1848 : : uint16_t idx;
1849 : :
1850 [ # # ]: 0 : for (idx = 0; idx < sh->cnt_svc->aso_mng.sq_num; idx++)
1851 : 0 : mlx5_aso_destroy_sq(&sh->cnt_svc->aso_mng.sqs[idx]);
1852 : 0 : sh->cnt_svc->aso_mng.sq_num = 0;
1853 : 0 : }
1854 : :
1855 : : static uint16_t
1856 : 0 : mlx5_aso_cnt_sq_enqueue_burst(struct mlx5_hws_cnt_pool *cpool,
1857 : : struct mlx5_dev_ctx_shared *sh,
1858 : : struct mlx5_aso_sq *sq, uint32_t n,
1859 : : uint32_t offset, uint32_t dcs_id_base)
1860 : : {
1861 : : volatile struct mlx5_aso_wqe *wqe;
1862 : 0 : uint16_t size = 1 << sq->log_desc_n;
1863 : 0 : uint16_t mask = size - 1;
1864 : : uint16_t max;
1865 : : uint32_t upper_offset = offset;
1866 : : uint64_t addr;
1867 : : uint32_t ctrl_gen_id = 0;
1868 : 0 : uint8_t opcmod = sh->cdev->config.hca_attr.flow_access_aso_opc_mod;
1869 [ # # ]: 0 : rte_be32_t lkey = rte_cpu_to_be_32(cpool->raw_mng->mr.lkey);
1870 : 0 : uint16_t aso_n = (uint16_t)(RTE_ALIGN_CEIL(n, 4) / 4);
1871 : : uint32_t ccntid;
1872 : :
1873 : 0 : max = RTE_MIN(size - (uint16_t)(sq->head - sq->tail), aso_n);
1874 [ # # ]: 0 : if (unlikely(!max))
1875 : : return 0;
1876 : 0 : upper_offset += (max * 4);
1877 : : /* Because only one burst at one time, we can use the same elt. */
1878 : 0 : sq->elts[0].burst_size = max;
1879 : : ctrl_gen_id = dcs_id_base;
1880 : 0 : ctrl_gen_id /= 4;
1881 : : do {
1882 : 0 : ccntid = upper_offset - max * 4;
1883 : 0 : wqe = &sq->sq_obj.aso_wqes[sq->head & mask];
1884 : 0 : rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]);
1885 [ # # ]: 0 : wqe->general_cseg.misc = rte_cpu_to_be_32(ctrl_gen_id);
1886 : 0 : wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ONLY_FIRST_ERR <<
1887 : : MLX5_COMP_MODE_OFFSET);
1888 [ # # ]: 0 : wqe->general_cseg.opcode = rte_cpu_to_be_32
1889 : : (MLX5_OPCODE_ACCESS_ASO |
1890 : : (opcmod <<
1891 : : WQE_CSEG_OPC_MOD_OFFSET) |
1892 : : (sq->pi <<
1893 : : WQE_CSEG_WQE_INDEX_OFFSET));
1894 : 0 : addr = (uint64_t)RTE_PTR_ADD(cpool->raw_mng->raw,
1895 : : ccntid * sizeof(struct flow_counter_stats));
1896 [ # # ]: 0 : wqe->aso_cseg.va_h = rte_cpu_to_be_32((uint32_t)(addr >> 32));
1897 [ # # ]: 0 : wqe->aso_cseg.va_l_r = rte_cpu_to_be_32((uint32_t)addr | 1u);
1898 : 0 : wqe->aso_cseg.lkey = lkey;
1899 : 0 : sq->pi += 2; /* Each WQE contains 2 WQEBB's. */
1900 : 0 : sq->head++;
1901 : 0 : sq->next++;
1902 : 0 : ctrl_gen_id++;
1903 : 0 : max--;
1904 [ # # ]: 0 : } while (max);
1905 : 0 : wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ALWAYS <<
1906 : : MLX5_COMP_MODE_OFFSET);
1907 : 0 : mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe,
1908 : 0 : sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR],
1909 : 0 : !sh->tx_uar.dbnc);
1910 : 0 : return sq->elts[0].burst_size;
1911 : : }
1912 : :
1913 : : static uint16_t
1914 : 0 : mlx5_aso_cnt_completion_handle(struct mlx5_aso_sq *sq)
1915 : : {
1916 : : struct mlx5_aso_cq *cq = &sq->cq;
1917 : : volatile struct mlx5_cqe *restrict cqe;
1918 : 0 : const unsigned int cq_size = 1 << cq->log_desc_n;
1919 : 0 : const unsigned int mask = cq_size - 1;
1920 : : uint32_t idx;
1921 : 0 : uint32_t next_idx = cq->cq_ci & mask;
1922 : 0 : const uint16_t max = (uint16_t)(sq->head - sq->tail);
1923 : : uint16_t i = 0;
1924 : : int ret;
1925 [ # # ]: 0 : if (unlikely(!max))
1926 : : return 0;
1927 : : idx = next_idx;
1928 : 0 : next_idx = (cq->cq_ci + 1) & mask;
1929 : 0 : rte_prefetch0(&cq->cq_obj.cqes[next_idx]);
1930 : 0 : cqe = &cq->cq_obj.cqes[idx];
1931 [ # # ]: 0 : ret = check_cqe(cqe, cq_size, cq->cq_ci);
1932 : : /*
1933 : : * Be sure owner read is done before any other cookie field or
1934 : : * opaque field.
1935 : : */
1936 : 0 : rte_io_rmb();
1937 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
1938 [ # # ]: 0 : if (likely(ret == MLX5_CQE_STATUS_HW_OWN))
1939 : : return 0; /* return immediately. */
1940 : 0 : mlx5_aso_cqe_err_handle(sq);
1941 : : }
1942 : 0 : i += sq->elts[0].burst_size;
1943 : 0 : sq->elts[0].burst_size = 0;
1944 : 0 : cq->cq_ci++;
1945 [ # # ]: 0 : if (likely(i)) {
1946 : 0 : sq->tail += i;
1947 : 0 : rte_io_wmb();
1948 [ # # ]: 0 : cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
1949 : : }
1950 : : return i;
1951 : : }
1952 : :
1953 : : static uint16_t
1954 : 0 : mlx5_aso_cnt_query_one_dcs(struct mlx5_dev_ctx_shared *sh,
1955 : : struct mlx5_hws_cnt_pool *cpool,
1956 : : uint8_t dcs_idx, uint32_t num)
1957 : : {
1958 : 0 : uint32_t dcs_id = cpool->dcs_mng.dcs[dcs_idx].obj->id;
1959 : 0 : uint64_t cnt_num = cpool->dcs_mng.dcs[dcs_idx].batch_sz;
1960 : : uint64_t left;
1961 : 0 : uint32_t iidx = cpool->dcs_mng.dcs[dcs_idx].iidx;
1962 : : uint32_t offset;
1963 : : uint16_t mask;
1964 : : uint16_t sq_idx;
1965 : : uint64_t burst_sz = (uint64_t)(1 << MLX5_ASO_CNT_QUEUE_LOG_DESC) * 4 *
1966 : : sh->cnt_svc->aso_mng.sq_num;
1967 : : uint64_t qburst_sz = burst_sz / sh->cnt_svc->aso_mng.sq_num;
1968 : : uint64_t n;
1969 : : struct mlx5_aso_sq *sq;
1970 : :
1971 : 0 : cnt_num = RTE_MIN(num, cnt_num);
1972 : : left = cnt_num;
1973 [ # # ]: 0 : while (left) {
1974 : : mask = 0;
1975 [ # # ]: 0 : for (sq_idx = 0; sq_idx < sh->cnt_svc->aso_mng.sq_num;
1976 : 0 : sq_idx++) {
1977 [ # # ]: 0 : if (left == 0) {
1978 : 0 : mask |= (1 << sq_idx);
1979 : 0 : continue;
1980 : : }
1981 : 0 : n = RTE_MIN(left, qburst_sz);
1982 : 0 : offset = cnt_num - left;
1983 : 0 : offset += iidx;
1984 : 0 : mlx5_aso_cnt_sq_enqueue_burst(cpool, sh,
1985 : 0 : &sh->cnt_svc->aso_mng.sqs[sq_idx], n,
1986 : : offset, dcs_id);
1987 : 0 : left -= n;
1988 : : }
1989 : : do {
1990 [ # # ]: 0 : for (sq_idx = 0; sq_idx < sh->cnt_svc->aso_mng.sq_num;
1991 : 0 : sq_idx++) {
1992 : 0 : sq = &sh->cnt_svc->aso_mng.sqs[sq_idx];
1993 [ # # ]: 0 : if (mlx5_aso_cnt_completion_handle(sq))
1994 : 0 : mask |= (1 << sq_idx);
1995 : : }
1996 [ # # ]: 0 : } while (mask < ((1 << sh->cnt_svc->aso_mng.sq_num) - 1));
1997 : : }
1998 : 0 : return cnt_num;
1999 : : }
2000 : :
2001 : : /*
2002 : : * Query FW counter via ASO WQE.
2003 : : *
2004 : : * ASO query counter use _sync_ mode, means:
2005 : : * 1. each SQ issue one burst with several WQEs
2006 : : * 2. ask for CQE at last WQE
2007 : : * 3. busy poll CQ of each SQ's
2008 : : * 4. If all SQ's CQE are received then goto step 1, issue next burst
2009 : : *
2010 : : * @param[in] sh
2011 : : * Pointer to shared device.
2012 : : * @param[in] cpool
2013 : : * Pointer to counter pool.
2014 : : *
2015 : : * @return
2016 : : * 0 on success, -1 on failure.
2017 : : */
2018 : : int
2019 [ # # ]: 0 : mlx5_aso_cnt_query(struct mlx5_dev_ctx_shared *sh,
2020 : : struct mlx5_hws_cnt_pool *cpool)
2021 : : {
2022 : : uint32_t idx;
2023 : : uint32_t num;
2024 : 0 : uint32_t cnt_num = mlx5_hws_cnt_pool_get_size(cpool) -
2025 : 0 : rte_ring_count(cpool->free_list);
2026 : :
2027 [ # # ]: 0 : for (idx = 0; idx < cpool->dcs_mng.batch_total; idx++) {
2028 : 0 : num = RTE_MIN(cnt_num, cpool->dcs_mng.dcs[idx].batch_sz);
2029 : 0 : mlx5_aso_cnt_query_one_dcs(sh, cpool, idx, num);
2030 : 0 : cnt_num -= num;
2031 [ # # ]: 0 : if (cnt_num == 0)
2032 : : break;
2033 : : }
2034 : 0 : return 0;
2035 : : }
|