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 : : void *user_data,
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].mtr = user_data ? user_data : 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 : : mlx5_aso_mtrs_status_update(struct mlx5_aso_sq *sq, uint16_t aso_mtrs_nums)
902 : : {
903 : 0 : uint16_t size = 1 << sq->log_desc_n;
904 : 0 : uint16_t mask = size - 1;
905 : : uint16_t i;
906 : : struct mlx5_aso_mtr *aso_mtr = NULL;
907 : : uint8_t exp_state = ASO_METER_WAIT;
908 : :
909 [ # # ]: 0 : for (i = 0; i < aso_mtrs_nums; ++i) {
910 : 0 : aso_mtr = sq->elts[(sq->tail + i) & mask].mtr;
911 : : MLX5_ASSERT(aso_mtr);
912 : 0 : (void)__atomic_compare_exchange_n(&aso_mtr->state,
913 : : &exp_state, ASO_METER_READY,
914 : : false, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
915 : : }
916 : : }
917 : :
918 : : static void
919 : 0 : mlx5_aso_mtr_completion_handle(struct mlx5_aso_sq *sq, bool need_lock)
920 : : {
921 : : struct mlx5_aso_cq *cq = &sq->cq;
922 : : volatile struct mlx5_cqe *restrict cqe;
923 : 0 : const unsigned int cq_size = 1 << cq->log_desc_n;
924 : 0 : const unsigned int mask = cq_size - 1;
925 : : uint32_t idx;
926 : 0 : uint32_t next_idx = cq->cq_ci & mask;
927 : : uint16_t max;
928 : : uint16_t n = 0;
929 : : int ret;
930 : :
931 [ # # ]: 0 : if (need_lock)
932 : 0 : rte_spinlock_lock(&sq->sqsl);
933 : 0 : max = (uint16_t)(sq->head - sq->tail);
934 [ # # ]: 0 : if (unlikely(!max)) {
935 [ # # ]: 0 : if (need_lock)
936 : 0 : rte_spinlock_unlock(&sq->sqsl);
937 : 0 : return;
938 : : }
939 : : do {
940 : 0 : idx = next_idx;
941 : 0 : next_idx = (cq->cq_ci + 1) & mask;
942 : 0 : rte_prefetch0(&cq->cq_obj.cqes[next_idx]);
943 : 0 : cqe = &cq->cq_obj.cqes[idx];
944 [ # # ]: 0 : ret = check_cqe(cqe, cq_size, cq->cq_ci);
945 : : /*
946 : : * Be sure owner read is done before any other cookie field or
947 : : * opaque field.
948 : : */
949 : 0 : rte_io_rmb();
950 : : if (ret != MLX5_CQE_STATUS_SW_OWN) {
951 [ # # ]: 0 : if (likely(ret == MLX5_CQE_STATUS_HW_OWN))
952 : : break;
953 : 0 : mlx5_aso_cqe_err_handle(sq);
954 : : } else {
955 : 0 : n++;
956 : : }
957 : 0 : cq->cq_ci++;
958 : : } while (1);
959 [ # # ]: 0 : if (likely(n)) {
960 : : mlx5_aso_mtrs_status_update(sq, n);
961 : 0 : sq->tail += n;
962 : 0 : rte_io_wmb();
963 [ # # ]: 0 : cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
964 : : }
965 [ # # ]: 0 : if (need_lock)
966 : 0 : rte_spinlock_unlock(&sq->sqsl);
967 : : }
968 : :
969 : : /**
970 : : * Update meter parameter by send WQE.
971 : : *
972 : : * @param[in] dev
973 : : * Pointer to Ethernet device.
974 : : * @param[in] priv
975 : : * Pointer to mlx5 private data structure.
976 : : * @param[in] fm
977 : : * Pointer to flow meter to be modified.
978 : : *
979 : : * @return
980 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
981 : : */
982 : : int
983 : 0 : mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh, uint32_t queue,
984 : : struct mlx5_aso_mtr *mtr,
985 : : struct mlx5_mtr_bulk *bulk,
986 : : void *user_data,
987 : : bool push)
988 : : {
989 : : struct mlx5_aso_sq *sq;
990 : : uint32_t poll_wqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
991 : : bool need_lock;
992 : : int ret;
993 : :
994 [ # # ]: 0 : if (likely(sh->config.dv_flow_en == 2) &&
995 [ # # ]: 0 : mtr->type == ASO_METER_INDIRECT) {
996 [ # # ]: 0 : if (queue == MLX5_HW_INV_QUEUE) {
997 : 0 : sq = &mtr->pool->sq[mtr->pool->nb_sq - 1];
998 : : need_lock = true;
999 : : } else {
1000 : 0 : sq = &mtr->pool->sq[queue];
1001 : : need_lock = false;
1002 : : }
1003 : : } else {
1004 : 0 : sq = &sh->mtrmng->pools_mng.sq;
1005 : : need_lock = true;
1006 : : }
1007 [ # # ]: 0 : if (queue != MLX5_HW_INV_QUEUE) {
1008 : 0 : ret = mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr, bulk,
1009 : : need_lock, user_data, push);
1010 [ # # ]: 0 : return ret > 0 ? 0 : -1;
1011 : : }
1012 : : do {
1013 : 0 : mlx5_aso_mtr_completion_handle(sq, need_lock);
1014 [ # # ]: 0 : if (mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr, bulk,
1015 : : need_lock, NULL, true))
1016 : : return 0;
1017 : : /* Waiting for wqe resource. */
1018 : 0 : rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
1019 [ # # ]: 0 : } while (--poll_wqe_times);
1020 : 0 : DRV_LOG(ERR, "Fail to send WQE for ASO meter offset %d",
1021 : : mtr->offset);
1022 : 0 : return -1;
1023 : : }
1024 : :
1025 : : /**
1026 : : * Wait for meter to be ready.
1027 : : *
1028 : : * @param[in] dev
1029 : : * Pointer to Ethernet device.
1030 : : * @param[in] priv
1031 : : * Pointer to mlx5 private data structure.
1032 : : * @param[in] fm
1033 : : * Pointer to flow meter to be modified.
1034 : : *
1035 : : * @return
1036 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1037 : : */
1038 : : int
1039 : 0 : mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh, uint32_t queue,
1040 : : struct mlx5_aso_mtr *mtr)
1041 : : {
1042 : : struct mlx5_aso_sq *sq;
1043 : : uint32_t poll_cqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
1044 : : uint8_t state;
1045 : : bool need_lock;
1046 : :
1047 [ # # ]: 0 : if (likely(sh->config.dv_flow_en == 2) &&
1048 [ # # ]: 0 : mtr->type == ASO_METER_INDIRECT) {
1049 [ # # ]: 0 : if (queue == MLX5_HW_INV_QUEUE) {
1050 : 0 : sq = &mtr->pool->sq[mtr->pool->nb_sq - 1];
1051 : : need_lock = true;
1052 : : } else {
1053 : 0 : sq = &mtr->pool->sq[queue];
1054 : : need_lock = false;
1055 : : }
1056 : : } else {
1057 : 0 : sq = &sh->mtrmng->pools_mng.sq;
1058 : : need_lock = true;
1059 : : }
1060 : 0 : state = __atomic_load_n(&mtr->state, __ATOMIC_RELAXED);
1061 [ # # ]: 0 : if (state == ASO_METER_READY || state == ASO_METER_WAIT_ASYNC)
1062 : : return 0;
1063 : : do {
1064 : 0 : mlx5_aso_mtr_completion_handle(sq, need_lock);
1065 [ # # ]: 0 : if (__atomic_load_n(&mtr->state, __ATOMIC_RELAXED) ==
1066 : : ASO_METER_READY)
1067 : : return 0;
1068 : : /* Waiting for CQE ready. */
1069 : 0 : rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
1070 [ # # ]: 0 : } while (--poll_cqe_times);
1071 : 0 : DRV_LOG(ERR, "Fail to poll CQE ready for ASO meter offset %d",
1072 : : mtr->offset);
1073 : 0 : return -1;
1074 : : }
1075 : :
1076 : : static inline struct mlx5_aso_sq*
1077 : : __mlx5_aso_ct_get_sq_in_hws(uint32_t queue,
1078 : : struct mlx5_aso_ct_pool *pool)
1079 : : {
1080 : : return (queue == MLX5_HW_INV_QUEUE) ?
1081 [ # # # # : 0 : pool->shared_sq : &pool->sq[queue];
# # # # ]
1082 : : }
1083 : :
1084 : : static inline struct mlx5_aso_sq*
1085 : : __mlx5_aso_ct_get_sq_in_sws(struct mlx5_dev_ctx_shared *sh,
1086 : : struct mlx5_aso_ct_action *ct)
1087 : : {
1088 : 0 : return &sh->ct_mng->aso_sqs[ct->offset & (MLX5_ASO_CT_SQ_NUM - 1)];
1089 : : }
1090 : :
1091 : : static inline struct mlx5_aso_ct_pool*
1092 : : __mlx5_aso_ct_get_pool(struct mlx5_dev_ctx_shared *sh,
1093 : : struct mlx5_aso_ct_action *ct)
1094 : : {
1095 [ # # # # ]: 0 : if (likely(sh->config.dv_flow_en == 2))
1096 : 0 : return ct->pool;
1097 : 0 : return container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]);
1098 : : }
1099 : :
1100 : : int
1101 : 0 : mlx5_aso_ct_queue_uninit(struct mlx5_dev_ctx_shared *sh,
1102 : : struct mlx5_aso_ct_pools_mng *ct_mng)
1103 : : {
1104 : : uint32_t i;
1105 : :
1106 : : /* 64B per object for query. */
1107 [ # # ]: 0 : for (i = 0; i < ct_mng->nb_sq; i++) {
1108 [ # # ]: 0 : if (ct_mng->aso_sqs[i].mr.addr)
1109 : 0 : mlx5_aso_dereg_mr(sh->cdev, &ct_mng->aso_sqs[i].mr);
1110 : 0 : mlx5_aso_destroy_sq(&ct_mng->aso_sqs[i]);
1111 : : }
1112 : 0 : return 0;
1113 : : }
1114 : :
1115 : : /**
1116 : : * API to create and initialize CT Send Queue used for ASO access.
1117 : : *
1118 : : * @param[in] sh
1119 : : * Pointer to shared device context.
1120 : : * @param[in] ct_mng
1121 : : * Pointer to the CT management struct.
1122 : : * *param[in] nb_queues
1123 : : * Number of queues to be allocated.
1124 : : *
1125 : : * @return
1126 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1127 : : */
1128 : : int
1129 : 0 : mlx5_aso_ct_queue_init(struct mlx5_dev_ctx_shared *sh,
1130 : : struct mlx5_aso_ct_pools_mng *ct_mng,
1131 : : uint32_t nb_queues)
1132 : : {
1133 : : uint32_t i;
1134 : :
1135 : : /* 64B per object for query. */
1136 [ # # ]: 0 : for (i = 0; i < nb_queues; i++) {
1137 [ # # ]: 0 : if (mlx5_aso_reg_mr(sh->cdev, 64 * (1 << MLX5_ASO_QUEUE_LOG_DESC),
1138 : : &ct_mng->aso_sqs[i].mr))
1139 : 0 : goto error;
1140 [ # # ]: 0 : if (mlx5_aso_sq_create(sh->cdev, &ct_mng->aso_sqs[i],
1141 : : sh->tx_uar.obj,
1142 : : MLX5_ASO_QUEUE_LOG_DESC))
1143 : 0 : goto error;
1144 : 0 : mlx5_aso_ct_init_sq(&ct_mng->aso_sqs[i]);
1145 : : }
1146 : 0 : ct_mng->nb_sq = nb_queues;
1147 : 0 : return 0;
1148 : : error:
1149 : : do {
1150 [ # # ]: 0 : if (ct_mng->aso_sqs[i].mr.addr)
1151 : 0 : mlx5_aso_dereg_mr(sh->cdev, &ct_mng->aso_sqs[i].mr);
1152 : 0 : mlx5_aso_destroy_sq(&ct_mng->aso_sqs[i]);
1153 [ # # ]: 0 : } while (i--);
1154 : 0 : ct_mng->nb_sq = 0;
1155 : 0 : return -1;
1156 : : }
1157 : :
1158 : : /*
1159 : : * Post a WQE to the ASO CT SQ to modify the context.
1160 : : *
1161 : : * @param[in] sh
1162 : : * Pointer to shared device context.
1163 : : * @param[in] ct
1164 : : * Pointer to the generic CT structure related to the context.
1165 : : * @param[in] profile
1166 : : * Pointer to configuration profile.
1167 : : *
1168 : : * @return
1169 : : * 1 on success (WQE number), 0 on failure.
1170 : : */
1171 : : static uint16_t
1172 : 0 : mlx5_aso_ct_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh,
1173 : : struct mlx5_aso_sq *sq,
1174 : : struct mlx5_aso_ct_action *ct,
1175 : : const struct rte_flow_action_conntrack *profile,
1176 : : bool need_lock,
1177 : : void *user_data,
1178 : : bool push)
1179 : : {
1180 : : volatile struct mlx5_aso_wqe *wqe = NULL;
1181 : 0 : uint16_t size = 1 << sq->log_desc_n;
1182 : 0 : uint16_t mask = size - 1;
1183 : : uint16_t res;
1184 : : struct mlx5_aso_ct_pool *pool;
1185 : : void *desg;
1186 : : void *orig_dir;
1187 : : void *reply_dir;
1188 : :
1189 [ # # ]: 0 : if (need_lock)
1190 : 0 : rte_spinlock_lock(&sq->sqsl);
1191 : : /* Prevent other threads to update the index. */
1192 : 0 : res = size - (uint16_t)(sq->head - sq->tail);
1193 [ # # ]: 0 : if (unlikely(!res)) {
1194 [ # # ]: 0 : if (need_lock)
1195 : 0 : rte_spinlock_unlock(&sq->sqsl);
1196 : 0 : DRV_LOG(ERR, "Fail: SQ is full and no free WQE to send");
1197 : 0 : return 0;
1198 : : }
1199 : 0 : wqe = &sq->sq_obj.aso_wqes[sq->head & mask];
1200 : 0 : rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]);
1201 : : /* Fill next WQE. */
1202 [ # # ]: 0 : MLX5_ASO_CT_UPDATE_STATE(ct,
1203 : : user_data ? ASO_CONNTRACK_WAIT_ASYNC : ASO_CONNTRACK_WAIT);
1204 [ # # ]: 0 : if (user_data) {
1205 : 0 : sq->elts[sq->head & mask].user_data = user_data;
1206 : : } else {
1207 : 0 : sq->elts[sq->head & mask].ct = ct;
1208 : 0 : sq->elts[sq->head & mask].query_data = NULL;
1209 : : }
1210 : : pool = __mlx5_aso_ct_get_pool(sh, ct);
1211 : :
1212 : : /* Each WQE will have a single CT object. */
1213 [ # # ]: 0 : wqe->general_cseg.misc = rte_cpu_to_be_32(pool->devx_obj->id +
1214 : : ct->offset);
1215 [ # # ]: 0 : wqe->general_cseg.opcode = rte_cpu_to_be_32(MLX5_OPCODE_ACCESS_ASO |
1216 : : (ASO_OPC_MOD_CONNECTION_TRACKING <<
1217 : : WQE_CSEG_OPC_MOD_OFFSET) |
1218 : : sq->pi << WQE_CSEG_WQE_INDEX_OFFSET);
1219 : 0 : wqe->aso_cseg.operand_masks = rte_cpu_to_be_32
1220 : : (0u |
1221 : : (ASO_OPER_LOGICAL_OR << ASO_CSEG_COND_OPER_OFFSET) |
1222 : : (ASO_OP_ALWAYS_TRUE << ASO_CSEG_COND_1_OPER_OFFSET) |
1223 : : (ASO_OP_ALWAYS_TRUE << ASO_CSEG_COND_0_OPER_OFFSET) |
1224 : : (BYTEWISE_64BYTE << ASO_CSEG_DATA_MASK_MODE_OFFSET));
1225 : 0 : wqe->aso_cseg.data_mask = UINT64_MAX;
1226 : : /* To make compiler happy. */
1227 : : desg = (void *)(uintptr_t)wqe->aso_dseg.data;
1228 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, valid, 1);
1229 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, state, profile->state);
1230 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, freeze_track, !profile->enable);
1231 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, connection_assured,
1232 : : profile->live_connection);
1233 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, sack_permitted, profile->selective_ack);
1234 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, challenged_acked,
1235 : : profile->challenge_ack_passed);
1236 : : /* Heartbeat, retransmission_counter, retranmission_limit_exceeded: 0 */
1237 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, heartbeat, 0);
1238 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, max_ack_window,
1239 : : profile->max_ack_window);
1240 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, retransmission_counter, 0);
1241 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, retranmission_limit_exceeded, 0);
1242 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, retranmission_limit,
1243 : : profile->retransmission_limit);
1244 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_scale,
1245 : : profile->reply_dir.scale);
1246 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_close_initiated,
1247 : : profile->reply_dir.close_initiated);
1248 : : /* Both directions will use the same liberal mode. */
1249 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_liberal_enabled,
1250 : : profile->liberal_mode);
1251 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_data_unacked,
1252 : : profile->reply_dir.data_unacked);
1253 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_max_ack,
1254 : : profile->reply_dir.last_ack_seen);
1255 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_scale,
1256 : : profile->original_dir.scale);
1257 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_close_initiated,
1258 : : profile->original_dir.close_initiated);
1259 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_liberal_enabled,
1260 : : profile->liberal_mode);
1261 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_data_unacked,
1262 : : profile->original_dir.data_unacked);
1263 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_max_ack,
1264 : : profile->original_dir.last_ack_seen);
1265 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_win, profile->last_window);
1266 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_dir, profile->last_direction);
1267 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_index, profile->last_index);
1268 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_seq, profile->last_seq);
1269 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_ack, profile->last_ack);
1270 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_end, profile->last_end);
1271 : : orig_dir = MLX5_ADDR_OF(conn_track_aso, desg, original_dir);
1272 [ # # ]: 0 : MLX5_SET(tcp_window_params, orig_dir, sent_end,
1273 : : profile->original_dir.sent_end);
1274 [ # # ]: 0 : MLX5_SET(tcp_window_params, orig_dir, reply_end,
1275 : : profile->original_dir.reply_end);
1276 [ # # ]: 0 : MLX5_SET(tcp_window_params, orig_dir, max_win,
1277 : : profile->original_dir.max_win);
1278 [ # # ]: 0 : MLX5_SET(tcp_window_params, orig_dir, max_ack,
1279 : : profile->original_dir.max_ack);
1280 : : reply_dir = MLX5_ADDR_OF(conn_track_aso, desg, reply_dir);
1281 [ # # ]: 0 : MLX5_SET(tcp_window_params, reply_dir, sent_end,
1282 : : profile->reply_dir.sent_end);
1283 [ # # ]: 0 : MLX5_SET(tcp_window_params, reply_dir, reply_end,
1284 : : profile->reply_dir.reply_end);
1285 [ # # ]: 0 : MLX5_SET(tcp_window_params, reply_dir, max_win,
1286 : : profile->reply_dir.max_win);
1287 [ # # ]: 0 : MLX5_SET(tcp_window_params, reply_dir, max_ack,
1288 : : profile->reply_dir.max_ack);
1289 : 0 : sq->head++;
1290 : 0 : sq->pi += 2; /* Each WQE contains 2 WQEBB's. */
1291 [ # # ]: 0 : if (push) {
1292 : 0 : mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe,
1293 : 0 : sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR],
1294 : 0 : !sh->tx_uar.dbnc);
1295 : 0 : sq->db_pi = sq->pi;
1296 : : }
1297 : 0 : sq->db = wqe;
1298 [ # # ]: 0 : if (need_lock)
1299 : 0 : rte_spinlock_unlock(&sq->sqsl);
1300 : : return 1;
1301 : : }
1302 : :
1303 : : /*
1304 : : * Update the status field of CTs to indicate ready to be used by flows.
1305 : : * A continuous number of CTs since last update.
1306 : : *
1307 : : * @param[in] sq
1308 : : * Pointer to ASO CT SQ.
1309 : : * @param[in] num
1310 : : * Number of CT structures to be updated.
1311 : : *
1312 : : * @return
1313 : : * 0 on success, a negative value.
1314 : : */
1315 : : static void
1316 : 0 : mlx5_aso_ct_status_update(struct mlx5_aso_sq *sq, uint16_t num)
1317 : : {
1318 : 0 : uint16_t size = 1 << sq->log_desc_n;
1319 : 0 : uint16_t mask = size - 1;
1320 : : uint16_t i;
1321 : : struct mlx5_aso_ct_action *ct = NULL;
1322 : : uint16_t idx;
1323 : :
1324 [ # # ]: 0 : for (i = 0; i < num; i++) {
1325 : 0 : idx = (uint16_t)((sq->tail + i) & mask);
1326 : 0 : ct = sq->elts[idx].ct;
1327 : : MLX5_ASSERT(ct);
1328 : 0 : MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_READY);
1329 [ # # ]: 0 : if (sq->elts[idx].query_data)
1330 : 0 : rte_memcpy(sq->elts[idx].query_data,
1331 [ # # ]: 0 : (char *)((uintptr_t)sq->mr.addr + idx * 64),
1332 : : 64);
1333 : : }
1334 : 0 : }
1335 : :
1336 : : /*
1337 : : * Post a WQE to the ASO CT SQ to query the current context.
1338 : : *
1339 : : * @param[in] sh
1340 : : * Pointer to shared device context.
1341 : : * @param[in] ct
1342 : : * Pointer to the generic CT structure related to the context.
1343 : : * @param[in] data
1344 : : * Pointer to data area to be filled.
1345 : : *
1346 : : * @return
1347 : : * 1 on success (WQE number), 0 on failure.
1348 : : */
1349 : : static int
1350 : 0 : mlx5_aso_ct_sq_query_single(struct mlx5_dev_ctx_shared *sh,
1351 : : struct mlx5_aso_sq *sq,
1352 : : struct mlx5_aso_ct_action *ct, char *data,
1353 : : bool need_lock,
1354 : : void *user_data,
1355 : : bool push)
1356 : : {
1357 : : volatile struct mlx5_aso_wqe *wqe = NULL;
1358 : 0 : uint16_t size = 1 << sq->log_desc_n;
1359 : 0 : uint16_t mask = size - 1;
1360 : : uint16_t res;
1361 : : uint16_t wqe_idx;
1362 : : struct mlx5_aso_ct_pool *pool;
1363 : : enum mlx5_aso_ct_state state =
1364 : 0 : __atomic_load_n(&ct->state, __ATOMIC_RELAXED);
1365 : :
1366 [ # # ]: 0 : if (state == ASO_CONNTRACK_FREE) {
1367 : 0 : DRV_LOG(ERR, "Fail: No context to query");
1368 : 0 : return -1;
1369 [ # # ]: 0 : } else if (state == ASO_CONNTRACK_WAIT) {
1370 : : return 0;
1371 : : }
1372 [ # # ]: 0 : if (need_lock)
1373 : 0 : rte_spinlock_lock(&sq->sqsl);
1374 : 0 : res = size - (uint16_t)(sq->head - sq->tail);
1375 [ # # ]: 0 : if (unlikely(!res)) {
1376 [ # # ]: 0 : if (need_lock)
1377 : 0 : rte_spinlock_unlock(&sq->sqsl);
1378 : 0 : DRV_LOG(ERR, "Fail: SQ is full and no free WQE to send");
1379 : 0 : return 0;
1380 : : }
1381 [ # # ]: 0 : MLX5_ASO_CT_UPDATE_STATE(ct,
1382 : : user_data ? ASO_CONNTRACK_WAIT_ASYNC : ASO_CONNTRACK_QUERY);
1383 : 0 : wqe = &sq->sq_obj.aso_wqes[sq->head & mask];
1384 : : /* Confirm the location and address of the prefetch instruction. */
1385 : 0 : rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]);
1386 : : /* Fill next WQE. */
1387 : 0 : wqe_idx = sq->head & mask;
1388 : : /* Check if this is async mode. */
1389 [ # # ]: 0 : if (user_data) {
1390 : : struct mlx5_hw_q_job *job = (struct mlx5_hw_q_job *)user_data;
1391 : :
1392 : 0 : sq->elts[wqe_idx].ct = user_data;
1393 : 0 : job->query.hw = (char *)((uintptr_t)sq->mr.addr + wqe_idx * 64);
1394 : : } else {
1395 : 0 : sq->elts[wqe_idx].query_data = data;
1396 : 0 : sq->elts[wqe_idx].ct = ct;
1397 : : }
1398 : : pool = __mlx5_aso_ct_get_pool(sh, ct);
1399 : : /* Each WQE will have a single CT object. */
1400 [ # # ]: 0 : wqe->general_cseg.misc = rte_cpu_to_be_32(pool->devx_obj->id +
1401 : : ct->offset);
1402 [ # # ]: 0 : wqe->general_cseg.opcode = rte_cpu_to_be_32(MLX5_OPCODE_ACCESS_ASO |
1403 : : (ASO_OPC_MOD_CONNECTION_TRACKING <<
1404 : : WQE_CSEG_OPC_MOD_OFFSET) |
1405 : : sq->pi << WQE_CSEG_WQE_INDEX_OFFSET);
1406 : : /*
1407 : : * There is no write request is required.
1408 : : * ASO_OPER_LOGICAL_AND and ASO_OP_ALWAYS_FALSE are both 0.
1409 : : * "BYTEWISE_64BYTE" is needed for a whole context.
1410 : : * Set to 0 directly to reduce an endian swap. (Modify should rewrite.)
1411 : : * "data_mask" is ignored.
1412 : : * Buffer address was already filled during initialization.
1413 : : */
1414 : 0 : wqe->aso_cseg.operand_masks = rte_cpu_to_be_32(BYTEWISE_64BYTE <<
1415 : : ASO_CSEG_DATA_MASK_MODE_OFFSET);
1416 : 0 : wqe->aso_cseg.data_mask = 0;
1417 : 0 : sq->head++;
1418 : : /*
1419 : : * Each WQE contains 2 WQEBB's, even though
1420 : : * data segment is not used in this case.
1421 : : */
1422 : 0 : sq->pi += 2;
1423 [ # # ]: 0 : if (push) {
1424 : 0 : mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe,
1425 : 0 : sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR],
1426 : 0 : !sh->tx_uar.dbnc);
1427 : 0 : sq->db_pi = sq->pi;
1428 : : }
1429 : 0 : sq->db = wqe;
1430 [ # # ]: 0 : if (need_lock)
1431 : 0 : rte_spinlock_unlock(&sq->sqsl);
1432 : : return 1;
1433 : : }
1434 : :
1435 : : /*
1436 : : * Handle completions from WQEs sent to ASO CT.
1437 : : *
1438 : : * @param[in] mng
1439 : : * Pointer to the CT pools management structure.
1440 : : */
1441 : : static void
1442 : 0 : mlx5_aso_ct_completion_handle(struct mlx5_dev_ctx_shared *sh __rte_unused,
1443 : : struct mlx5_aso_sq *sq,
1444 : : bool need_lock)
1445 : : {
1446 : : struct mlx5_aso_cq *cq = &sq->cq;
1447 : : volatile struct mlx5_cqe *restrict cqe;
1448 : 0 : const uint32_t cq_size = 1 << cq->log_desc_n;
1449 : 0 : const uint32_t mask = cq_size - 1;
1450 : : uint32_t idx;
1451 : : uint32_t next_idx;
1452 : : uint16_t max;
1453 : : uint16_t n = 0;
1454 : : int ret;
1455 : :
1456 [ # # ]: 0 : if (need_lock)
1457 : 0 : rte_spinlock_lock(&sq->sqsl);
1458 : 0 : max = (uint16_t)(sq->head - sq->tail);
1459 [ # # ]: 0 : if (unlikely(!max)) {
1460 [ # # ]: 0 : if (need_lock)
1461 : 0 : rte_spinlock_unlock(&sq->sqsl);
1462 : 0 : return;
1463 : : }
1464 : 0 : next_idx = cq->cq_ci & mask;
1465 : : do {
1466 : 0 : idx = next_idx;
1467 : 0 : next_idx = (cq->cq_ci + 1) & mask;
1468 : : /* Need to confirm the position of the prefetch. */
1469 : 0 : rte_prefetch0(&cq->cq_obj.cqes[next_idx]);
1470 : 0 : cqe = &cq->cq_obj.cqes[idx];
1471 [ # # ]: 0 : ret = check_cqe(cqe, cq_size, cq->cq_ci);
1472 : : /*
1473 : : * Be sure owner read is done before any other cookie field or
1474 : : * opaque field.
1475 : : */
1476 : 0 : rte_io_rmb();
1477 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
1478 [ # # ]: 0 : if (likely(ret == MLX5_CQE_STATUS_HW_OWN))
1479 : : break;
1480 : 0 : mlx5_aso_cqe_err_handle(sq);
1481 : : } else {
1482 : 0 : n++;
1483 : : }
1484 : 0 : cq->cq_ci++;
1485 : : } while (1);
1486 [ # # ]: 0 : if (likely(n)) {
1487 : 0 : mlx5_aso_ct_status_update(sq, n);
1488 : 0 : sq->tail += n;
1489 : 0 : rte_io_wmb();
1490 [ # # ]: 0 : cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
1491 : : }
1492 [ # # ]: 0 : if (need_lock)
1493 : 0 : rte_spinlock_unlock(&sq->sqsl);
1494 : : }
1495 : :
1496 : : /*
1497 : : * Update connection tracking ASO context by sending WQE.
1498 : : *
1499 : : * @param[in] sh
1500 : : * Pointer to mlx5_dev_ctx_shared object.
1501 : : * @param[in] queue
1502 : : * The queue index.
1503 : : * @param[in] ct
1504 : : * Pointer to connection tracking offload object.
1505 : : * @param[in] profile
1506 : : * Pointer to connection tracking TCP parameter.
1507 : : *
1508 : : * @return
1509 : : * 0 on success, -1 on failure.
1510 : : */
1511 : : int
1512 [ # # ]: 0 : mlx5_aso_ct_update_by_wqe(struct mlx5_dev_ctx_shared *sh,
1513 : : uint32_t queue,
1514 : : struct mlx5_aso_ct_action *ct,
1515 : : const struct rte_flow_action_conntrack *profile,
1516 : : void *user_data,
1517 : : bool push)
1518 : : {
1519 : : uint32_t poll_wqe_times = MLX5_CT_POLL_WQE_CQE_TIMES;
1520 : : struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct);
1521 : : struct mlx5_aso_sq *sq;
1522 : 0 : bool need_lock = !!(queue == MLX5_HW_INV_QUEUE);
1523 : : int ret;
1524 : :
1525 [ # # ]: 0 : if (sh->config.dv_flow_en == 2)
1526 : : sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool);
1527 : : else
1528 : : sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct);
1529 [ # # ]: 0 : if (queue != MLX5_HW_INV_QUEUE) {
1530 : 0 : ret = mlx5_aso_ct_sq_enqueue_single(sh, sq, ct, profile,
1531 : : need_lock, user_data, push);
1532 [ # # ]: 0 : return ret > 0 ? 0 : -1;
1533 : : }
1534 : : do {
1535 : 0 : mlx5_aso_ct_completion_handle(sh, sq, need_lock);
1536 [ # # ]: 0 : if (mlx5_aso_ct_sq_enqueue_single(sh, sq, ct, profile,
1537 : : need_lock, NULL, true))
1538 : : return 0;
1539 : : /* Waiting for wqe resource. */
1540 : 0 : rte_delay_us_sleep(10u);
1541 [ # # ]: 0 : } while (--poll_wqe_times);
1542 : 0 : DRV_LOG(ERR, "Fail to send WQE for ASO CT %d in pool %d",
1543 : : ct->offset, pool->index);
1544 : 0 : return -1;
1545 : : }
1546 : :
1547 : : /*
1548 : : * The routine is used to wait for WQE completion to continue with queried data.
1549 : : *
1550 : : * @param[in] sh
1551 : : * Pointer to mlx5_dev_ctx_shared object.
1552 : : * @param[in] queue
1553 : : * The queue which CT works on..
1554 : : * @param[in] ct
1555 : : * Pointer to connection tracking offload object.
1556 : : *
1557 : : * @return
1558 : : * 0 on success, -1 on failure.
1559 : : */
1560 : : int
1561 [ # # ]: 0 : mlx5_aso_ct_wait_ready(struct mlx5_dev_ctx_shared *sh, uint32_t queue,
1562 : : struct mlx5_aso_ct_action *ct)
1563 : : {
1564 : : uint32_t poll_cqe_times = MLX5_CT_POLL_WQE_CQE_TIMES;
1565 : : struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct);
1566 : : struct mlx5_aso_sq *sq;
1567 : 0 : bool need_lock = !!(queue == MLX5_HW_INV_QUEUE);
1568 : :
1569 [ # # ]: 0 : if (sh->config.dv_flow_en == 2)
1570 : : sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool);
1571 : : else
1572 : : sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct);
1573 [ # # ]: 0 : if (__atomic_load_n(&ct->state, __ATOMIC_RELAXED) ==
1574 : : ASO_CONNTRACK_READY)
1575 : : return 0;
1576 : : do {
1577 : 0 : mlx5_aso_ct_completion_handle(sh, sq, need_lock);
1578 [ # # ]: 0 : if (__atomic_load_n(&ct->state, __ATOMIC_RELAXED) ==
1579 : : ASO_CONNTRACK_READY)
1580 : : return 0;
1581 : : /* Waiting for CQE ready, consider should block or sleep. */
1582 : 0 : rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
1583 [ # # ]: 0 : } while (--poll_cqe_times);
1584 : 0 : DRV_LOG(ERR, "Fail to poll CQE for ASO CT %d in pool %d",
1585 : : ct->offset, pool->index);
1586 : 0 : return -1;
1587 : : }
1588 : :
1589 : : /*
1590 : : * Convert the hardware conntrack data format into the profile.
1591 : : *
1592 : : * @param[in] profile
1593 : : * Pointer to conntrack profile to be filled after query.
1594 : : * @param[in] wdata
1595 : : * Pointer to data fetched from hardware.
1596 : : */
1597 : : void
1598 : 0 : mlx5_aso_ct_obj_analyze(struct rte_flow_action_conntrack *profile,
1599 : : char *wdata)
1600 : : {
1601 : : void *o_dir = MLX5_ADDR_OF(conn_track_aso, wdata, original_dir);
1602 : : void *r_dir = MLX5_ADDR_OF(conn_track_aso, wdata, reply_dir);
1603 : :
1604 : : /* MLX5_GET16 should be taken into consideration. */
1605 : 0 : profile->state = (enum rte_flow_conntrack_state)
1606 [ # # ]: 0 : MLX5_GET(conn_track_aso, wdata, state);
1607 [ # # ]: 0 : profile->enable = !MLX5_GET(conn_track_aso, wdata, freeze_track);
1608 [ # # ]: 0 : profile->selective_ack = MLX5_GET(conn_track_aso, wdata,
1609 : : sack_permitted);
1610 [ # # ]: 0 : profile->live_connection = MLX5_GET(conn_track_aso, wdata,
1611 : : connection_assured);
1612 [ # # ]: 0 : profile->challenge_ack_passed = MLX5_GET(conn_track_aso, wdata,
1613 : : challenged_acked);
1614 [ # # ]: 0 : profile->max_ack_window = MLX5_GET(conn_track_aso, wdata,
1615 : : max_ack_window);
1616 [ # # ]: 0 : profile->retransmission_limit = MLX5_GET(conn_track_aso, wdata,
1617 : : retranmission_limit);
1618 [ # # ]: 0 : profile->last_window = MLX5_GET(conn_track_aso, wdata, last_win);
1619 [ # # ]: 0 : profile->last_direction = MLX5_GET(conn_track_aso, wdata, last_dir);
1620 : 0 : profile->last_index = (enum rte_flow_conntrack_tcp_last_index)
1621 [ # # ]: 0 : MLX5_GET(conn_track_aso, wdata, last_index);
1622 [ # # ]: 0 : profile->last_seq = MLX5_GET(conn_track_aso, wdata, last_seq);
1623 [ # # ]: 0 : profile->last_ack = MLX5_GET(conn_track_aso, wdata, last_ack);
1624 [ # # ]: 0 : profile->last_end = MLX5_GET(conn_track_aso, wdata, last_end);
1625 : 0 : profile->liberal_mode = MLX5_GET(conn_track_aso, wdata,
1626 [ # # # # ]: 0 : reply_direction_tcp_liberal_enabled) |
1627 : 0 : MLX5_GET(conn_track_aso, wdata,
1628 : : original_direction_tcp_liberal_enabled);
1629 : : /* No liberal in the RTE structure profile. */
1630 [ # # ]: 0 : profile->reply_dir.scale = MLX5_GET(conn_track_aso, wdata,
1631 : : reply_direction_tcp_scale);
1632 [ # # ]: 0 : profile->reply_dir.close_initiated = MLX5_GET(conn_track_aso, wdata,
1633 : : reply_direction_tcp_close_initiated);
1634 [ # # ]: 0 : profile->reply_dir.data_unacked = MLX5_GET(conn_track_aso, wdata,
1635 : : reply_direction_tcp_data_unacked);
1636 [ # # ]: 0 : profile->reply_dir.last_ack_seen = MLX5_GET(conn_track_aso, wdata,
1637 : : reply_direction_tcp_max_ack);
1638 [ # # ]: 0 : profile->reply_dir.sent_end = MLX5_GET(tcp_window_params,
1639 : : r_dir, sent_end);
1640 [ # # ]: 0 : profile->reply_dir.reply_end = MLX5_GET(tcp_window_params,
1641 : : r_dir, reply_end);
1642 [ # # ]: 0 : profile->reply_dir.max_win = MLX5_GET(tcp_window_params,
1643 : : r_dir, max_win);
1644 [ # # ]: 0 : profile->reply_dir.max_ack = MLX5_GET(tcp_window_params,
1645 : : r_dir, max_ack);
1646 [ # # ]: 0 : profile->original_dir.scale = MLX5_GET(conn_track_aso, wdata,
1647 : : original_direction_tcp_scale);
1648 [ # # ]: 0 : profile->original_dir.close_initiated = MLX5_GET(conn_track_aso, wdata,
1649 : : original_direction_tcp_close_initiated);
1650 [ # # ]: 0 : profile->original_dir.data_unacked = MLX5_GET(conn_track_aso, wdata,
1651 : : original_direction_tcp_data_unacked);
1652 [ # # ]: 0 : profile->original_dir.last_ack_seen = MLX5_GET(conn_track_aso, wdata,
1653 : : original_direction_tcp_max_ack);
1654 [ # # ]: 0 : profile->original_dir.sent_end = MLX5_GET(tcp_window_params,
1655 : : o_dir, sent_end);
1656 [ # # ]: 0 : profile->original_dir.reply_end = MLX5_GET(tcp_window_params,
1657 : : o_dir, reply_end);
1658 [ # # ]: 0 : profile->original_dir.max_win = MLX5_GET(tcp_window_params,
1659 : : o_dir, max_win);
1660 [ # # ]: 0 : profile->original_dir.max_ack = MLX5_GET(tcp_window_params,
1661 : : o_dir, max_ack);
1662 : 0 : }
1663 : :
1664 : : /*
1665 : : * Query connection tracking information parameter by send WQE.
1666 : : *
1667 : : * @param[in] dev
1668 : : * Pointer to Ethernet device.
1669 : : * @param[in] ct
1670 : : * Pointer to connection tracking offload object.
1671 : : * @param[out] profile
1672 : : * Pointer to connection tracking TCP information.
1673 : : *
1674 : : * @return
1675 : : * 0 on success, -1 on failure.
1676 : : */
1677 : : int
1678 [ # # ]: 0 : mlx5_aso_ct_query_by_wqe(struct mlx5_dev_ctx_shared *sh,
1679 : : uint32_t queue,
1680 : : struct mlx5_aso_ct_action *ct,
1681 : : struct rte_flow_action_conntrack *profile,
1682 : : void *user_data, bool push)
1683 : : {
1684 : : uint32_t poll_wqe_times = MLX5_CT_POLL_WQE_CQE_TIMES;
1685 : : struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct);
1686 : : struct mlx5_aso_sq *sq;
1687 : 0 : bool need_lock = !!(queue == MLX5_HW_INV_QUEUE);
1688 : : char out_data[64 * 2];
1689 : : int ret;
1690 : :
1691 [ # # ]: 0 : if (sh->config.dv_flow_en == 2)
1692 : : sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool);
1693 : : else
1694 : : sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct);
1695 [ # # ]: 0 : if (queue != MLX5_HW_INV_QUEUE) {
1696 : 0 : ret = mlx5_aso_ct_sq_query_single(sh, sq, ct, out_data,
1697 : : need_lock, user_data, push);
1698 [ # # ]: 0 : return ret > 0 ? 0 : -1;
1699 : : }
1700 : : do {
1701 : 0 : mlx5_aso_ct_completion_handle(sh, sq, need_lock);
1702 : 0 : ret = mlx5_aso_ct_sq_query_single(sh, sq, ct, out_data,
1703 : : need_lock, NULL, true);
1704 [ # # ]: 0 : if (ret < 0)
1705 : 0 : return ret;
1706 [ # # ]: 0 : else if (ret > 0)
1707 : 0 : goto data_handle;
1708 : : /* Waiting for wqe resource or state. */
1709 : : else
1710 : 0 : rte_delay_us_sleep(10u);
1711 [ # # ]: 0 : } while (--poll_wqe_times);
1712 : 0 : DRV_LOG(ERR, "Fail to send WQE for ASO CT %d in pool %d",
1713 : : ct->offset, pool->index);
1714 : 0 : return -1;
1715 : : data_handle:
1716 : 0 : ret = mlx5_aso_ct_wait_ready(sh, queue, ct);
1717 [ # # ]: 0 : if (!ret)
1718 : 0 : mlx5_aso_ct_obj_analyze(profile, out_data);
1719 : : return ret;
1720 : : }
1721 : :
1722 : : /*
1723 : : * Make sure the conntrack context is synchronized with hardware before
1724 : : * creating a flow rule that uses it.
1725 : : *
1726 : : * @param[in] sh
1727 : : * Pointer to shared device context.
1728 : : * @param[in] ct
1729 : : * Pointer to connection tracking offload object.
1730 : : *
1731 : : * @return
1732 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1733 : : */
1734 : : int
1735 [ # # ]: 0 : mlx5_aso_ct_available(struct mlx5_dev_ctx_shared *sh,
1736 : : uint32_t queue,
1737 : : struct mlx5_aso_ct_action *ct)
1738 : : {
1739 : : struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct);
1740 : : struct mlx5_aso_sq *sq;
1741 : 0 : bool need_lock = !!(queue == MLX5_HW_INV_QUEUE);
1742 : : uint32_t poll_cqe_times = MLX5_CT_POLL_WQE_CQE_TIMES;
1743 : : enum mlx5_aso_ct_state state =
1744 : 0 : __atomic_load_n(&ct->state, __ATOMIC_RELAXED);
1745 : :
1746 [ # # ]: 0 : if (sh->config.dv_flow_en == 2)
1747 : : sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool);
1748 : : else
1749 : : sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct);
1750 [ # # ]: 0 : if (state == ASO_CONNTRACK_FREE) {
1751 : 0 : rte_errno = ENXIO;
1752 : 0 : return -rte_errno;
1753 : 0 : } else if (state == ASO_CONNTRACK_READY ||
1754 [ # # ]: 0 : state == ASO_CONNTRACK_QUERY ||
1755 : : state == ASO_CONNTRACK_WAIT_ASYNC) {
1756 : : return 0;
1757 : : }
1758 : : do {
1759 : 0 : mlx5_aso_ct_completion_handle(sh, sq, need_lock);
1760 : 0 : state = __atomic_load_n(&ct->state, __ATOMIC_RELAXED);
1761 [ # # ]: 0 : if (state == ASO_CONNTRACK_READY ||
1762 : : state == ASO_CONNTRACK_QUERY)
1763 : : return 0;
1764 : : /* Waiting for CQE ready, consider should block or sleep. */
1765 : 0 : rte_delay_us_block(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
1766 [ # # ]: 0 : } while (--poll_cqe_times);
1767 : 0 : rte_errno = EBUSY;
1768 : 0 : return -rte_errno;
1769 : : }
1770 : :
1771 : : int
1772 : 0 : mlx5_aso_cnt_queue_init(struct mlx5_dev_ctx_shared *sh)
1773 : : {
1774 : : struct mlx5_hws_aso_mng *aso_mng = NULL;
1775 : : uint8_t idx;
1776 : : struct mlx5_aso_sq *sq;
1777 : :
1778 : : MLX5_ASSERT(sh);
1779 : : MLX5_ASSERT(sh->cnt_svc);
1780 : 0 : aso_mng = &sh->cnt_svc->aso_mng;
1781 : 0 : aso_mng->sq_num = HWS_CNT_ASO_SQ_NUM;
1782 [ # # ]: 0 : for (idx = 0; idx < HWS_CNT_ASO_SQ_NUM; idx++) {
1783 : 0 : sq = &aso_mng->sqs[idx];
1784 [ # # ]: 0 : if (mlx5_aso_sq_create(sh->cdev, sq, sh->tx_uar.obj,
1785 : : MLX5_ASO_CNT_QUEUE_LOG_DESC))
1786 : 0 : goto error;
1787 : 0 : mlx5_aso_cnt_init_sq(sq);
1788 : : }
1789 : : return 0;
1790 : : error:
1791 : 0 : mlx5_aso_cnt_queue_uninit(sh);
1792 : 0 : return -1;
1793 : : }
1794 : :
1795 : : void
1796 : 0 : mlx5_aso_cnt_queue_uninit(struct mlx5_dev_ctx_shared *sh)
1797 : : {
1798 : : uint16_t idx;
1799 : :
1800 [ # # ]: 0 : for (idx = 0; idx < sh->cnt_svc->aso_mng.sq_num; idx++)
1801 : 0 : mlx5_aso_destroy_sq(&sh->cnt_svc->aso_mng.sqs[idx]);
1802 : 0 : sh->cnt_svc->aso_mng.sq_num = 0;
1803 : 0 : }
1804 : :
1805 : : static uint16_t
1806 : 0 : mlx5_aso_cnt_sq_enqueue_burst(struct mlx5_hws_cnt_pool *cpool,
1807 : : struct mlx5_dev_ctx_shared *sh,
1808 : : struct mlx5_aso_sq *sq, uint32_t n,
1809 : : uint32_t offset, uint32_t dcs_id_base)
1810 : : {
1811 : : volatile struct mlx5_aso_wqe *wqe;
1812 : 0 : uint16_t size = 1 << sq->log_desc_n;
1813 : 0 : uint16_t mask = size - 1;
1814 : : uint16_t max;
1815 : : uint32_t upper_offset = offset;
1816 : : uint64_t addr;
1817 : : uint32_t ctrl_gen_id = 0;
1818 : 0 : uint8_t opcmod = sh->cdev->config.hca_attr.flow_access_aso_opc_mod;
1819 [ # # ]: 0 : rte_be32_t lkey = rte_cpu_to_be_32(cpool->raw_mng->mr.lkey);
1820 : 0 : uint16_t aso_n = (uint16_t)(RTE_ALIGN_CEIL(n, 4) / 4);
1821 : : uint32_t ccntid;
1822 : :
1823 : 0 : max = RTE_MIN(size - (uint16_t)(sq->head - sq->tail), aso_n);
1824 [ # # ]: 0 : if (unlikely(!max))
1825 : : return 0;
1826 : 0 : upper_offset += (max * 4);
1827 : : /* Because only one burst at one time, we can use the same elt. */
1828 : 0 : sq->elts[0].burst_size = max;
1829 : : ctrl_gen_id = dcs_id_base;
1830 : 0 : ctrl_gen_id /= 4;
1831 : : do {
1832 : 0 : ccntid = upper_offset - max * 4;
1833 : 0 : wqe = &sq->sq_obj.aso_wqes[sq->head & mask];
1834 : 0 : rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]);
1835 [ # # ]: 0 : wqe->general_cseg.misc = rte_cpu_to_be_32(ctrl_gen_id);
1836 : 0 : wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ONLY_FIRST_ERR <<
1837 : : MLX5_COMP_MODE_OFFSET);
1838 [ # # ]: 0 : wqe->general_cseg.opcode = rte_cpu_to_be_32
1839 : : (MLX5_OPCODE_ACCESS_ASO |
1840 : : (opcmod <<
1841 : : WQE_CSEG_OPC_MOD_OFFSET) |
1842 : : (sq->pi <<
1843 : : WQE_CSEG_WQE_INDEX_OFFSET));
1844 : 0 : addr = (uint64_t)RTE_PTR_ADD(cpool->raw_mng->raw,
1845 : : ccntid * sizeof(struct flow_counter_stats));
1846 [ # # ]: 0 : wqe->aso_cseg.va_h = rte_cpu_to_be_32((uint32_t)(addr >> 32));
1847 [ # # ]: 0 : wqe->aso_cseg.va_l_r = rte_cpu_to_be_32((uint32_t)addr | 1u);
1848 : 0 : wqe->aso_cseg.lkey = lkey;
1849 : 0 : sq->pi += 2; /* Each WQE contains 2 WQEBB's. */
1850 : 0 : sq->head++;
1851 : 0 : sq->next++;
1852 : 0 : ctrl_gen_id++;
1853 : 0 : max--;
1854 [ # # ]: 0 : } while (max);
1855 : 0 : wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ALWAYS <<
1856 : : MLX5_COMP_MODE_OFFSET);
1857 : 0 : mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe,
1858 : 0 : sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR],
1859 : 0 : !sh->tx_uar.dbnc);
1860 : 0 : return sq->elts[0].burst_size;
1861 : : }
1862 : :
1863 : : static uint16_t
1864 : 0 : mlx5_aso_cnt_completion_handle(struct mlx5_aso_sq *sq)
1865 : : {
1866 : : struct mlx5_aso_cq *cq = &sq->cq;
1867 : : volatile struct mlx5_cqe *restrict cqe;
1868 : 0 : const unsigned int cq_size = 1 << cq->log_desc_n;
1869 : 0 : const unsigned int mask = cq_size - 1;
1870 : : uint32_t idx;
1871 : 0 : uint32_t next_idx = cq->cq_ci & mask;
1872 : 0 : const uint16_t max = (uint16_t)(sq->head - sq->tail);
1873 : : uint16_t i = 0;
1874 : : int ret;
1875 [ # # ]: 0 : if (unlikely(!max))
1876 : : return 0;
1877 : : idx = next_idx;
1878 : 0 : next_idx = (cq->cq_ci + 1) & mask;
1879 : 0 : rte_prefetch0(&cq->cq_obj.cqes[next_idx]);
1880 : 0 : cqe = &cq->cq_obj.cqes[idx];
1881 [ # # ]: 0 : ret = check_cqe(cqe, cq_size, cq->cq_ci);
1882 : : /*
1883 : : * Be sure owner read is done before any other cookie field or
1884 : : * opaque field.
1885 : : */
1886 : 0 : rte_io_rmb();
1887 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
1888 [ # # ]: 0 : if (likely(ret == MLX5_CQE_STATUS_HW_OWN))
1889 : : return 0; /* return immediately. */
1890 : 0 : mlx5_aso_cqe_err_handle(sq);
1891 : : }
1892 : 0 : i += sq->elts[0].burst_size;
1893 : 0 : sq->elts[0].burst_size = 0;
1894 : 0 : cq->cq_ci++;
1895 [ # # ]: 0 : if (likely(i)) {
1896 : 0 : sq->tail += i;
1897 : 0 : rte_io_wmb();
1898 [ # # ]: 0 : cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
1899 : : }
1900 : : return i;
1901 : : }
1902 : :
1903 : : static uint16_t
1904 : 0 : mlx5_aso_cnt_query_one_dcs(struct mlx5_dev_ctx_shared *sh,
1905 : : struct mlx5_hws_cnt_pool *cpool,
1906 : : uint8_t dcs_idx, uint32_t num)
1907 : : {
1908 : 0 : uint32_t dcs_id = cpool->dcs_mng.dcs[dcs_idx].obj->id;
1909 : 0 : uint64_t cnt_num = cpool->dcs_mng.dcs[dcs_idx].batch_sz;
1910 : : uint64_t left;
1911 : 0 : uint32_t iidx = cpool->dcs_mng.dcs[dcs_idx].iidx;
1912 : : uint32_t offset;
1913 : : uint16_t mask;
1914 : : uint16_t sq_idx;
1915 : : uint64_t burst_sz = (uint64_t)(1 << MLX5_ASO_CNT_QUEUE_LOG_DESC) * 4 *
1916 : : sh->cnt_svc->aso_mng.sq_num;
1917 : : uint64_t qburst_sz = burst_sz / sh->cnt_svc->aso_mng.sq_num;
1918 : : uint64_t n;
1919 : : struct mlx5_aso_sq *sq;
1920 : :
1921 : 0 : cnt_num = RTE_MIN(num, cnt_num);
1922 : : left = cnt_num;
1923 [ # # ]: 0 : while (left) {
1924 : : mask = 0;
1925 [ # # ]: 0 : for (sq_idx = 0; sq_idx < sh->cnt_svc->aso_mng.sq_num;
1926 : 0 : sq_idx++) {
1927 [ # # ]: 0 : if (left == 0) {
1928 : 0 : mask |= (1 << sq_idx);
1929 : 0 : continue;
1930 : : }
1931 : 0 : n = RTE_MIN(left, qburst_sz);
1932 : 0 : offset = cnt_num - left;
1933 : 0 : offset += iidx;
1934 : 0 : mlx5_aso_cnt_sq_enqueue_burst(cpool, sh,
1935 : 0 : &sh->cnt_svc->aso_mng.sqs[sq_idx], n,
1936 : : offset, dcs_id);
1937 : 0 : left -= n;
1938 : : }
1939 : : do {
1940 [ # # ]: 0 : for (sq_idx = 0; sq_idx < sh->cnt_svc->aso_mng.sq_num;
1941 : 0 : sq_idx++) {
1942 : 0 : sq = &sh->cnt_svc->aso_mng.sqs[sq_idx];
1943 [ # # ]: 0 : if (mlx5_aso_cnt_completion_handle(sq))
1944 : 0 : mask |= (1 << sq_idx);
1945 : : }
1946 [ # # ]: 0 : } while (mask < ((1 << sh->cnt_svc->aso_mng.sq_num) - 1));
1947 : : }
1948 : 0 : return cnt_num;
1949 : : }
1950 : :
1951 : : /*
1952 : : * Query FW counter via ASO WQE.
1953 : : *
1954 : : * ASO query counter use _sync_ mode, means:
1955 : : * 1. each SQ issue one burst with several WQEs
1956 : : * 2. ask for CQE at last WQE
1957 : : * 3. busy poll CQ of each SQ's
1958 : : * 4. If all SQ's CQE are received then goto step 1, issue next burst
1959 : : *
1960 : : * @param[in] sh
1961 : : * Pointer to shared device.
1962 : : * @param[in] cpool
1963 : : * Pointer to counter pool.
1964 : : *
1965 : : * @return
1966 : : * 0 on success, -1 on failure.
1967 : : */
1968 : : int
1969 [ # # ]: 0 : mlx5_aso_cnt_query(struct mlx5_dev_ctx_shared *sh,
1970 : : struct mlx5_hws_cnt_pool *cpool)
1971 : : {
1972 : : uint32_t idx;
1973 : : uint32_t num;
1974 : 0 : uint32_t cnt_num = mlx5_hws_cnt_pool_get_size(cpool) -
1975 : 0 : rte_ring_count(cpool->free_list);
1976 : :
1977 [ # # ]: 0 : for (idx = 0; idx < cpool->dcs_mng.batch_total; idx++) {
1978 : 0 : num = RTE_MIN(cnt_num, cpool->dcs_mng.dcs[idx].batch_sz);
1979 : 0 : mlx5_aso_cnt_query_one_dcs(sh, cpool, idx, num);
1980 : 0 : cnt_num -= num;
1981 [ # # ]: 0 : if (cnt_num == 0)
1982 : : break;
1983 : : }
1984 : 0 : return 0;
1985 : : }
|