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