net/mlx5: support flow hit action for aging
[dpdk.git] / drivers / net / mlx5 / mlx5_flow_age.c
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
8 #include <mlx5_malloc.h>
9 #include <mlx5_common_os.h>
10
11 #include "mlx5.h"
12 #include "mlx5_flow.h"
13
14 /**
15  * Destroy Completion Queue used for ASO access.
16  *
17  * @param[in] cq
18  *   ASO CQ to destroy.
19  */
20 static void
21 mlx5_aso_cq_destroy(struct mlx5_aso_cq *cq)
22 {
23         if (cq->cq)
24                 claim_zero(mlx5_devx_cmd_destroy(cq->cq));
25         if (cq->umem_obj)
26                 claim_zero(mlx5_glue->devx_umem_dereg(cq->umem_obj));
27         if (cq->umem_buf)
28                 mlx5_free((void *)(uintptr_t)cq->umem_buf);
29         memset(cq, 0, sizeof(*cq));
30 }
31
32 /**
33  * Create Completion Queue used for ASO access.
34  *
35  * @param[in] ctx
36  *   Context returned from mlx5 open_device() glue function.
37  * @param[in/out] cq
38  *   Pointer to CQ to create.
39  * @param[in] log_desc_n
40  *   Log of number of descriptors in queue.
41  * @param[in] socket
42  *   Socket to use for allocation.
43  * @param[in] uar_page_id
44  *   UAR page ID to use.
45  * @param[in] eqn
46  *   EQ number.
47  *
48  * @return
49  *   0 on success, a negative errno value otherwise and rte_errno is set.
50  */
51 static int
52 mlx5_aso_cq_create(void *ctx, struct mlx5_aso_cq *cq, uint16_t log_desc_n,
53                    int socket, int uar_page_id, uint32_t eqn)
54 {
55         struct mlx5_devx_cq_attr attr = { 0 };
56         size_t pgsize = sysconf(_SC_PAGESIZE);
57         uint32_t umem_size;
58         uint16_t cq_size = 1 << log_desc_n;
59
60         cq->log_desc_n = log_desc_n;
61         umem_size = sizeof(struct mlx5_cqe) * cq_size + sizeof(*cq->db_rec) * 2;
62         cq->umem_buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, umem_size,
63                                    4096, socket);
64         if (!cq->umem_buf) {
65                 DRV_LOG(ERR, "Failed to allocate memory for CQ.");
66                 rte_errno = ENOMEM;
67                 return -ENOMEM;
68         }
69         cq->umem_obj = mlx5_glue->devx_umem_reg(ctx,
70                                                 (void *)(uintptr_t)cq->umem_buf,
71                                                 umem_size,
72                                                 IBV_ACCESS_LOCAL_WRITE);
73         if (!cq->umem_obj) {
74                 DRV_LOG(ERR, "Failed to register umem for aso CQ.");
75                 goto error;
76         }
77         attr.q_umem_valid = 1;
78         attr.db_umem_valid = 1;
79         attr.use_first_only = 0;
80         attr.overrun_ignore = 0;
81         attr.uar_page_id = uar_page_id;
82         attr.q_umem_id = mlx5_os_get_umem_id(cq->umem_obj);
83         attr.q_umem_offset = 0;
84         attr.db_umem_id = attr.q_umem_id;
85         attr.db_umem_offset = sizeof(struct mlx5_cqe) * cq_size;
86         attr.eqn = eqn;
87         attr.log_cq_size = log_desc_n;
88         attr.log_page_size = rte_log2_u32(pgsize);
89         cq->cq = mlx5_devx_cmd_create_cq(ctx, &attr);
90         if (!cq->cq)
91                 goto error;
92         cq->db_rec = RTE_PTR_ADD(cq->umem_buf, (uintptr_t)attr.db_umem_offset);
93         cq->cq_ci = 0;
94         memset((void *)(uintptr_t)cq->umem_buf, 0xFF, attr.db_umem_offset);
95         return 0;
96 error:
97         mlx5_aso_cq_destroy(cq);
98         return -1;
99 }
100
101 /**
102  * Free MR resources.
103  *
104  * @param[in] mr
105  *   MR to free.
106  */
107 static void
108 mlx5_aso_devx_dereg_mr(struct mlx5_aso_devx_mr *mr)
109 {
110         claim_zero(mlx5_devx_cmd_destroy(mr->mkey));
111         if (!mr->is_indirect && mr->umem)
112                 claim_zero(mlx5_glue->devx_umem_dereg(mr->umem));
113         mlx5_free(mr->buf);
114         memset(mr, 0, sizeof(*mr));
115 }
116
117 /**
118  * Register Memory Region.
119  *
120  * @param[in] ctx
121  *   Context returned from mlx5 open_device() glue function.
122  * @param[in] length
123  *   Size of MR buffer.
124  * @param[in/out] mr
125  *   Pointer to MR to create.
126  * @param[in] socket
127  *   Socket to use for allocation.
128  * @param[in] pdn
129  *   Protection Domain number to use.
130  *
131  * @return
132  *   0 on success, a negative errno value otherwise and rte_errno is set.
133  */
134 static int
135 mlx5_aso_devx_reg_mr(void *ctx, size_t length, struct mlx5_aso_devx_mr *mr,
136                      int socket, int pdn)
137 {
138         struct mlx5_devx_mkey_attr mkey_attr;
139
140         mr->buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, length, 4096,
141                               socket);
142         if (!mr->buf) {
143                 DRV_LOG(ERR, "Failed to create ASO bits mem for MR by Devx.");
144                 return -1;
145         }
146         mr->umem = mlx5_glue->devx_umem_reg(ctx, mr->buf, length,
147                                                  IBV_ACCESS_LOCAL_WRITE);
148         if (!mr->umem) {
149                 DRV_LOG(ERR, "Failed to register Umem for MR by Devx.");
150                 goto error;
151         }
152         mkey_attr.addr = (uintptr_t)mr->buf;
153         mkey_attr.size = length;
154         mkey_attr.umem_id = mlx5_os_get_umem_id(mr->umem);
155         mkey_attr.pd = pdn;
156         mkey_attr.pg_access = 1;
157         mkey_attr.klm_array = NULL;
158         mkey_attr.klm_num = 0;
159         mkey_attr.relaxed_ordering = 0;
160         mr->mkey = mlx5_devx_cmd_mkey_create(ctx, &mkey_attr);
161         if (!mr->mkey) {
162                 DRV_LOG(ERR, "Failed to create direct Mkey.");
163                 goto error;
164         }
165         mr->length = length;
166         mr->is_indirect = false;
167         return 0;
168 error:
169         if (mr->umem)
170                 claim_zero(mlx5_glue->devx_umem_dereg(mr->umem));
171         mlx5_free(mr->buf);
172         return -1;
173 }
174
175 /**
176  * Destroy Send Queue used for ASO access.
177  *
178  * @param[in] sq
179  *   ASO SQ to destroy.
180  */
181 static void
182 mlx5_aso_destroy_sq(struct mlx5_aso_sq *sq)
183 {
184         if (sq->wqe_umem) {
185                 mlx5_glue->devx_umem_dereg(sq->wqe_umem);
186                 sq->wqe_umem = NULL;
187         }
188         if (sq->umem_buf) {
189                 mlx5_free((void *)(uintptr_t)sq->umem_buf);
190                 sq->umem_buf = NULL;
191         }
192         if (sq->sq) {
193                 mlx5_devx_cmd_destroy(sq->sq);
194                 sq->sq = NULL;
195         }
196         if (sq->cq.cq)
197                 mlx5_aso_cq_destroy(&sq->cq);
198         if (sq->uar_obj)
199                 mlx5_glue->devx_free_uar(sq->uar_obj);
200         mlx5_aso_devx_dereg_mr(&sq->mr);
201         memset(sq, 0, sizeof(*sq));
202 }
203
204 /**
205  * Initialize Send Queue used for ASO access.
206  *
207  * @param[in] sq
208  *   ASO SQ to initialize.
209  */
210 static void
211 mlx5_aso_init_sq(struct mlx5_aso_sq *sq)
212 {
213         volatile struct mlx5_aso_wqe *restrict wqe;
214         int i;
215         int size = 1 << sq->log_desc_n;
216         uint64_t addr;
217
218         /* All the next fields state should stay constant. */
219         for (i = 0, wqe = &sq->wqes[0]; i < size; ++i, ++wqe) {
220                 wqe->general_cseg.sq_ds = rte_cpu_to_be_32((sq->sqn << 8) |
221                                                           (sizeof(*wqe) >> 4));
222                 wqe->aso_cseg.lkey = rte_cpu_to_be_32(sq->mr.mkey->id);
223                 addr = (uint64_t)((uint64_t *)sq->mr.buf + i *
224                                             MLX5_ASO_AGE_ACTIONS_PER_POOL / 64);
225                 wqe->aso_cseg.va_h = rte_cpu_to_be_32((uint32_t)(addr >> 32));
226                 wqe->aso_cseg.va_l_r = rte_cpu_to_be_32((uint32_t)addr | 1u);
227                 wqe->aso_cseg.operand_masks = rte_cpu_to_be_32
228                         (0u |
229                          (ASO_OPER_LOGICAL_OR << ASO_CSEG_COND_OPER_OFFSET) |
230                          (ASO_OP_ALWAYS_TRUE << ASO_CSEG_COND_1_OPER_OFFSET) |
231                          (ASO_OP_ALWAYS_TRUE << ASO_CSEG_COND_0_OPER_OFFSET) |
232                          (BYTEWISE_64BYTE << ASO_CSEG_DATA_MASK_MODE_OFFSET));
233                 wqe->aso_cseg.data_mask = RTE_BE64(UINT64_MAX);
234         }
235 }
236
237 /**
238  * Create Send Queue used for ASO access.
239  *
240  * @param[in] ctx
241  *   Context returned from mlx5 open_device() glue function.
242  * @param[in/out] sq
243  *   Pointer to SQ to create.
244  * @param[in] socket
245  *   Socket to use for allocation.
246  * @param[in] pdn
247  *   Protection Domain number to use.
248  * @param[in] eqn
249  *   EQ number.
250  * @param[in] log_desc_n
251  *   Log of number of descriptors in queue.
252  *
253  * @return
254  *   0 on success, a negative errno value otherwise and rte_errno is set.
255  */
256 static int
257 mlx5_aso_sq_create(void *ctx, struct mlx5_aso_sq *sq, int socket,
258                    uint32_t pdn, uint32_t eqn,  uint16_t log_desc_n)
259 {
260         struct mlx5_devx_create_sq_attr attr = { 0 };
261         struct mlx5_devx_modify_sq_attr modify_attr = { 0 };
262         size_t pgsize = sysconf(_SC_PAGESIZE);
263         struct mlx5_devx_wq_attr *wq_attr = &attr.wq_attr;
264         uint32_t sq_desc_n = 1 << log_desc_n;
265         uint32_t wq_size = sizeof(struct mlx5_aso_wqe) * sq_desc_n;
266         int ret;
267
268         if (mlx5_aso_devx_reg_mr(ctx, (MLX5_ASO_AGE_ACTIONS_PER_POOL / 8) *
269                                  sq_desc_n, &sq->mr, socket, pdn))
270                 return -1;
271         sq->uar_obj = mlx5_glue->devx_alloc_uar(ctx, 0);
272         if (!sq->uar_obj)
273                 goto error;
274         if (mlx5_aso_cq_create(ctx, &sq->cq, log_desc_n, socket,
275                                 mlx5_os_get_devx_uar_page_id(sq->uar_obj), eqn))
276                 goto error;
277         sq->log_desc_n = log_desc_n;
278         sq->umem_buf = mlx5_malloc(MLX5_MEM_RTE | MLX5_MEM_ZERO, wq_size +
279                                    sizeof(*sq->db_rec) * 2, 4096, socket);
280         if (!sq->umem_buf) {
281                 DRV_LOG(ERR, "Can't allocate wqe buffer.");
282                 return -ENOMEM;
283         }
284         sq->wqe_umem = mlx5_glue->devx_umem_reg(ctx,
285                                                 (void *)(uintptr_t)sq->umem_buf,
286                                                 wq_size +
287                                                 sizeof(*sq->db_rec) * 2,
288                                                 IBV_ACCESS_LOCAL_WRITE);
289         if (!sq->wqe_umem) {
290                 DRV_LOG(ERR, "Failed to register umem for SQ.");
291                 rte_errno = ENOMEM;
292                 goto error;
293         }
294         attr.state = MLX5_SQC_STATE_RST;
295         attr.tis_lst_sz = 0;
296         attr.tis_num = 0;
297         attr.user_index = 0xFFFF;
298         attr.cqn = sq->cq.cq->id;
299         wq_attr->uar_page = mlx5_os_get_devx_uar_page_id(sq->uar_obj);
300         wq_attr->pd = pdn;
301         wq_attr->wq_type = MLX5_WQ_TYPE_CYCLIC;
302         wq_attr->log_wq_pg_sz = rte_log2_u32(pgsize);
303         wq_attr->wq_umem_id = mlx5_os_get_umem_id(sq->wqe_umem);
304         wq_attr->wq_umem_offset = 0;
305         wq_attr->wq_umem_valid = 1;
306         wq_attr->log_wq_stride = 6;
307         wq_attr->log_wq_sz = rte_log2_u32(wq_size) - 6;
308         wq_attr->dbr_umem_id = wq_attr->wq_umem_id;
309         wq_attr->dbr_addr = wq_size;
310         wq_attr->dbr_umem_valid = 1;
311         sq->sq = mlx5_devx_cmd_create_sq(ctx, &attr);
312         if (!sq->sq) {
313                 DRV_LOG(ERR, "Can't create sq object.");
314                 rte_errno  = ENOMEM;
315                 goto error;
316         }
317         modify_attr.state = MLX5_SQC_STATE_RDY;
318         ret = mlx5_devx_cmd_modify_sq(sq->sq, &modify_attr);
319         if (ret) {
320                 DRV_LOG(ERR, "Can't change sq state to ready.");
321                 rte_errno  = ENOMEM;
322                 goto error;
323         }
324         sq->ci = 0;
325         sq->pi = 0;
326         sq->sqn = sq->sq->id;
327         sq->db_rec = RTE_PTR_ADD(sq->umem_buf, (uintptr_t)(wq_attr->dbr_addr));
328         sq->uar_addr = (volatile uint64_t *)((uint8_t *)sq->uar_obj->base_addr +
329                                                                          0x800);
330         mlx5_aso_init_sq(sq);
331         return 0;
332 error:
333         mlx5_aso_destroy_sq(sq);
334         return -1;
335 }
336
337 /**
338  * API to create and initialize Send Queue used for ASO access.
339  *
340  * @param[in] sh
341  *   Pointer to shared device context.
342  *
343  * @return
344  *   0 on success, a negative errno value otherwise and rte_errno is set.
345  */
346 int
347 mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh)
348 {
349         return mlx5_aso_sq_create(sh->ctx, &sh->aso_age_mng->aso_sq, 0, sh->pdn,
350                                   sh->eqn, MLX5_ASO_QUEUE_LOG_DESC);
351 }
352
353 /**
354  * API to destroy Send Queue used for ASO access.
355  *
356  * @param[in] sh
357  *   Pointer to shared device context.
358  */
359 void
360 mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh)
361 {
362         mlx5_aso_destroy_sq(&sh->aso_age_mng->aso_sq);
363 }
364
365 /**
366  * Write a burst of WQEs to ASO SQ.
367  *
368  * @param[in] mng
369  *   ASO management data, contains the SQ.
370  * @param[in] n
371  *   Index of the last valid pool.
372  *
373  * @return
374  *   Number of WQEs in burst.
375  */
376 static uint16_t
377 mlx5_aso_sq_enqueue_burst(struct mlx5_aso_age_mng *mng, uint16_t n)
378 {
379         volatile struct mlx5_aso_wqe *wqe;
380         struct mlx5_aso_sq *sq = &mng->aso_sq;
381         struct mlx5_aso_age_pool *pool;
382         uint16_t size = 1 << sq->log_desc_n;
383         uint16_t mask = size - 1;
384         uint16_t max;
385         uint16_t start_pi = sq->pi;
386
387         max = RTE_MIN(size - (uint16_t)(sq->pi - sq->ci), n - sq->next);
388         if (unlikely(!max))
389                 return 0;
390         sq->elts[start_pi & mask].burst_size = max;
391         do {
392                 wqe = &sq->wqes[sq->pi & mask];
393                 rte_prefetch0(&sq->wqes[(sq->pi + 1) & mask]);
394                 /* Fill next WQE. */
395                 rte_spinlock_lock(&mng->resize_sl);
396                 pool = mng->pools[sq->next];
397                 rte_spinlock_unlock(&mng->resize_sl);
398                 sq->elts[sq->pi & mask].pool = pool;
399                 wqe->general_cseg.misc =
400                                 rte_cpu_to_be_32(((struct mlx5_devx_obj *)
401                                                  (pool->flow_hit_aso_obj))->id);
402                 wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ONLY_FIRST_ERR <<
403                                                          MLX5_COMP_MODE_OFFSET);
404                 wqe->general_cseg.opcode = rte_cpu_to_be_32
405                                                 (MLX5_OPCODE_ACCESS_ASO |
406                                                  ASO_OP_MOD_FLOW_HIT << 24 |
407                                                  sq->pi << 9);
408                 sq->pi++;
409                 sq->next++;
410                 max--;
411         } while (max);
412         wqe->general_cseg.flags = RTE_BE32(MLX5_COMP_ALWAYS <<
413                                                          MLX5_COMP_MODE_OFFSET);
414         rte_io_wmb();
415         sq->db_rec[MLX5_SND_DBR] = rte_cpu_to_be_32(sq->pi << 1);
416         rte_wmb();
417         *sq->uar_addr = *(volatile uint64_t *)wqe; /* Assume 64 bit ARCH.*/
418         rte_wmb();
419         return sq->elts[start_pi & mask].burst_size;
420 }
421
422 /**
423  * Debug utility function. Dump contents of error CQE and WQE.
424  *
425  * @param[in] cqe
426  *   Error CQE to dump.
427  * @param[in] wqe
428  *   Error WQE to dump.
429  */
430 static void
431 mlx5_aso_dump_err_objs(volatile uint32_t *cqe, volatile uint32_t *wqe)
432 {
433         int i;
434
435         DRV_LOG(ERR, "Error cqe:");
436         for (i = 0; i < 16; i += 4)
437                 DRV_LOG(ERR, "%08X %08X %08X %08X", cqe[i], cqe[i + 1],
438                         cqe[i + 2], cqe[i + 3]);
439         DRV_LOG(ERR, "\nError wqe:");
440         for (i = 0; i < (int)sizeof(struct mlx5_aso_wqe) / 4; i += 4)
441                 DRV_LOG(ERR, "%08X %08X %08X %08X", wqe[i], wqe[i + 1],
442                         wqe[i + 2], wqe[i + 3]);
443 }
444
445 /**
446  * Handle case of error CQE.
447  *
448  * @param[in] sq
449  *   ASO SQ to use.
450  */
451 static void
452 mlx5_aso_cqe_err_handle(struct mlx5_aso_sq *sq)
453 {
454         struct mlx5_aso_cq *cq = &sq->cq;
455         uint32_t idx = cq->cq_ci & ((1 << cq->log_desc_n) - 1);
456         volatile struct mlx5_err_cqe *cqe =
457                                 (volatile struct mlx5_err_cqe *)&cq->cqes[idx];
458
459         cq->errors++;
460         idx = rte_be_to_cpu_16(cqe->wqe_counter) & (1u << sq->log_desc_n);
461         mlx5_aso_dump_err_objs((volatile uint32_t *)cqe,
462                                  (volatile uint32_t *)&sq->wqes[idx]);
463 }
464
465 /**
466  * Update ASO objects upon completion.
467  *
468  * @param[in] sh
469  *   Shared device context.
470  * @param[in] n
471  *   Number of completed ASO objects.
472  */
473 static void
474 mlx5_aso_age_action_update(struct mlx5_dev_ctx_shared *sh, uint16_t n)
475 {
476         struct mlx5_aso_age_mng *mng = sh->aso_age_mng;
477         struct mlx5_aso_sq *sq = &mng->aso_sq;
478         struct mlx5_age_info *age_info;
479         const uint16_t size = 1 << sq->log_desc_n;
480         const uint16_t mask = size - 1;
481         const uint64_t curr = MLX5_CURR_TIME_SEC;
482         uint16_t expected = AGE_CANDIDATE;
483         uint16_t i;
484
485         for (i = 0; i < n; ++i) {
486                 uint16_t idx = (sq->ci + i) & mask;
487                 struct mlx5_aso_age_pool *pool = sq->elts[idx].pool;
488                 uint64_t diff = curr - pool->time_of_last_age_check;
489                 uint64_t *addr = sq->mr.buf;
490                 int j;
491
492                 addr += idx * MLX5_ASO_AGE_ACTIONS_PER_POOL / 64;
493                 pool->time_of_last_age_check = curr;
494                 for (j = 0; j < MLX5_ASO_AGE_ACTIONS_PER_POOL; j++) {
495                         struct mlx5_aso_age_action *act = &pool->actions[j];
496                         struct mlx5_age_param *ap = &act->age_params;
497                         uint8_t byte;
498                         uint8_t offset;
499                         uint8_t *u8addr;
500                         uint8_t hit;
501
502                         if (__atomic_load_n(&ap->state, __ATOMIC_RELAXED) !=
503                                             AGE_CANDIDATE)
504                                 continue;
505                         byte = 63 - (j / 8);
506                         offset = j % 8;
507                         u8addr = (uint8_t *)addr;
508                         hit = (u8addr[byte] >> offset) & 0x1;
509                         if (hit) {
510                                 __atomic_store_n(&ap->sec_since_last_hit, 0,
511                                                  __ATOMIC_RELAXED);
512                         } else {
513                                 struct mlx5_priv *priv;
514
515                                 __atomic_fetch_add(&ap->sec_since_last_hit,
516                                                    diff, __ATOMIC_RELAXED);
517                                 /* If timeout passed add to aged-out list. */
518                                 if (ap->sec_since_last_hit <= ap->timeout)
519                                         continue;
520                                 priv =
521                                 rte_eth_devices[ap->port_id].data->dev_private;
522                                 age_info = GET_PORT_AGE_INFO(priv);
523                                 rte_spinlock_lock(&age_info->aged_sl);
524                                 if (__atomic_compare_exchange_n(&ap->state,
525                                                                 &expected,
526                                                                 AGE_TMOUT,
527                                                                 false,
528                                                                __ATOMIC_RELAXED,
529                                                             __ATOMIC_RELAXED)) {
530                                         LIST_INSERT_HEAD(&age_info->aged_aso,
531                                                          act, next);
532                                         MLX5_AGE_SET(age_info,
533                                                      MLX5_AGE_EVENT_NEW);
534                                 }
535                                 rte_spinlock_unlock(&age_info->aged_sl);
536                         }
537                 }
538         }
539         mlx5_age_event_prepare(sh);
540 }
541
542 /**
543  * Handle completions from WQEs sent to ASO SQ.
544  *
545  * @param[in] sh
546  *   Shared device context.
547  *
548  * @return
549  *   Number of CQEs handled.
550  */
551 static uint16_t
552 mlx5_aso_completion_handle(struct mlx5_dev_ctx_shared *sh)
553 {
554         struct mlx5_aso_age_mng *mng = sh->aso_age_mng;
555         struct mlx5_aso_sq *sq = &mng->aso_sq;
556         struct mlx5_aso_cq *cq = &sq->cq;
557         volatile struct mlx5_cqe *restrict cqe;
558         const unsigned int cq_size = 1 << cq->log_desc_n;
559         const unsigned int mask = cq_size - 1;
560         uint32_t idx;
561         uint32_t next_idx = cq->cq_ci & mask;
562         const uint16_t max = (uint16_t)(sq->pi - sq->ci);
563         uint16_t i = 0;
564         int ret;
565         if (unlikely(!max))
566                 return 0;
567         do {
568                 idx = next_idx;
569                 next_idx = (cq->cq_ci + 1) & mask;
570                 rte_prefetch0(&cq->cqes[next_idx]);
571                 cqe = &cq->cqes[idx];
572                 ret = check_cqe(cqe, cq_size, cq->cq_ci);
573                 /*
574                  * Be sure owner read is done before any other cookie field or
575                  * opaque field.
576                  */
577                 rte_io_rmb();
578                 if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
579                         if (likely(ret == MLX5_CQE_STATUS_HW_OWN))
580                                 break;
581                         mlx5_aso_cqe_err_handle(sq);
582                 } else {
583                         i += sq->elts[(sq->ci + i) & mask].burst_size;
584                 }
585                 cq->cq_ci++;
586         } while (1);
587         if (likely(i)) {
588                 mlx5_aso_age_action_update(sh, i);
589                 sq->ci += i;
590                 rte_io_wmb();
591                 cq->db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
592         }
593         return i;
594 }
595
596 /**
597  * Periodically read CQEs and send WQEs to ASO SQ.
598  *
599  * @param[in] arg
600  *   Shared device context containing the ASO SQ.
601  */
602 static void
603 mlx5_flow_aso_alarm(void *arg)
604 {
605         struct mlx5_dev_ctx_shared *sh = arg;
606         struct mlx5_aso_sq *sq = &sh->aso_age_mng->aso_sq;
607         uint32_t us = 100u;
608         uint16_t n;
609
610         rte_spinlock_lock(&sh->aso_age_mng->resize_sl);
611         n = sh->aso_age_mng->next;
612         rte_spinlock_unlock(&sh->aso_age_mng->resize_sl);
613         mlx5_aso_completion_handle(sh);
614         if (sq->next == n) {
615                 /* End of loop: wait 1 second. */
616                 us = US_PER_S;
617                 sq->next = 0;
618         }
619         mlx5_aso_sq_enqueue_burst(sh->aso_age_mng, n);
620         if (rte_eal_alarm_set(us, mlx5_flow_aso_alarm, sh))
621                 DRV_LOG(ERR, "Cannot reinitialize aso alarm.");
622 }
623
624 /**
625  * API to start ASO access using ASO SQ.
626  *
627  * @param[in] sh
628  *   Pointer to shared device context.
629  *
630  * @return
631  *   0 on success, a negative errno value otherwise and rte_errno is set.
632  */
633 int
634 mlx5_aso_queue_start(struct mlx5_dev_ctx_shared *sh)
635 {
636         if (rte_eal_alarm_set(US_PER_S, mlx5_flow_aso_alarm, sh)) {
637                 DRV_LOG(ERR, "Cannot reinitialize ASO age alarm.");
638                 return -rte_errno;
639         }
640         return 0;
641 }
642
643 /**
644  * API to stop ASO access using ASO SQ.
645  *
646  * @param[in] sh
647  *   Pointer to shared device context.
648  *
649  * @return
650  *   0 on success, a negative errno value otherwise and rte_errno is set.
651  */
652 int
653 mlx5_aso_queue_stop(struct mlx5_dev_ctx_shared *sh)
654 {
655         int retries = 1024;
656
657         if (!sh->aso_age_mng->aso_sq.sq)
658                 return -EINVAL;
659         rte_errno = 0;
660         while (--retries) {
661                 rte_eal_alarm_cancel(mlx5_flow_aso_alarm, sh);
662                 if (rte_errno != EINPROGRESS)
663                         break;
664                 rte_pause();
665         }
666         return -rte_errno;
667 }