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 < (int)sizeof(struct mlx5_error_cqe) / 4; 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_error_cqe *cqe =
513 : 0 : (volatile struct mlx5_error_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 (rte_atomic_load_explicit(&ap->state, rte_memory_order_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 : rte_atomic_store_explicit(&ap->sec_since_last_hit, 0,
631 : : rte_memory_order_relaxed);
632 : : } else {
633 : : struct mlx5_priv *priv;
634 : :
635 : 0 : rte_atomic_fetch_add_explicit(&ap->sec_since_last_hit,
636 : : diff, rte_memory_order_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 (rte_atomic_compare_exchange_strong_explicit(&ap->state,
645 : : &expected,
646 : : AGE_TMOUT,
647 : : rte_memory_order_relaxed,
648 : : rte_memory_order_relaxed)) {
649 [ # # ]: 0 : LIST_INSERT_HEAD(&age_info->aged_aso,
650 : : act, next);
651 : 0 : MLX5_AGE_SET(age_info,
652 : : MLX5_AGE_EVENT_NEW);
653 : : }
654 : : rte_spinlock_unlock(&age_info->aged_sl);
655 : : }
656 : : }
657 : : }
658 : 0 : mlx5_age_event_prepare(sh);
659 : 0 : }
660 : :
661 : : /**
662 : : * Handle completions from WQEs sent to ASO SQ.
663 : : *
664 : : * @param[in] sh
665 : : * Shared device context.
666 : : *
667 : : * @return
668 : : * Number of CQEs handled.
669 : : */
670 : : static uint16_t
671 : 0 : mlx5_aso_completion_handle(struct mlx5_dev_ctx_shared *sh)
672 : : {
673 : 0 : struct mlx5_aso_age_mng *mng = sh->aso_age_mng;
674 : 0 : struct mlx5_aso_sq *sq = &mng->aso_sq;
675 : : struct mlx5_aso_cq *cq = &sq->cq;
676 : : volatile struct mlx5_cqe *restrict cqe;
677 : 0 : const unsigned int cq_size = 1 << cq->log_desc_n;
678 : 0 : const unsigned int mask = cq_size - 1;
679 : : uint32_t idx;
680 : 0 : uint32_t next_idx = cq->cq_ci & mask;
681 : 0 : const uint16_t max = (uint16_t)(sq->head - sq->tail);
682 : : uint16_t i = 0;
683 : : int ret;
684 [ # # ]: 0 : if (unlikely(!max))
685 : : return 0;
686 : : do {
687 : 0 : idx = next_idx;
688 : 0 : next_idx = (cq->cq_ci + 1) & mask;
689 : 0 : rte_prefetch0(&cq->cq_obj.cqes[next_idx]);
690 : 0 : cqe = &cq->cq_obj.cqes[idx];
691 [ # # ]: 0 : ret = check_cqe(cqe, cq_size, cq->cq_ci);
692 : : /*
693 : : * Be sure owner read is done before any other cookie field or
694 : : * opaque field.
695 : : */
696 : 0 : rte_io_rmb();
697 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
698 [ # # ]: 0 : if (likely(ret == MLX5_CQE_STATUS_HW_OWN))
699 : : break;
700 : 0 : mlx5_aso_cqe_err_handle(sq);
701 : : } else {
702 : 0 : i += sq->elts[(sq->tail + i) & mask].burst_size;
703 : : }
704 : 0 : cq->cq_ci++;
705 : : } while (1);
706 [ # # ]: 0 : if (likely(i)) {
707 : 0 : mlx5_aso_age_action_update(sh, i);
708 : 0 : sq->tail += i;
709 : 0 : rte_io_wmb();
710 [ # # ]: 0 : cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
711 : : }
712 : : return i;
713 : : }
714 : :
715 : : /**
716 : : * Periodically read CQEs and send WQEs to ASO SQ.
717 : : *
718 : : * @param[in] arg
719 : : * Shared device context containing the ASO SQ.
720 : : */
721 : : static void
722 : 0 : mlx5_flow_aso_alarm(void *arg)
723 : : {
724 : : struct mlx5_dev_ctx_shared *sh = arg;
725 : 0 : struct mlx5_aso_sq *sq = &sh->aso_age_mng->aso_sq;
726 : : uint32_t us = 100u;
727 : : uint16_t n;
728 : :
729 : 0 : rte_rwlock_read_lock(&sh->aso_age_mng->resize_rwl);
730 : 0 : n = sh->aso_age_mng->next;
731 : : rte_rwlock_read_unlock(&sh->aso_age_mng->resize_rwl);
732 : 0 : mlx5_aso_completion_handle(sh);
733 [ # # ]: 0 : if (sq->next == n) {
734 : : /* End of loop: wait 1 second. */
735 : : us = US_PER_S;
736 : 0 : sq->next = 0;
737 : : }
738 : 0 : mlx5_aso_sq_enqueue_burst(sh, n);
739 [ # # ]: 0 : if (rte_eal_alarm_set(us, mlx5_flow_aso_alarm, sh))
740 : 0 : DRV_LOG(ERR, "Cannot reinitialize aso alarm.");
741 : 0 : }
742 : :
743 : : /**
744 : : * API to start ASO access using ASO SQ.
745 : : *
746 : : * @param[in] sh
747 : : * Pointer to shared device context.
748 : : *
749 : : * @return
750 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
751 : : */
752 : : int
753 : 0 : mlx5_aso_flow_hit_queue_poll_start(struct mlx5_dev_ctx_shared *sh)
754 : : {
755 [ # # ]: 0 : if (rte_eal_alarm_set(US_PER_S, mlx5_flow_aso_alarm, sh)) {
756 : 0 : DRV_LOG(ERR, "Cannot reinitialize ASO age alarm.");
757 : 0 : return -rte_errno;
758 : : }
759 : : return 0;
760 : : }
761 : :
762 : : /**
763 : : * API to stop ASO access using ASO SQ.
764 : : *
765 : : * @param[in] sh
766 : : * Pointer to shared device context.
767 : : *
768 : : * @return
769 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
770 : : */
771 : : int
772 : 0 : mlx5_aso_flow_hit_queue_poll_stop(struct mlx5_dev_ctx_shared *sh)
773 : : {
774 : : int retries = 1024;
775 : :
776 [ # # ]: 0 : if (!sh->aso_age_mng->aso_sq.sq_obj.sq)
777 : : return -EINVAL;
778 : 0 : rte_errno = 0;
779 [ # # ]: 0 : while (--retries) {
780 : 0 : rte_eal_alarm_cancel(mlx5_flow_aso_alarm, sh);
781 [ # # ]: 0 : if (rte_errno != EINPROGRESS)
782 : : break;
783 : : rte_pause();
784 : : }
785 : 0 : return -rte_errno;
786 : : }
787 : :
788 : : static uint16_t
789 : 0 : mlx5_aso_mtr_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh,
790 : : struct mlx5_aso_sq *sq,
791 : : struct mlx5_aso_mtr *aso_mtr,
792 : : struct mlx5_mtr_bulk *bulk,
793 : : bool need_lock,
794 : : struct mlx5_hw_q_job *job,
795 : : bool push)
796 : : {
797 : : volatile struct mlx5_aso_wqe *wqe = NULL;
798 : : struct mlx5_flow_meter_info *fm = NULL;
799 : : struct mlx5_flow_meter_profile *fmp;
800 : 0 : uint16_t size = 1 << sq->log_desc_n;
801 : 0 : uint16_t mask = size - 1;
802 : : uint16_t res;
803 : : uint32_t dseg_idx = 0;
804 : : struct mlx5_aso_mtr_pool *pool = NULL;
805 : : uint32_t param_le;
806 : : int id;
807 : :
808 [ # # ]: 0 : if (need_lock)
809 : 0 : rte_spinlock_lock(&sq->sqsl);
810 : 0 : res = size - (uint16_t)(sq->head - sq->tail);
811 [ # # ]: 0 : if (unlikely(!res)) {
812 : 0 : DRV_LOG(ERR, "Fail: SQ is full and no free WQE to send");
813 [ # # ]: 0 : if (need_lock)
814 : 0 : rte_spinlock_unlock(&sq->sqsl);
815 : 0 : return 0;
816 : : }
817 : 0 : wqe = &sq->sq_obj.aso_wqes[sq->head & mask];
818 : 0 : rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]);
819 : : /* Fill next WQE. */
820 : : fm = &aso_mtr->fm;
821 [ # # ]: 0 : sq->elts[sq->head & mask].user_data = job ? job : (void *)aso_mtr;
822 [ # # ]: 0 : if (aso_mtr->type == ASO_METER_INDIRECT) {
823 [ # # ]: 0 : if (likely(sh->config.dv_flow_en == 2))
824 : 0 : pool = aso_mtr->pool;
825 : : else
826 : 0 : pool = container_of(aso_mtr, struct mlx5_aso_mtr_pool,
827 : : mtrs[aso_mtr->offset]);
828 : 0 : id = pool->devx_obj->id;
829 : : } else {
830 : 0 : id = bulk->devx_obj->id;
831 : : }
832 [ # # ]: 0 : wqe->general_cseg.misc = rte_cpu_to_be_32(id +
833 : : (aso_mtr->offset >> 1));
834 : 0 : wqe->general_cseg.opcode =
835 [ # # ]: 0 : rte_cpu_to_be_32(MLX5_OPCODE_ACCESS_ASO |
836 : : (ASO_OPC_MOD_POLICER << WQE_CSEG_OPC_MOD_OFFSET) |
837 : : sq->pi << WQE_CSEG_WQE_INDEX_OFFSET);
838 : : /* There are 2 meters in one ASO cache line. */
839 : 0 : dseg_idx = aso_mtr->offset & 0x1;
840 : 0 : wqe->aso_cseg.data_mask =
841 [ # # # # : 0 : RTE_BE64(MLX5_IFC_FLOW_METER_PARAM_MASK << (32 * !dseg_idx));
# # # # #
# # # # #
# # ]
842 [ # # ]: 0 : if (fm->is_enable) {
843 : 0 : wqe->aso_dseg.mtrs[dseg_idx].cbs_cir =
844 : 0 : fm->profile->srtcm_prm.cbs_cir;
845 : 0 : wqe->aso_dseg.mtrs[dseg_idx].ebs_eir =
846 : 0 : fm->profile->srtcm_prm.ebs_eir;
847 : : } else {
848 : 0 : wqe->aso_dseg.mtrs[dseg_idx].cbs_cir =
849 : : RTE_BE32(MLX5_IFC_FLOW_METER_DISABLE_CBS_CIR_VAL);
850 : 0 : wqe->aso_dseg.mtrs[dseg_idx].ebs_eir = 0;
851 : : }
852 : 0 : fmp = fm->profile;
853 : : param_le = (1 << ASO_DSEG_VALID_OFFSET);
854 [ # # ]: 0 : if (fm->color_aware)
855 : : param_le |= (MLX5_FLOW_COLOR_UNDEFINED << ASO_DSEG_SC_OFFSET);
856 : : else
857 : : param_le |= (MLX5_FLOW_COLOR_GREEN << ASO_DSEG_SC_OFFSET);
858 [ # # ]: 0 : if (fmp->profile.packet_mode)
859 : 0 : param_le |= (MLX5_METER_MODE_PKT << ASO_DSEG_MTR_MODE);
860 : 0 : wqe->aso_dseg.mtrs[dseg_idx].v_bo_sc_bbog_mm = RTE_BE32(param_le);
861 [ # # # # ]: 0 : switch (fmp->profile.alg) {
862 : 0 : case RTE_MTR_SRTCM_RFC2697:
863 : : /* Only needed for RFC2697. */
864 [ # # ]: 0 : if (fm->profile->srtcm_prm.ebs_eir)
865 : 0 : wqe->aso_dseg.mtrs[dseg_idx].v_bo_sc_bbog_mm |=
866 : : RTE_BE32(1 << ASO_DSEG_BO_OFFSET);
867 : : break;
868 : 0 : case RTE_MTR_TRTCM_RFC2698:
869 : 0 : wqe->aso_dseg.mtrs[dseg_idx].v_bo_sc_bbog_mm |=
870 : : RTE_BE32(1 << ASO_DSEG_BBOG_OFFSET);
871 : 0 : break;
872 : 0 : case RTE_MTR_TRTCM_RFC4115:
873 : 0 : wqe->aso_dseg.mtrs[dseg_idx].v_bo_sc_bbog_mm |=
874 : : RTE_BE32(1 << ASO_DSEG_BO_OFFSET);
875 : 0 : break;
876 : : default:
877 : : break;
878 : : }
879 : : /*
880 : : * Note:
881 : : * Due to software performance reason, the token fields will not be
882 : : * set when posting the WQE to ASO SQ. It will be filled by the HW
883 : : * automatically.
884 : : */
885 : 0 : sq->head++;
886 : 0 : sq->pi += 2;/* Each WQE contains 2 WQEBB's. */
887 [ # # ]: 0 : if (push) {
888 : 0 : mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe,
889 : 0 : sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR],
890 : 0 : !sh->tx_uar.dbnc);
891 : 0 : sq->db_pi = sq->pi;
892 : : }
893 : 0 : sq->db = wqe;
894 [ # # ]: 0 : if (need_lock)
895 : 0 : rte_spinlock_unlock(&sq->sqsl);
896 : : return 1;
897 : : }
898 : :
899 : : static void
900 : 0 : mlx5_aso_mtr_completion_handle(struct mlx5_aso_sq *sq, bool need_lock)
901 : : {
902 : : struct mlx5_aso_cq *cq = &sq->cq;
903 : : volatile struct mlx5_cqe *restrict cqe;
904 : 0 : const unsigned int cq_size = 1 << cq->log_desc_n;
905 : 0 : const unsigned int mask = cq_size - 1;
906 : : uint32_t idx;
907 : 0 : uint32_t next_idx = cq->cq_ci & mask;
908 : : uint16_t max;
909 : : uint16_t i, n = 0;
910 : : int ret;
911 : :
912 [ # # ]: 0 : if (need_lock)
913 : 0 : rte_spinlock_lock(&sq->sqsl);
914 : 0 : max = (uint16_t)(sq->head - sq->tail);
915 [ # # ]: 0 : if (unlikely(!max)) {
916 [ # # ]: 0 : if (need_lock)
917 : 0 : rte_spinlock_unlock(&sq->sqsl);
918 : 0 : return;
919 : : }
920 : : do {
921 : 0 : idx = next_idx;
922 : 0 : next_idx = (cq->cq_ci + 1) & mask;
923 : 0 : rte_prefetch0(&cq->cq_obj.cqes[next_idx]);
924 : 0 : cqe = &cq->cq_obj.cqes[idx];
925 [ # # ]: 0 : ret = check_cqe(cqe, cq_size, cq->cq_ci);
926 : : /*
927 : : * Be sure owner read is done before any other cookie field or
928 : : * opaque field.
929 : : */
930 : 0 : rte_io_rmb();
931 : : if (ret != MLX5_CQE_STATUS_SW_OWN) {
932 [ # # ]: 0 : if (likely(ret == MLX5_CQE_STATUS_HW_OWN))
933 : : break;
934 : 0 : mlx5_aso_cqe_err_handle(sq);
935 : : } else {
936 : 0 : n++;
937 : : }
938 : 0 : cq->cq_ci++;
939 : : } while (1);
940 [ # # ]: 0 : if (likely(n)) {
941 : : uint8_t exp_state = ASO_METER_WAIT;
942 : : struct mlx5_aso_mtr *aso_mtr;
943 : : __rte_unused bool verdict;
944 : :
945 [ # # ]: 0 : for (i = 0; i < n; ++i) {
946 : 0 : aso_mtr = sq->elts[(sq->tail + i) & mask].mtr;
947 : : MLX5_ASSERT(aso_mtr);
948 : 0 : verdict = rte_atomic_compare_exchange_strong_explicit(&aso_mtr->state,
949 : : &exp_state, ASO_METER_READY,
950 : : rte_memory_order_relaxed,
951 : : rte_memory_order_relaxed);
952 : : MLX5_ASSERT(verdict);
953 : : }
954 : 0 : sq->tail += n;
955 : 0 : rte_io_wmb();
956 [ # # ]: 0 : cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
957 : : }
958 [ # # ]: 0 : if (need_lock)
959 : 0 : rte_spinlock_unlock(&sq->sqsl);
960 : : }
961 : :
962 : : static __rte_always_inline struct mlx5_aso_sq *
963 : : mlx5_aso_mtr_select_sq(struct mlx5_dev_ctx_shared *sh, uint32_t queue,
964 : : struct mlx5_aso_mtr *mtr, bool *need_lock)
965 : : {
966 : : struct mlx5_aso_sq *sq;
967 : :
968 [ # # ]: 0 : if (likely(sh->config.dv_flow_en == 2) &&
969 [ # # # # ]: 0 : mtr->type == ASO_METER_INDIRECT) {
970 [ # # ]: 0 : if (queue == MLX5_HW_INV_QUEUE) {
971 : 0 : sq = &mtr->pool->sq[mtr->pool->nb_sq - 1];
972 : : *need_lock = true;
973 : : } else {
974 : 0 : sq = &mtr->pool->sq[queue];
975 : : *need_lock = false;
976 : : }
977 : : } else {
978 : 0 : sq = &sh->mtrmng->pools_mng.sq;
979 : : *need_lock = true;
980 : : }
981 : : return sq;
982 : : }
983 : :
984 : : #if defined(HAVE_MLX5_HWS_SUPPORT)
985 : : static void
986 : 0 : mlx5_aso_poll_cq_mtr_hws(struct mlx5_priv *priv, struct mlx5_aso_sq *sq)
987 : : {
988 : : #define MLX5_HWS_MTR_CMPL_NUM 4
989 : :
990 : : int i, ret;
991 : : struct mlx5_aso_mtr *mtr;
992 : : uint8_t exp_state = ASO_METER_WAIT;
993 : : struct rte_flow_op_result res[MLX5_HWS_MTR_CMPL_NUM];
994 : : __rte_unused bool verdict;
995 : :
996 : 0 : rte_spinlock_lock(&sq->sqsl);
997 : 0 : repeat:
998 : 0 : ret = mlx5_aso_pull_completion(sq, res, MLX5_HWS_MTR_CMPL_NUM);
999 [ # # ]: 0 : if (ret) {
1000 [ # # ]: 0 : for (i = 0; i < ret; i++) {
1001 : 0 : struct mlx5_hw_q_job *job = res[i].user_data;
1002 : :
1003 : : MLX5_ASSERT(job);
1004 : 0 : mtr = mlx5_ipool_get(priv->hws_mpool->idx_pool,
1005 : 0 : MLX5_INDIRECT_ACTION_IDX_GET(job->action));
1006 : : MLX5_ASSERT(mtr);
1007 : 0 : verdict = rte_atomic_compare_exchange_strong_explicit(&mtr->state,
1008 : : &exp_state, ASO_METER_READY,
1009 : : rte_memory_order_relaxed,
1010 : : rte_memory_order_relaxed);
1011 : : MLX5_ASSERT(verdict);
1012 : 0 : flow_hw_job_put(priv, job, CTRL_QUEUE_ID(priv));
1013 : : }
1014 [ # # ]: 0 : if (ret == MLX5_HWS_MTR_CMPL_NUM)
1015 : 0 : goto repeat;
1016 : : }
1017 : : rte_spinlock_unlock(&sq->sqsl);
1018 : :
1019 : : #undef MLX5_HWS_MTR_CMPL_NUM
1020 : 0 : }
1021 : : #else
1022 : : static void
1023 : : mlx5_aso_poll_cq_mtr_hws(__rte_unused struct mlx5_priv *priv, __rte_unused struct mlx5_aso_sq *sq)
1024 : : {
1025 : : MLX5_ASSERT(false);
1026 : : }
1027 : : #endif
1028 : :
1029 : : static void
1030 : 0 : mlx5_aso_poll_cq_mtr_sws(__rte_unused struct mlx5_priv *priv,
1031 : : struct mlx5_aso_sq *sq)
1032 : : {
1033 : 0 : mlx5_aso_mtr_completion_handle(sq, true);
1034 : 0 : }
1035 : :
1036 : : typedef void (*poll_cq_t)(struct mlx5_priv *, struct mlx5_aso_sq *);
1037 : :
1038 : : /**
1039 : : * Update meter parameter by send WQE.
1040 : : *
1041 : : * @param[in] dev
1042 : : * Pointer to Ethernet device.
1043 : : * @param[in] priv
1044 : : * Pointer to mlx5 private data structure.
1045 : : * @param[in] fm
1046 : : * Pointer to flow meter to be modified.
1047 : : *
1048 : : * @return
1049 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1050 : : */
1051 : : int
1052 : 0 : mlx5_aso_meter_update_by_wqe(struct mlx5_priv *priv, uint32_t queue,
1053 : : struct mlx5_aso_mtr *mtr,
1054 : : struct mlx5_mtr_bulk *bulk,
1055 : : struct mlx5_hw_q_job *job, bool push)
1056 : : {
1057 : : bool need_lock;
1058 [ # # ]: 0 : struct mlx5_dev_ctx_shared *sh = priv->sh;
1059 : : struct mlx5_aso_sq *sq =
1060 : : mlx5_aso_mtr_select_sq(sh, queue, mtr, &need_lock);
1061 : : uint32_t poll_wqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
1062 : : poll_cq_t poll_mtr_cq =
1063 [ # # ]: 0 : job ? mlx5_aso_poll_cq_mtr_hws : mlx5_aso_poll_cq_mtr_sws;
1064 : : int ret;
1065 : :
1066 [ # # ]: 0 : if (queue != MLX5_HW_INV_QUEUE) {
1067 : 0 : ret = mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr, bulk,
1068 : : need_lock, job, push);
1069 [ # # ]: 0 : return ret > 0 ? 0 : -1;
1070 : : }
1071 : : do {
1072 : 0 : poll_mtr_cq(priv, sq);
1073 [ # # ]: 0 : if (mlx5_aso_mtr_sq_enqueue_single(sh, sq, mtr, bulk,
1074 : : need_lock, job, true))
1075 : : return 0;
1076 : : /* Waiting for wqe resource. */
1077 : 0 : rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
1078 [ # # ]: 0 : } while (--poll_wqe_times);
1079 : 0 : DRV_LOG(ERR, "Fail to send WQE for ASO meter offset %d",
1080 : : mtr->offset);
1081 : 0 : return -1;
1082 : : }
1083 : :
1084 : : /**
1085 : : * Wait for meter to be ready.
1086 : : *
1087 : : * @param[in] dev
1088 : : * Pointer to Ethernet device.
1089 : : * @param[in] priv
1090 : : * Pointer to mlx5 private data structure.
1091 : : * @param[in] fm
1092 : : * Pointer to flow meter to be modified.
1093 : : *
1094 : : * @return
1095 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1096 : : */
1097 : : int
1098 : 0 : mlx5_aso_mtr_wait(struct mlx5_priv *priv,
1099 : : struct mlx5_aso_mtr *mtr, bool is_tmpl_api)
1100 : : {
1101 : : bool need_lock;
1102 : : struct mlx5_aso_sq *sq;
1103 : 0 : struct mlx5_dev_ctx_shared *sh = priv->sh;
1104 : : uint32_t poll_cqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
1105 : 0 : uint8_t state = rte_atomic_load_explicit(&mtr->state, rte_memory_order_relaxed);
1106 : : poll_cq_t poll_mtr_cq =
1107 [ # # ]: 0 : is_tmpl_api ? mlx5_aso_poll_cq_mtr_hws : mlx5_aso_poll_cq_mtr_sws;
1108 : :
1109 [ # # ]: 0 : if (state == ASO_METER_READY || state == ASO_METER_WAIT_ASYNC)
1110 : : return 0;
1111 : : sq = mlx5_aso_mtr_select_sq(sh, MLX5_HW_INV_QUEUE, mtr, &need_lock);
1112 : : do {
1113 : 0 : poll_mtr_cq(priv, sq);
1114 [ # # ]: 0 : if (rte_atomic_load_explicit(&mtr->state, rte_memory_order_relaxed) ==
1115 : : ASO_METER_READY)
1116 : : return 0;
1117 : : /* Waiting for CQE ready. */
1118 : 0 : rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
1119 [ # # ]: 0 : } while (--poll_cqe_times);
1120 : 0 : DRV_LOG(ERR, "Fail to poll CQE ready for ASO meter offset %d",
1121 : : mtr->offset);
1122 : 0 : return -1;
1123 : : }
1124 : :
1125 : : static inline struct mlx5_aso_sq*
1126 : : __mlx5_aso_ct_get_sq_in_hws(uint32_t queue,
1127 : : struct mlx5_aso_ct_pool *pool)
1128 : : {
1129 : : return (queue == MLX5_HW_INV_QUEUE) ?
1130 [ # # # # : 0 : pool->shared_sq : &pool->sq[queue];
# # # # ]
1131 : : }
1132 : :
1133 : : static inline struct mlx5_aso_sq*
1134 : : __mlx5_aso_ct_get_sq_in_sws(struct mlx5_dev_ctx_shared *sh,
1135 : : struct mlx5_aso_ct_action *ct)
1136 : : {
1137 : 0 : return &sh->ct_mng->aso_sqs[ct->offset & (MLX5_ASO_CT_SQ_NUM - 1)];
1138 : : }
1139 : :
1140 : : static inline struct mlx5_aso_ct_pool*
1141 : : __mlx5_aso_ct_get_pool(struct mlx5_dev_ctx_shared *sh,
1142 : : struct mlx5_aso_ct_action *ct)
1143 : : {
1144 [ # # # # ]: 0 : if (likely(sh->config.dv_flow_en == 2))
1145 : 0 : return ct->pool;
1146 : 0 : return container_of(ct, struct mlx5_aso_ct_pool, actions[ct->offset]);
1147 : : }
1148 : :
1149 : : int
1150 : 0 : mlx5_aso_ct_queue_uninit(struct mlx5_dev_ctx_shared *sh,
1151 : : struct mlx5_aso_ct_pools_mng *ct_mng)
1152 : : {
1153 : : uint32_t i;
1154 : :
1155 : : /* 64B per object for query. */
1156 [ # # ]: 0 : for (i = 0; i < ct_mng->nb_sq; i++) {
1157 [ # # ]: 0 : if (ct_mng->aso_sqs[i].mr.addr)
1158 : 0 : mlx5_aso_dereg_mr(sh->cdev, &ct_mng->aso_sqs[i].mr);
1159 : 0 : mlx5_aso_destroy_sq(&ct_mng->aso_sqs[i]);
1160 : : }
1161 : 0 : return 0;
1162 : : }
1163 : :
1164 : : /**
1165 : : * API to create and initialize CT Send Queue used for ASO access.
1166 : : *
1167 : : * @param[in] sh
1168 : : * Pointer to shared device context.
1169 : : * @param[in] ct_mng
1170 : : * Pointer to the CT management struct.
1171 : : * *param[in] nb_queues
1172 : : * Number of queues to be allocated.
1173 : : *
1174 : : * @return
1175 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1176 : : */
1177 : : int
1178 : 0 : mlx5_aso_ct_queue_init(struct mlx5_dev_ctx_shared *sh,
1179 : : struct mlx5_aso_ct_pools_mng *ct_mng,
1180 : : uint32_t nb_queues)
1181 : : {
1182 : : uint32_t i;
1183 : :
1184 : : /* 64B per object for query. */
1185 [ # # ]: 0 : for (i = 0; i < nb_queues; i++) {
1186 [ # # ]: 0 : if (mlx5_aso_reg_mr(sh->cdev, 64 * (1 << MLX5_ASO_QUEUE_LOG_DESC),
1187 : : &ct_mng->aso_sqs[i].mr))
1188 : 0 : goto error;
1189 [ # # ]: 0 : if (mlx5_aso_sq_create(sh->cdev, &ct_mng->aso_sqs[i],
1190 : : sh->tx_uar.obj,
1191 : : MLX5_ASO_QUEUE_LOG_DESC))
1192 : 0 : goto error;
1193 : 0 : mlx5_aso_ct_init_sq(&ct_mng->aso_sqs[i]);
1194 : : }
1195 : 0 : ct_mng->nb_sq = nb_queues;
1196 : 0 : return 0;
1197 : : error:
1198 : : do {
1199 [ # # ]: 0 : if (ct_mng->aso_sqs[i].mr.addr)
1200 : 0 : mlx5_aso_dereg_mr(sh->cdev, &ct_mng->aso_sqs[i].mr);
1201 : 0 : mlx5_aso_destroy_sq(&ct_mng->aso_sqs[i]);
1202 [ # # ]: 0 : } while (i--);
1203 : 0 : ct_mng->nb_sq = 0;
1204 : 0 : return -1;
1205 : : }
1206 : :
1207 : : /*
1208 : : * Post a WQE to the ASO CT SQ to modify the context.
1209 : : *
1210 : : * @param[in] sh
1211 : : * Pointer to shared device context.
1212 : : * @param[in] ct
1213 : : * Pointer to the generic CT structure related to the context.
1214 : : * @param[in] profile
1215 : : * Pointer to configuration profile.
1216 : : *
1217 : : * @return
1218 : : * 1 on success (WQE number), 0 on failure.
1219 : : */
1220 : : static uint16_t
1221 : 0 : mlx5_aso_ct_sq_enqueue_single(struct mlx5_dev_ctx_shared *sh,
1222 : : struct mlx5_aso_sq *sq,
1223 : : struct mlx5_aso_ct_action *ct,
1224 : : const struct rte_flow_action_conntrack *profile,
1225 : : bool need_lock,
1226 : : void *user_data,
1227 : : bool push)
1228 : : {
1229 : : volatile struct mlx5_aso_wqe *wqe = NULL;
1230 : 0 : uint16_t size = 1 << sq->log_desc_n;
1231 : 0 : uint16_t mask = size - 1;
1232 : : uint16_t res;
1233 : : struct mlx5_aso_ct_pool *pool;
1234 : : void *desg;
1235 : : void *orig_dir;
1236 : : void *reply_dir;
1237 : :
1238 [ # # ]: 0 : if (need_lock)
1239 : 0 : rte_spinlock_lock(&sq->sqsl);
1240 : : /* Prevent other threads to update the index. */
1241 : 0 : res = size - (uint16_t)(sq->head - sq->tail);
1242 [ # # ]: 0 : if (unlikely(!res)) {
1243 [ # # ]: 0 : if (need_lock)
1244 : 0 : rte_spinlock_unlock(&sq->sqsl);
1245 : 0 : DRV_LOG(ERR, "Fail: SQ is full and no free WQE to send");
1246 : 0 : return 0;
1247 : : }
1248 : 0 : wqe = &sq->sq_obj.aso_wqes[sq->head & mask];
1249 : 0 : rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]);
1250 : : /* Fill next WQE. */
1251 [ # # ]: 0 : MLX5_ASO_CT_UPDATE_STATE(ct,
1252 : : user_data ? ASO_CONNTRACK_WAIT_ASYNC : ASO_CONNTRACK_WAIT);
1253 [ # # ]: 0 : if (user_data) {
1254 : 0 : sq->elts[sq->head & mask].user_data = user_data;
1255 : : } else {
1256 : 0 : sq->elts[sq->head & mask].ct = ct;
1257 : 0 : sq->elts[sq->head & mask].query_data = NULL;
1258 : : }
1259 : : pool = __mlx5_aso_ct_get_pool(sh, ct);
1260 : :
1261 : : /* Each WQE will have a single CT object. */
1262 [ # # ]: 0 : wqe->general_cseg.misc = rte_cpu_to_be_32(pool->devx_obj->id +
1263 : : ct->offset);
1264 [ # # ]: 0 : wqe->general_cseg.opcode = rte_cpu_to_be_32(MLX5_OPCODE_ACCESS_ASO |
1265 : : (ASO_OPC_MOD_CONNECTION_TRACKING <<
1266 : : WQE_CSEG_OPC_MOD_OFFSET) |
1267 : : sq->pi << WQE_CSEG_WQE_INDEX_OFFSET);
1268 : 0 : wqe->aso_cseg.operand_masks = rte_cpu_to_be_32
1269 : : (0u |
1270 : : (ASO_OPER_LOGICAL_OR << ASO_CSEG_COND_OPER_OFFSET) |
1271 : : (ASO_OP_ALWAYS_TRUE << ASO_CSEG_COND_1_OPER_OFFSET) |
1272 : : (ASO_OP_ALWAYS_TRUE << ASO_CSEG_COND_0_OPER_OFFSET) |
1273 : : (BYTEWISE_64BYTE << ASO_CSEG_DATA_MASK_MODE_OFFSET));
1274 : 0 : wqe->aso_cseg.data_mask = UINT64_MAX;
1275 : : /* To make compiler happy. */
1276 : : desg = (void *)(uintptr_t)wqe->aso_dseg.data;
1277 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, valid, 1);
1278 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, state, profile->state);
1279 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, freeze_track, !profile->enable);
1280 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, connection_assured,
1281 : : profile->live_connection);
1282 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, sack_permitted, profile->selective_ack);
1283 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, challenged_acked,
1284 : : profile->challenge_ack_passed);
1285 : : /* Heartbeat, retransmission_counter, retranmission_limit_exceeded: 0 */
1286 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, heartbeat, 0);
1287 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, max_ack_window,
1288 : : profile->max_ack_window);
1289 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, retransmission_counter, 0);
1290 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, retranmission_limit_exceeded, 0);
1291 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, retranmission_limit,
1292 : : profile->retransmission_limit);
1293 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_scale,
1294 : : profile->reply_dir.scale);
1295 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_close_initiated,
1296 : : profile->reply_dir.close_initiated);
1297 : : /* Both directions will use the same liberal mode. */
1298 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_liberal_enabled,
1299 : : profile->liberal_mode);
1300 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_data_unacked,
1301 : : profile->reply_dir.data_unacked);
1302 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, reply_direction_tcp_max_ack,
1303 : : profile->reply_dir.last_ack_seen);
1304 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_scale,
1305 : : profile->original_dir.scale);
1306 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_close_initiated,
1307 : : profile->original_dir.close_initiated);
1308 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_liberal_enabled,
1309 : : profile->liberal_mode);
1310 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_data_unacked,
1311 : : profile->original_dir.data_unacked);
1312 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, original_direction_tcp_max_ack,
1313 : : profile->original_dir.last_ack_seen);
1314 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_win, profile->last_window);
1315 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_dir, profile->last_direction);
1316 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_index, profile->last_index);
1317 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_seq, profile->last_seq);
1318 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_ack, profile->last_ack);
1319 [ # # ]: 0 : MLX5_SET(conn_track_aso, desg, last_end, profile->last_end);
1320 : : orig_dir = MLX5_ADDR_OF(conn_track_aso, desg, original_dir);
1321 [ # # ]: 0 : MLX5_SET(tcp_window_params, orig_dir, sent_end,
1322 : : profile->original_dir.sent_end);
1323 [ # # ]: 0 : MLX5_SET(tcp_window_params, orig_dir, reply_end,
1324 : : profile->original_dir.reply_end);
1325 [ # # ]: 0 : MLX5_SET(tcp_window_params, orig_dir, max_win,
1326 : : profile->original_dir.max_win);
1327 [ # # ]: 0 : MLX5_SET(tcp_window_params, orig_dir, max_ack,
1328 : : profile->original_dir.max_ack);
1329 : : reply_dir = MLX5_ADDR_OF(conn_track_aso, desg, reply_dir);
1330 [ # # ]: 0 : MLX5_SET(tcp_window_params, reply_dir, sent_end,
1331 : : profile->reply_dir.sent_end);
1332 [ # # ]: 0 : MLX5_SET(tcp_window_params, reply_dir, reply_end,
1333 : : profile->reply_dir.reply_end);
1334 [ # # ]: 0 : MLX5_SET(tcp_window_params, reply_dir, max_win,
1335 : : profile->reply_dir.max_win);
1336 [ # # ]: 0 : MLX5_SET(tcp_window_params, reply_dir, max_ack,
1337 : : profile->reply_dir.max_ack);
1338 : 0 : sq->head++;
1339 : 0 : sq->pi += 2; /* Each WQE contains 2 WQEBB's. */
1340 [ # # ]: 0 : if (push) {
1341 : 0 : mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe,
1342 : 0 : sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR],
1343 : 0 : !sh->tx_uar.dbnc);
1344 : 0 : sq->db_pi = sq->pi;
1345 : : }
1346 : 0 : sq->db = wqe;
1347 [ # # ]: 0 : if (need_lock)
1348 : 0 : rte_spinlock_unlock(&sq->sqsl);
1349 : : return 1;
1350 : : }
1351 : :
1352 : : /*
1353 : : * Update the status field of CTs to indicate ready to be used by flows.
1354 : : * A continuous number of CTs since last update.
1355 : : *
1356 : : * @param[in] sq
1357 : : * Pointer to ASO CT SQ.
1358 : : * @param[in] num
1359 : : * Number of CT structures to be updated.
1360 : : *
1361 : : * @return
1362 : : * 0 on success, a negative value.
1363 : : */
1364 : : static void
1365 : 0 : mlx5_aso_ct_status_update(struct mlx5_aso_sq *sq, uint16_t num)
1366 : : {
1367 : 0 : uint16_t size = 1 << sq->log_desc_n;
1368 : 0 : uint16_t mask = size - 1;
1369 : : uint16_t i;
1370 : : struct mlx5_aso_ct_action *ct = NULL;
1371 : : uint16_t idx;
1372 : :
1373 [ # # ]: 0 : for (i = 0; i < num; i++) {
1374 : 0 : idx = (uint16_t)((sq->tail + i) & mask);
1375 : 0 : ct = sq->elts[idx].ct;
1376 : : MLX5_ASSERT(ct);
1377 : 0 : MLX5_ASO_CT_UPDATE_STATE(ct, ASO_CONNTRACK_READY);
1378 [ # # ]: 0 : if (sq->elts[idx].query_data)
1379 : 0 : rte_memcpy(sq->elts[idx].query_data,
1380 [ # # ]: 0 : (char *)((uintptr_t)sq->mr.addr + idx * 64),
1381 : : 64);
1382 : : }
1383 : 0 : }
1384 : :
1385 : : /*
1386 : : * Post a WQE to the ASO CT SQ to query the current context.
1387 : : *
1388 : : * @param[in] sh
1389 : : * Pointer to shared device context.
1390 : : * @param[in] ct
1391 : : * Pointer to the generic CT structure related to the context.
1392 : : * @param[in] data
1393 : : * Pointer to data area to be filled.
1394 : : *
1395 : : * @return
1396 : : * 1 on success (WQE number), 0 on failure.
1397 : : */
1398 : : static int
1399 : 0 : mlx5_aso_ct_sq_query_single(struct mlx5_dev_ctx_shared *sh,
1400 : : struct mlx5_aso_sq *sq,
1401 : : struct mlx5_aso_ct_action *ct, char *data,
1402 : : bool need_lock,
1403 : : void *user_data,
1404 : : bool push)
1405 : : {
1406 : : volatile struct mlx5_aso_wqe *wqe = NULL;
1407 : 0 : uint16_t size = 1 << sq->log_desc_n;
1408 : 0 : uint16_t mask = size - 1;
1409 : : uint16_t res;
1410 : : uint16_t wqe_idx;
1411 : : struct mlx5_aso_ct_pool *pool;
1412 : : enum mlx5_aso_ct_state state =
1413 : 0 : rte_atomic_load_explicit(&ct->state, rte_memory_order_relaxed);
1414 : :
1415 [ # # ]: 0 : if (state == ASO_CONNTRACK_FREE) {
1416 : 0 : DRV_LOG(ERR, "Fail: No context to query");
1417 : 0 : return -1;
1418 [ # # ]: 0 : } else if (state == ASO_CONNTRACK_WAIT) {
1419 : : return 0;
1420 : : }
1421 [ # # ]: 0 : if (need_lock)
1422 : 0 : rte_spinlock_lock(&sq->sqsl);
1423 : 0 : res = size - (uint16_t)(sq->head - sq->tail);
1424 [ # # ]: 0 : if (unlikely(!res)) {
1425 [ # # ]: 0 : if (need_lock)
1426 : 0 : rte_spinlock_unlock(&sq->sqsl);
1427 : 0 : DRV_LOG(ERR, "Fail: SQ is full and no free WQE to send");
1428 : 0 : return 0;
1429 : : }
1430 [ # # ]: 0 : MLX5_ASO_CT_UPDATE_STATE(ct,
1431 : : user_data ? ASO_CONNTRACK_WAIT_ASYNC : ASO_CONNTRACK_QUERY);
1432 : 0 : wqe = &sq->sq_obj.aso_wqes[sq->head & mask];
1433 : : /* Confirm the location and address of the prefetch instruction. */
1434 : 0 : rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]);
1435 : : /* Fill next WQE. */
1436 : 0 : wqe_idx = sq->head & mask;
1437 : : /* Check if this is async mode. */
1438 [ # # ]: 0 : if (user_data) {
1439 : : struct mlx5_hw_q_job *job = (struct mlx5_hw_q_job *)user_data;
1440 : :
1441 : 0 : sq->elts[wqe_idx].ct = user_data;
1442 : 0 : job->query.hw = (char *)((uintptr_t)sq->mr.addr + wqe_idx * 64);
1443 : : } else {
1444 : 0 : sq->elts[wqe_idx].query_data = data;
1445 : 0 : sq->elts[wqe_idx].ct = ct;
1446 : : }
1447 : : pool = __mlx5_aso_ct_get_pool(sh, ct);
1448 : : /* Each WQE will have a single CT object. */
1449 [ # # ]: 0 : wqe->general_cseg.misc = rte_cpu_to_be_32(pool->devx_obj->id +
1450 : : ct->offset);
1451 [ # # ]: 0 : wqe->general_cseg.opcode = rte_cpu_to_be_32(MLX5_OPCODE_ACCESS_ASO |
1452 : : (ASO_OPC_MOD_CONNECTION_TRACKING <<
1453 : : WQE_CSEG_OPC_MOD_OFFSET) |
1454 : : sq->pi << WQE_CSEG_WQE_INDEX_OFFSET);
1455 : : /*
1456 : : * There is no write request is required.
1457 : : * ASO_OPER_LOGICAL_AND and ASO_OP_ALWAYS_FALSE are both 0.
1458 : : * "BYTEWISE_64BYTE" is needed for a whole context.
1459 : : * Set to 0 directly to reduce an endian swap. (Modify should rewrite.)
1460 : : * "data_mask" is ignored.
1461 : : * Buffer address was already filled during initialization.
1462 : : */
1463 : 0 : wqe->aso_cseg.operand_masks = rte_cpu_to_be_32(BYTEWISE_64BYTE <<
1464 : : ASO_CSEG_DATA_MASK_MODE_OFFSET);
1465 : 0 : wqe->aso_cseg.data_mask = 0;
1466 : 0 : sq->head++;
1467 : : /*
1468 : : * Each WQE contains 2 WQEBB's, even though
1469 : : * data segment is not used in this case.
1470 : : */
1471 : 0 : sq->pi += 2;
1472 [ # # ]: 0 : if (push) {
1473 : 0 : mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe,
1474 : 0 : sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR],
1475 : 0 : !sh->tx_uar.dbnc);
1476 : 0 : sq->db_pi = sq->pi;
1477 : : }
1478 : 0 : sq->db = wqe;
1479 [ # # ]: 0 : if (need_lock)
1480 : 0 : rte_spinlock_unlock(&sq->sqsl);
1481 : : return 1;
1482 : : }
1483 : :
1484 : : /*
1485 : : * Handle completions from WQEs sent to ASO CT.
1486 : : *
1487 : : * @param[in] mng
1488 : : * Pointer to the CT pools management structure.
1489 : : */
1490 : : static void
1491 : 0 : mlx5_aso_ct_completion_handle(struct mlx5_dev_ctx_shared *sh __rte_unused,
1492 : : struct mlx5_aso_sq *sq,
1493 : : bool need_lock)
1494 : : {
1495 : : struct mlx5_aso_cq *cq = &sq->cq;
1496 : : volatile struct mlx5_cqe *restrict cqe;
1497 : 0 : const uint32_t cq_size = 1 << cq->log_desc_n;
1498 : 0 : const uint32_t mask = cq_size - 1;
1499 : : uint32_t idx;
1500 : : uint32_t next_idx;
1501 : : uint16_t max;
1502 : : uint16_t n = 0;
1503 : : int ret;
1504 : :
1505 [ # # ]: 0 : if (need_lock)
1506 : 0 : rte_spinlock_lock(&sq->sqsl);
1507 : 0 : max = (uint16_t)(sq->head - sq->tail);
1508 [ # # ]: 0 : if (unlikely(!max)) {
1509 [ # # ]: 0 : if (need_lock)
1510 : 0 : rte_spinlock_unlock(&sq->sqsl);
1511 : 0 : return;
1512 : : }
1513 : 0 : next_idx = cq->cq_ci & mask;
1514 : : do {
1515 : 0 : idx = next_idx;
1516 : 0 : next_idx = (cq->cq_ci + 1) & mask;
1517 : : /* Need to confirm the position of the prefetch. */
1518 : 0 : rte_prefetch0(&cq->cq_obj.cqes[next_idx]);
1519 : 0 : cqe = &cq->cq_obj.cqes[idx];
1520 [ # # ]: 0 : ret = check_cqe(cqe, cq_size, cq->cq_ci);
1521 : : /*
1522 : : * Be sure owner read is done before any other cookie field or
1523 : : * opaque field.
1524 : : */
1525 : 0 : rte_io_rmb();
1526 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
1527 [ # # ]: 0 : if (likely(ret == MLX5_CQE_STATUS_HW_OWN))
1528 : : break;
1529 : 0 : mlx5_aso_cqe_err_handle(sq);
1530 : : } else {
1531 : 0 : n++;
1532 : : }
1533 : 0 : cq->cq_ci++;
1534 : : } while (1);
1535 [ # # ]: 0 : if (likely(n)) {
1536 : 0 : mlx5_aso_ct_status_update(sq, n);
1537 : 0 : sq->tail += n;
1538 : 0 : rte_io_wmb();
1539 [ # # ]: 0 : cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
1540 : : }
1541 [ # # ]: 0 : if (need_lock)
1542 : 0 : rte_spinlock_unlock(&sq->sqsl);
1543 : : }
1544 : :
1545 : : /*
1546 : : * Update connection tracking ASO context by sending WQE.
1547 : : *
1548 : : * @param[in] sh
1549 : : * Pointer to mlx5_dev_ctx_shared object.
1550 : : * @param[in] queue
1551 : : * The queue index.
1552 : : * @param[in] ct
1553 : : * Pointer to connection tracking offload object.
1554 : : * @param[in] profile
1555 : : * Pointer to connection tracking TCP parameter.
1556 : : *
1557 : : * @return
1558 : : * 0 on success, -1 on failure.
1559 : : */
1560 : : int
1561 [ # # ]: 0 : mlx5_aso_ct_update_by_wqe(struct mlx5_dev_ctx_shared *sh,
1562 : : uint32_t queue,
1563 : : struct mlx5_aso_ct_action *ct,
1564 : : const struct rte_flow_action_conntrack *profile,
1565 : : void *user_data,
1566 : : bool push)
1567 : : {
1568 : : uint32_t poll_wqe_times = MLX5_CT_POLL_WQE_CQE_TIMES;
1569 : : struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct);
1570 : : struct mlx5_aso_sq *sq;
1571 : 0 : bool need_lock = !!(queue == MLX5_HW_INV_QUEUE);
1572 : : int ret;
1573 : :
1574 [ # # ]: 0 : if (sh->config.dv_flow_en == 2)
1575 : : sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool);
1576 : : else
1577 : : sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct);
1578 [ # # ]: 0 : if (queue != MLX5_HW_INV_QUEUE) {
1579 : 0 : ret = mlx5_aso_ct_sq_enqueue_single(sh, sq, ct, profile,
1580 : : need_lock, user_data, push);
1581 [ # # ]: 0 : return ret > 0 ? 0 : -1;
1582 : : }
1583 : : do {
1584 : 0 : mlx5_aso_ct_completion_handle(sh, sq, need_lock);
1585 [ # # ]: 0 : if (mlx5_aso_ct_sq_enqueue_single(sh, sq, ct, profile,
1586 : : need_lock, NULL, true))
1587 : : return 0;
1588 : : /* Waiting for wqe resource. */
1589 : 0 : rte_delay_us_sleep(10u);
1590 [ # # ]: 0 : } while (--poll_wqe_times);
1591 : 0 : DRV_LOG(ERR, "Fail to send WQE for ASO CT %d in pool %d",
1592 : : ct->offset, pool->index);
1593 : 0 : return -1;
1594 : : }
1595 : :
1596 : : /*
1597 : : * The routine is used to wait for WQE completion to continue with queried data.
1598 : : *
1599 : : * @param[in] sh
1600 : : * Pointer to mlx5_dev_ctx_shared object.
1601 : : * @param[in] queue
1602 : : * The queue which CT works on..
1603 : : * @param[in] ct
1604 : : * Pointer to connection tracking offload object.
1605 : : *
1606 : : * @return
1607 : : * 0 on success, -1 on failure.
1608 : : */
1609 : : int
1610 [ # # ]: 0 : mlx5_aso_ct_wait_ready(struct mlx5_dev_ctx_shared *sh, uint32_t queue,
1611 : : struct mlx5_aso_ct_action *ct)
1612 : : {
1613 : : uint32_t poll_cqe_times = MLX5_CT_POLL_WQE_CQE_TIMES;
1614 : : struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct);
1615 : : struct mlx5_aso_sq *sq;
1616 : 0 : bool need_lock = !!(queue == MLX5_HW_INV_QUEUE);
1617 : :
1618 [ # # ]: 0 : if (sh->config.dv_flow_en == 2)
1619 : : sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool);
1620 : : else
1621 : : sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct);
1622 [ # # ]: 0 : if (rte_atomic_load_explicit(&ct->state, rte_memory_order_relaxed) ==
1623 : : ASO_CONNTRACK_READY)
1624 : : return 0;
1625 : : do {
1626 : 0 : mlx5_aso_ct_completion_handle(sh, sq, need_lock);
1627 [ # # ]: 0 : if (rte_atomic_load_explicit(&ct->state, rte_memory_order_relaxed) ==
1628 : : ASO_CONNTRACK_READY)
1629 : : return 0;
1630 : : /* Waiting for CQE ready, consider should block or sleep. */
1631 : 0 : rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
1632 [ # # ]: 0 : } while (--poll_cqe_times);
1633 : 0 : DRV_LOG(ERR, "Fail to poll CQE for ASO CT %d in pool %d",
1634 : : ct->offset, pool->index);
1635 : 0 : return -1;
1636 : : }
1637 : :
1638 : : /*
1639 : : * Convert the hardware conntrack data format into the profile.
1640 : : *
1641 : : * @param[in] profile
1642 : : * Pointer to conntrack profile to be filled after query.
1643 : : * @param[in] wdata
1644 : : * Pointer to data fetched from hardware.
1645 : : */
1646 : : void
1647 : 0 : mlx5_aso_ct_obj_analyze(struct rte_flow_action_conntrack *profile,
1648 : : char *wdata)
1649 : : {
1650 : : void *o_dir = MLX5_ADDR_OF(conn_track_aso, wdata, original_dir);
1651 : : void *r_dir = MLX5_ADDR_OF(conn_track_aso, wdata, reply_dir);
1652 : :
1653 : : /* MLX5_GET16 should be taken into consideration. */
1654 : 0 : profile->state = (enum rte_flow_conntrack_state)
1655 [ # # ]: 0 : MLX5_GET(conn_track_aso, wdata, state);
1656 [ # # ]: 0 : profile->enable = !MLX5_GET(conn_track_aso, wdata, freeze_track);
1657 [ # # ]: 0 : profile->selective_ack = MLX5_GET(conn_track_aso, wdata,
1658 : : sack_permitted);
1659 [ # # ]: 0 : profile->live_connection = MLX5_GET(conn_track_aso, wdata,
1660 : : connection_assured);
1661 [ # # ]: 0 : profile->challenge_ack_passed = MLX5_GET(conn_track_aso, wdata,
1662 : : challenged_acked);
1663 [ # # ]: 0 : profile->max_ack_window = MLX5_GET(conn_track_aso, wdata,
1664 : : max_ack_window);
1665 [ # # ]: 0 : profile->retransmission_limit = MLX5_GET(conn_track_aso, wdata,
1666 : : retranmission_limit);
1667 [ # # ]: 0 : profile->last_window = MLX5_GET(conn_track_aso, wdata, last_win);
1668 [ # # ]: 0 : profile->last_direction = MLX5_GET(conn_track_aso, wdata, last_dir);
1669 : 0 : profile->last_index = (enum rte_flow_conntrack_tcp_last_index)
1670 [ # # ]: 0 : MLX5_GET(conn_track_aso, wdata, last_index);
1671 [ # # ]: 0 : profile->last_seq = MLX5_GET(conn_track_aso, wdata, last_seq);
1672 [ # # ]: 0 : profile->last_ack = MLX5_GET(conn_track_aso, wdata, last_ack);
1673 [ # # ]: 0 : profile->last_end = MLX5_GET(conn_track_aso, wdata, last_end);
1674 : 0 : profile->liberal_mode = MLX5_GET(conn_track_aso, wdata,
1675 [ # # # # ]: 0 : reply_direction_tcp_liberal_enabled) |
1676 : 0 : MLX5_GET(conn_track_aso, wdata,
1677 : : original_direction_tcp_liberal_enabled);
1678 : : /* No liberal in the RTE structure profile. */
1679 [ # # ]: 0 : profile->reply_dir.scale = MLX5_GET(conn_track_aso, wdata,
1680 : : reply_direction_tcp_scale);
1681 [ # # ]: 0 : profile->reply_dir.close_initiated = MLX5_GET(conn_track_aso, wdata,
1682 : : reply_direction_tcp_close_initiated);
1683 [ # # ]: 0 : profile->reply_dir.data_unacked = MLX5_GET(conn_track_aso, wdata,
1684 : : reply_direction_tcp_data_unacked);
1685 [ # # ]: 0 : profile->reply_dir.last_ack_seen = MLX5_GET(conn_track_aso, wdata,
1686 : : reply_direction_tcp_max_ack);
1687 [ # # ]: 0 : profile->reply_dir.sent_end = MLX5_GET(tcp_window_params,
1688 : : r_dir, sent_end);
1689 [ # # ]: 0 : profile->reply_dir.reply_end = MLX5_GET(tcp_window_params,
1690 : : r_dir, reply_end);
1691 [ # # ]: 0 : profile->reply_dir.max_win = MLX5_GET(tcp_window_params,
1692 : : r_dir, max_win);
1693 [ # # ]: 0 : profile->reply_dir.max_ack = MLX5_GET(tcp_window_params,
1694 : : r_dir, max_ack);
1695 [ # # ]: 0 : profile->original_dir.scale = MLX5_GET(conn_track_aso, wdata,
1696 : : original_direction_tcp_scale);
1697 [ # # ]: 0 : profile->original_dir.close_initiated = MLX5_GET(conn_track_aso, wdata,
1698 : : original_direction_tcp_close_initiated);
1699 [ # # ]: 0 : profile->original_dir.data_unacked = MLX5_GET(conn_track_aso, wdata,
1700 : : original_direction_tcp_data_unacked);
1701 [ # # ]: 0 : profile->original_dir.last_ack_seen = MLX5_GET(conn_track_aso, wdata,
1702 : : original_direction_tcp_max_ack);
1703 [ # # ]: 0 : profile->original_dir.sent_end = MLX5_GET(tcp_window_params,
1704 : : o_dir, sent_end);
1705 [ # # ]: 0 : profile->original_dir.reply_end = MLX5_GET(tcp_window_params,
1706 : : o_dir, reply_end);
1707 [ # # ]: 0 : profile->original_dir.max_win = MLX5_GET(tcp_window_params,
1708 : : o_dir, max_win);
1709 [ # # ]: 0 : profile->original_dir.max_ack = MLX5_GET(tcp_window_params,
1710 : : o_dir, max_ack);
1711 : 0 : }
1712 : :
1713 : : /*
1714 : : * Query connection tracking information parameter by send WQE.
1715 : : *
1716 : : * @param[in] dev
1717 : : * Pointer to Ethernet device.
1718 : : * @param[in] ct
1719 : : * Pointer to connection tracking offload object.
1720 : : * @param[out] profile
1721 : : * Pointer to connection tracking TCP information.
1722 : : *
1723 : : * @return
1724 : : * 0 on success, -1 on failure.
1725 : : */
1726 : : int
1727 [ # # ]: 0 : mlx5_aso_ct_query_by_wqe(struct mlx5_dev_ctx_shared *sh,
1728 : : uint32_t queue,
1729 : : struct mlx5_aso_ct_action *ct,
1730 : : struct rte_flow_action_conntrack *profile,
1731 : : void *user_data, bool push)
1732 : : {
1733 : : uint32_t poll_wqe_times = MLX5_CT_POLL_WQE_CQE_TIMES;
1734 : : struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct);
1735 : : struct mlx5_aso_sq *sq;
1736 : 0 : bool need_lock = !!(queue == MLX5_HW_INV_QUEUE);
1737 : : char out_data[64 * 2];
1738 : : int ret;
1739 : :
1740 [ # # ]: 0 : if (sh->config.dv_flow_en == 2)
1741 : : sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool);
1742 : : else
1743 : : sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct);
1744 [ # # ]: 0 : if (queue != MLX5_HW_INV_QUEUE) {
1745 : 0 : ret = mlx5_aso_ct_sq_query_single(sh, sq, ct, out_data,
1746 : : need_lock, user_data, push);
1747 [ # # ]: 0 : return ret > 0 ? 0 : -1;
1748 : : }
1749 : : do {
1750 : 0 : mlx5_aso_ct_completion_handle(sh, sq, need_lock);
1751 : 0 : ret = mlx5_aso_ct_sq_query_single(sh, sq, ct, out_data,
1752 : : need_lock, NULL, true);
1753 [ # # ]: 0 : if (ret < 0)
1754 : 0 : return ret;
1755 [ # # ]: 0 : else if (ret > 0)
1756 : 0 : goto data_handle;
1757 : : /* Waiting for wqe resource or state. */
1758 : : else
1759 : 0 : rte_delay_us_sleep(10u);
1760 [ # # ]: 0 : } while (--poll_wqe_times);
1761 : 0 : DRV_LOG(ERR, "Fail to send WQE for ASO CT %d in pool %d",
1762 : : ct->offset, pool->index);
1763 : 0 : return -1;
1764 : : data_handle:
1765 : 0 : ret = mlx5_aso_ct_wait_ready(sh, queue, ct);
1766 [ # # ]: 0 : if (!ret)
1767 : 0 : mlx5_aso_ct_obj_analyze(profile, out_data);
1768 : : return ret;
1769 : : }
1770 : :
1771 : : /*
1772 : : * Make sure the conntrack context is synchronized with hardware before
1773 : : * creating a flow rule that uses it.
1774 : : *
1775 : : * @param[in] sh
1776 : : * Pointer to shared device context.
1777 : : * @param[in] ct
1778 : : * Pointer to connection tracking offload object.
1779 : : *
1780 : : * @return
1781 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1782 : : */
1783 : : int
1784 [ # # ]: 0 : mlx5_aso_ct_available(struct mlx5_dev_ctx_shared *sh,
1785 : : uint32_t queue,
1786 : : struct mlx5_aso_ct_action *ct)
1787 : : {
1788 : : struct mlx5_aso_ct_pool *pool = __mlx5_aso_ct_get_pool(sh, ct);
1789 : : struct mlx5_aso_sq *sq;
1790 : 0 : bool need_lock = !!(queue == MLX5_HW_INV_QUEUE);
1791 : : uint32_t poll_cqe_times = MLX5_CT_POLL_WQE_CQE_TIMES;
1792 : : enum mlx5_aso_ct_state state =
1793 : 0 : rte_atomic_load_explicit(&ct->state, rte_memory_order_relaxed);
1794 : :
1795 [ # # ]: 0 : if (sh->config.dv_flow_en == 2)
1796 : : sq = __mlx5_aso_ct_get_sq_in_hws(queue, pool);
1797 : : else
1798 : : sq = __mlx5_aso_ct_get_sq_in_sws(sh, ct);
1799 [ # # ]: 0 : if (state == ASO_CONNTRACK_FREE) {
1800 : 0 : rte_errno = ENXIO;
1801 : 0 : return -rte_errno;
1802 : 0 : } else if (state == ASO_CONNTRACK_READY ||
1803 [ # # ]: 0 : state == ASO_CONNTRACK_QUERY ||
1804 : : state == ASO_CONNTRACK_WAIT_ASYNC) {
1805 : : return 0;
1806 : : }
1807 : : do {
1808 : 0 : mlx5_aso_ct_completion_handle(sh, sq, need_lock);
1809 : 0 : state = rte_atomic_load_explicit(&ct->state, rte_memory_order_relaxed);
1810 [ # # ]: 0 : if (state == ASO_CONNTRACK_READY ||
1811 : : state == ASO_CONNTRACK_QUERY)
1812 : : return 0;
1813 : : /* Waiting for CQE ready, consider should block or sleep. */
1814 : 0 : rte_delay_us_block(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
1815 [ # # ]: 0 : } while (--poll_cqe_times);
1816 : 0 : rte_errno = EBUSY;
1817 : 0 : return -rte_errno;
1818 : : }
1819 : :
1820 : : int
1821 : 0 : mlx5_aso_cnt_queue_init(struct mlx5_dev_ctx_shared *sh)
1822 : : {
1823 : : struct mlx5_hws_aso_mng *aso_mng = NULL;
1824 : : uint8_t idx;
1825 : : struct mlx5_aso_sq *sq;
1826 : :
1827 : : MLX5_ASSERT(sh);
1828 : : MLX5_ASSERT(sh->cnt_svc);
1829 : 0 : aso_mng = &sh->cnt_svc->aso_mng;
1830 : 0 : aso_mng->sq_num = HWS_CNT_ASO_SQ_NUM;
1831 [ # # ]: 0 : for (idx = 0; idx < HWS_CNT_ASO_SQ_NUM; idx++) {
1832 : 0 : sq = &aso_mng->sqs[idx];
1833 [ # # ]: 0 : if (mlx5_aso_sq_create(sh->cdev, sq, sh->tx_uar.obj,
1834 : : MLX5_ASO_CNT_QUEUE_LOG_DESC))
1835 : 0 : goto error;
1836 : 0 : mlx5_aso_cnt_init_sq(sq);
1837 : : }
1838 : : return 0;
1839 : : error:
1840 : 0 : mlx5_aso_cnt_queue_uninit(sh);
1841 : 0 : return -1;
1842 : : }
1843 : :
1844 : : void
1845 : 0 : mlx5_aso_cnt_queue_uninit(struct mlx5_dev_ctx_shared *sh)
1846 : : {
1847 : : uint16_t idx;
1848 : :
1849 [ # # ]: 0 : for (idx = 0; idx < sh->cnt_svc->aso_mng.sq_num; idx++)
1850 : 0 : mlx5_aso_destroy_sq(&sh->cnt_svc->aso_mng.sqs[idx]);
1851 : 0 : sh->cnt_svc->aso_mng.sq_num = 0;
1852 : 0 : }
1853 : :
1854 : : static uint16_t
1855 : 0 : mlx5_aso_cnt_sq_enqueue_burst(struct mlx5_hws_cnt_pool *cpool,
1856 : : struct mlx5_dev_ctx_shared *sh,
1857 : : struct mlx5_aso_sq *sq, uint32_t n,
1858 : : uint32_t offset, uint32_t dcs_id_base)
1859 : : {
1860 : : volatile struct mlx5_aso_wqe *wqe;
1861 : 0 : uint16_t size = 1 << sq->log_desc_n;
1862 : 0 : uint16_t mask = size - 1;
1863 : : uint16_t max;
1864 : : uint32_t upper_offset = offset;
1865 : : uint64_t addr;
1866 : : uint32_t ctrl_gen_id = 0;
1867 : 0 : uint8_t opcmod = sh->cdev->config.hca_attr.flow_access_aso_opc_mod;
1868 [ # # ]: 0 : rte_be32_t lkey = rte_cpu_to_be_32(cpool->raw_mng->mr.lkey);
1869 : 0 : uint16_t aso_n = (uint16_t)(RTE_ALIGN_CEIL(n, 4) / 4);
1870 : : uint32_t ccntid;
1871 : :
1872 : 0 : max = RTE_MIN(size - (uint16_t)(sq->head - sq->tail), aso_n);
1873 [ # # ]: 0 : if (unlikely(!max))
1874 : : return 0;
1875 : 0 : upper_offset += (max * 4);
1876 : : /* Because only one burst at one time, we can use the same elt. */
1877 : 0 : sq->elts[0].burst_size = max;
1878 : : ctrl_gen_id = dcs_id_base;
1879 : 0 : ctrl_gen_id /= 4;
1880 : : do {
1881 : 0 : ccntid = upper_offset - max * 4;
1882 : 0 : wqe = &sq->sq_obj.aso_wqes[sq->head & mask];
1883 : 0 : rte_prefetch0(&sq->sq_obj.aso_wqes[(sq->head + 1) & mask]);
1884 [ # # ]: 0 : wqe->general_cseg.misc = rte_cpu_to_be_32(ctrl_gen_id);
1885 : 0 : wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ONLY_FIRST_ERR <<
1886 : : MLX5_COMP_MODE_OFFSET);
1887 [ # # ]: 0 : wqe->general_cseg.opcode = rte_cpu_to_be_32
1888 : : (MLX5_OPCODE_ACCESS_ASO |
1889 : : (opcmod <<
1890 : : WQE_CSEG_OPC_MOD_OFFSET) |
1891 : : (sq->pi <<
1892 : : WQE_CSEG_WQE_INDEX_OFFSET));
1893 : 0 : addr = (uint64_t)RTE_PTR_ADD(cpool->raw_mng->raw,
1894 : : ccntid * sizeof(struct flow_counter_stats));
1895 [ # # ]: 0 : wqe->aso_cseg.va_h = rte_cpu_to_be_32((uint32_t)(addr >> 32));
1896 [ # # ]: 0 : wqe->aso_cseg.va_l_r = rte_cpu_to_be_32((uint32_t)addr | 1u);
1897 : 0 : wqe->aso_cseg.lkey = lkey;
1898 : 0 : sq->pi += 2; /* Each WQE contains 2 WQEBB's. */
1899 : 0 : sq->head++;
1900 : 0 : sq->next++;
1901 : 0 : ctrl_gen_id++;
1902 : 0 : max--;
1903 [ # # ]: 0 : } while (max);
1904 : 0 : wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ALWAYS <<
1905 : : MLX5_COMP_MODE_OFFSET);
1906 : 0 : mlx5_doorbell_ring(&sh->tx_uar.bf_db, *(volatile uint64_t *)wqe,
1907 : 0 : sq->pi, &sq->sq_obj.db_rec[MLX5_SND_DBR],
1908 : 0 : !sh->tx_uar.dbnc);
1909 : 0 : return sq->elts[0].burst_size;
1910 : : }
1911 : :
1912 : : static uint16_t
1913 : 0 : mlx5_aso_cnt_completion_handle(struct mlx5_aso_sq *sq)
1914 : : {
1915 : : struct mlx5_aso_cq *cq = &sq->cq;
1916 : : volatile struct mlx5_cqe *restrict cqe;
1917 : 0 : const unsigned int cq_size = 1 << cq->log_desc_n;
1918 : 0 : const unsigned int mask = cq_size - 1;
1919 : : uint32_t idx;
1920 : 0 : uint32_t next_idx = cq->cq_ci & mask;
1921 : 0 : const uint16_t max = (uint16_t)(sq->head - sq->tail);
1922 : : uint16_t i = 0;
1923 : : int ret;
1924 [ # # ]: 0 : if (unlikely(!max))
1925 : : return 0;
1926 : : idx = next_idx;
1927 : 0 : next_idx = (cq->cq_ci + 1) & mask;
1928 : 0 : rte_prefetch0(&cq->cq_obj.cqes[next_idx]);
1929 : 0 : cqe = &cq->cq_obj.cqes[idx];
1930 [ # # ]: 0 : ret = check_cqe(cqe, cq_size, cq->cq_ci);
1931 : : /*
1932 : : * Be sure owner read is done before any other cookie field or
1933 : : * opaque field.
1934 : : */
1935 : 0 : rte_io_rmb();
1936 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
1937 [ # # ]: 0 : if (likely(ret == MLX5_CQE_STATUS_HW_OWN))
1938 : : return 0; /* return immediately. */
1939 : 0 : mlx5_aso_cqe_err_handle(sq);
1940 : : }
1941 : 0 : i += sq->elts[0].burst_size;
1942 : 0 : sq->elts[0].burst_size = 0;
1943 : 0 : cq->cq_ci++;
1944 [ # # ]: 0 : if (likely(i)) {
1945 : 0 : sq->tail += i;
1946 : 0 : rte_io_wmb();
1947 [ # # ]: 0 : cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
1948 : : }
1949 : : return i;
1950 : : }
1951 : :
1952 : : static uint16_t
1953 : 0 : mlx5_aso_cnt_query_one_dcs(struct mlx5_dev_ctx_shared *sh,
1954 : : struct mlx5_hws_cnt_pool *cpool,
1955 : : uint8_t dcs_idx, uint32_t num)
1956 : : {
1957 : 0 : uint32_t dcs_id = cpool->dcs_mng.dcs[dcs_idx].obj->id;
1958 : 0 : uint64_t cnt_num = cpool->dcs_mng.dcs[dcs_idx].batch_sz;
1959 : : uint64_t left;
1960 : 0 : uint32_t iidx = cpool->dcs_mng.dcs[dcs_idx].iidx;
1961 : : uint32_t offset;
1962 : : uint16_t mask;
1963 : : uint16_t sq_idx;
1964 : : uint64_t burst_sz = (uint64_t)(1 << MLX5_ASO_CNT_QUEUE_LOG_DESC) * 4 *
1965 : : sh->cnt_svc->aso_mng.sq_num;
1966 : : uint64_t qburst_sz = burst_sz / sh->cnt_svc->aso_mng.sq_num;
1967 : : uint64_t n;
1968 : : struct mlx5_aso_sq *sq;
1969 : :
1970 : 0 : cnt_num = RTE_MIN(num, cnt_num);
1971 : : left = cnt_num;
1972 [ # # ]: 0 : while (left) {
1973 : : mask = 0;
1974 [ # # ]: 0 : for (sq_idx = 0; sq_idx < sh->cnt_svc->aso_mng.sq_num;
1975 : 0 : sq_idx++) {
1976 [ # # ]: 0 : if (left == 0) {
1977 : 0 : mask |= (1 << sq_idx);
1978 : 0 : continue;
1979 : : }
1980 : 0 : n = RTE_MIN(left, qburst_sz);
1981 : 0 : offset = cnt_num - left;
1982 : 0 : offset += iidx;
1983 : 0 : mlx5_aso_cnt_sq_enqueue_burst(cpool, sh,
1984 : 0 : &sh->cnt_svc->aso_mng.sqs[sq_idx], n,
1985 : : offset, dcs_id);
1986 : 0 : left -= n;
1987 : : }
1988 : : do {
1989 [ # # ]: 0 : for (sq_idx = 0; sq_idx < sh->cnt_svc->aso_mng.sq_num;
1990 : 0 : sq_idx++) {
1991 : 0 : sq = &sh->cnt_svc->aso_mng.sqs[sq_idx];
1992 [ # # ]: 0 : if (mlx5_aso_cnt_completion_handle(sq))
1993 : 0 : mask |= (1 << sq_idx);
1994 : : }
1995 [ # # ]: 0 : } while (mask < ((1 << sh->cnt_svc->aso_mng.sq_num) - 1));
1996 : : }
1997 : 0 : return cnt_num;
1998 : : }
1999 : :
2000 : : /*
2001 : : * Query FW counter via ASO WQE.
2002 : : *
2003 : : * ASO query counter use _sync_ mode, means:
2004 : : * 1. each SQ issue one burst with several WQEs
2005 : : * 2. ask for CQE at last WQE
2006 : : * 3. busy poll CQ of each SQ's
2007 : : * 4. If all SQ's CQE are received then goto step 1, issue next burst
2008 : : *
2009 : : * @param[in] sh
2010 : : * Pointer to shared device.
2011 : : * @param[in] cpool
2012 : : * Pointer to counter pool.
2013 : : *
2014 : : * @return
2015 : : * 0 on success, -1 on failure.
2016 : : */
2017 : : int
2018 [ # # ]: 0 : mlx5_aso_cnt_query(struct mlx5_dev_ctx_shared *sh,
2019 : : struct mlx5_hws_cnt_pool *cpool)
2020 : : {
2021 : : uint32_t idx;
2022 : : uint32_t num;
2023 : 0 : uint32_t cnt_num = mlx5_hws_cnt_pool_get_size(cpool) -
2024 : 0 : rte_ring_count(cpool->free_list);
2025 : :
2026 [ # # ]: 0 : for (idx = 0; idx < cpool->dcs_mng.batch_total; idx++) {
2027 : 0 : num = RTE_MIN(cnt_num, cpool->dcs_mng.dcs[idx].batch_sz);
2028 : 0 : mlx5_aso_cnt_query_one_dcs(sh, cpool, idx, num);
2029 : 0 : cnt_num -= num;
2030 [ # # ]: 0 : if (cnt_num == 0)
2031 : : break;
2032 : : }
2033 : 0 : return 0;
2034 : : }
|