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