net/mlx5: support ESP SPI match and RSS hash
[dpdk.git] / drivers / net / mlx5 / mlx5_flow_hw.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2022 NVIDIA Corporation & Affiliates
3  */
4
5 #include <rte_flow.h>
6
7 #include <mlx5_malloc.h>
8 #include "mlx5_defs.h"
9 #include "mlx5_flow.h"
10 #include "mlx5_rx.h"
11
12 #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
13
14 /* The maximum actions support in the flow. */
15 #define MLX5_HW_MAX_ACTS 16
16
17 /* Default push burst threshold. */
18 #define BURST_THR 32u
19
20 /* Default queue to flush the flows. */
21 #define MLX5_DEFAULT_FLUSH_QUEUE 0
22
23 const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops;
24
25 /* DR action flags with different table. */
26 static uint32_t mlx5_hw_act_flag[MLX5_HW_ACTION_FLAG_MAX]
27                                 [MLX5DR_TABLE_TYPE_MAX] = {
28         {
29                 MLX5DR_ACTION_FLAG_ROOT_RX,
30                 MLX5DR_ACTION_FLAG_ROOT_TX,
31                 MLX5DR_ACTION_FLAG_ROOT_FDB,
32         },
33         {
34                 MLX5DR_ACTION_FLAG_HWS_RX,
35                 MLX5DR_ACTION_FLAG_HWS_TX,
36                 MLX5DR_ACTION_FLAG_HWS_FDB,
37         },
38 };
39
40 /**
41  * Set rxq flag.
42  *
43  * @param[in] dev
44  *   Pointer to the rte_eth_dev structure.
45  * @param[in] enable
46  *   Flag to enable or not.
47  */
48 static void
49 flow_hw_rxq_flag_set(struct rte_eth_dev *dev, bool enable)
50 {
51         struct mlx5_priv *priv = dev->data->dev_private;
52         unsigned int i;
53
54         if ((!priv->mark_enabled && !enable) ||
55             (priv->mark_enabled && enable))
56                 return;
57         for (i = 0; i < priv->rxqs_n; ++i) {
58                 struct mlx5_rxq_ctrl *rxq_ctrl = mlx5_rxq_ctrl_get(dev, i);
59
60                 rxq_ctrl->rxq.mark = enable;
61         }
62         priv->mark_enabled = enable;
63 }
64
65 /**
66  * Generate the pattern item flags.
67  * Will be used for shared RSS action.
68  *
69  * @param[in] items
70  *   Pointer to the list of items.
71  *
72  * @return
73  *   Item flags.
74  */
75 static uint64_t
76 flow_hw_rss_item_flags_get(const struct rte_flow_item items[])
77 {
78         uint64_t item_flags = 0;
79         uint64_t last_item = 0;
80
81         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
82                 int tunnel = !!(item_flags & MLX5_FLOW_LAYER_TUNNEL);
83                 int item_type = items->type;
84
85                 switch (item_type) {
86                 case RTE_FLOW_ITEM_TYPE_IPV4:
87                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV4 :
88                                              MLX5_FLOW_LAYER_OUTER_L3_IPV4;
89                         break;
90                 case RTE_FLOW_ITEM_TYPE_IPV6:
91                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L3_IPV6 :
92                                              MLX5_FLOW_LAYER_OUTER_L3_IPV6;
93                         break;
94                 case RTE_FLOW_ITEM_TYPE_TCP:
95                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_TCP :
96                                              MLX5_FLOW_LAYER_OUTER_L4_TCP;
97                         break;
98                 case RTE_FLOW_ITEM_TYPE_UDP:
99                         last_item = tunnel ? MLX5_FLOW_LAYER_INNER_L4_UDP :
100                                              MLX5_FLOW_LAYER_OUTER_L4_UDP;
101                         break;
102                 case RTE_FLOW_ITEM_TYPE_GRE:
103                         last_item = MLX5_FLOW_LAYER_GRE;
104                         break;
105                 case RTE_FLOW_ITEM_TYPE_NVGRE:
106                         last_item = MLX5_FLOW_LAYER_GRE;
107                         break;
108                 case RTE_FLOW_ITEM_TYPE_VXLAN:
109                         last_item = MLX5_FLOW_LAYER_VXLAN;
110                         break;
111                 case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
112                         last_item = MLX5_FLOW_LAYER_VXLAN_GPE;
113                         break;
114                 case RTE_FLOW_ITEM_TYPE_GENEVE:
115                         last_item = MLX5_FLOW_LAYER_GENEVE;
116                         break;
117                 case RTE_FLOW_ITEM_TYPE_MPLS:
118                         last_item = MLX5_FLOW_LAYER_MPLS;
119                         break;
120                 case RTE_FLOW_ITEM_TYPE_GTP:
121                         last_item = MLX5_FLOW_LAYER_GTP;
122                         break;
123                 default:
124                         break;
125                 }
126                 item_flags |= last_item;
127         }
128         return item_flags;
129 }
130
131 /**
132  * Register destination table DR jump action.
133  *
134  * @param[in] dev
135  *   Pointer to the rte_eth_dev structure.
136  * @param[in] table_attr
137  *   Pointer to the flow attributes.
138  * @param[in] dest_group
139  *   The destination group ID.
140  * @param[out] error
141  *   Pointer to error structure.
142  *
143  * @return
144  *    Table on success, NULL otherwise and rte_errno is set.
145  */
146 static struct mlx5_hw_jump_action *
147 flow_hw_jump_action_register(struct rte_eth_dev *dev,
148                              const struct rte_flow_attr *attr,
149                              uint32_t dest_group,
150                              struct rte_flow_error *error)
151 {
152         struct mlx5_priv *priv = dev->data->dev_private;
153         struct rte_flow_attr jattr = *attr;
154         struct mlx5_flow_group *grp;
155         struct mlx5_flow_cb_ctx ctx = {
156                 .dev = dev,
157                 .error = error,
158                 .data = &jattr,
159         };
160         struct mlx5_list_entry *ge;
161
162         jattr.group = dest_group;
163         ge = mlx5_hlist_register(priv->sh->flow_tbls, dest_group, &ctx);
164         if (!ge)
165                 return NULL;
166         grp = container_of(ge, struct mlx5_flow_group, entry);
167         return &grp->jump;
168 }
169
170 /**
171  * Release jump action.
172  *
173  * @param[in] dev
174  *   Pointer to the rte_eth_dev structure.
175  * @param[in] jump
176  *   Pointer to the jump action.
177  */
178
179 static void
180 flow_hw_jump_release(struct rte_eth_dev *dev, struct mlx5_hw_jump_action *jump)
181 {
182         struct mlx5_priv *priv = dev->data->dev_private;
183         struct mlx5_flow_group *grp;
184
185         grp = container_of
186                 (jump, struct mlx5_flow_group, jump);
187         mlx5_hlist_unregister(priv->sh->flow_tbls, &grp->entry);
188 }
189
190 /**
191  * Register queue/RSS action.
192  *
193  * @param[in] dev
194  *   Pointer to the rte_eth_dev structure.
195  * @param[in] hws_flags
196  *   DR action flags.
197  * @param[in] action
198  *   rte flow action.
199  *
200  * @return
201  *    Table on success, NULL otherwise and rte_errno is set.
202  */
203 static inline struct mlx5_hrxq*
204 flow_hw_tir_action_register(struct rte_eth_dev *dev,
205                             uint32_t hws_flags,
206                             const struct rte_flow_action *action)
207 {
208         struct mlx5_flow_rss_desc rss_desc = {
209                 .hws_flags = hws_flags,
210         };
211         struct mlx5_hrxq *hrxq;
212
213         if (action->type == RTE_FLOW_ACTION_TYPE_QUEUE) {
214                 const struct rte_flow_action_queue *queue = action->conf;
215
216                 rss_desc.const_q = &queue->index;
217                 rss_desc.queue_num = 1;
218         } else {
219                 const struct rte_flow_action_rss *rss = action->conf;
220
221                 rss_desc.queue_num = rss->queue_num;
222                 rss_desc.const_q = rss->queue;
223                 memcpy(rss_desc.key,
224                        !rss->key ? rss_hash_default_key : rss->key,
225                        MLX5_RSS_HASH_KEY_LEN);
226                 rss_desc.key_len = MLX5_RSS_HASH_KEY_LEN;
227                 rss_desc.types = !rss->types ? RTE_ETH_RSS_IP : rss->types;
228                 flow_dv_hashfields_set(0, &rss_desc, &rss_desc.hash_fields);
229                 flow_dv_action_rss_l34_hash_adjust(rss->types,
230                                                    &rss_desc.hash_fields);
231                 if (rss->level > 1) {
232                         rss_desc.hash_fields |= IBV_RX_HASH_INNER;
233                         rss_desc.tunnel = 1;
234                 }
235         }
236         hrxq = mlx5_hrxq_get(dev, &rss_desc);
237         return hrxq;
238 }
239
240 /**
241  * Destroy DR actions created by action template.
242  *
243  * For DR actions created during table creation's action translate.
244  * Need to destroy the DR action when destroying the table.
245  *
246  * @param[in] dev
247  *   Pointer to the rte_eth_dev structure.
248  * @param[in] acts
249  *   Pointer to the template HW steering DR actions.
250  */
251 static void
252 __flow_hw_action_template_destroy(struct rte_eth_dev *dev,
253                                  struct mlx5_hw_actions *acts)
254 {
255         struct mlx5_priv *priv = dev->data->dev_private;
256
257         if (acts->jump) {
258                 struct mlx5_flow_group *grp;
259
260                 grp = container_of
261                         (acts->jump, struct mlx5_flow_group, jump);
262                 mlx5_hlist_unregister(priv->sh->flow_tbls, &grp->entry);
263                 acts->jump = NULL;
264         }
265 }
266
267 /**
268  * Append dynamic action to the dynamic action list.
269  *
270  * @param[in] priv
271  *   Pointer to the port private data structure.
272  * @param[in] acts
273  *   Pointer to the template HW steering DR actions.
274  * @param[in] type
275  *   Action type.
276  * @param[in] action_src
277  *   Offset of source rte flow action.
278  * @param[in] action_dst
279  *   Offset of destination DR action.
280  *
281  * @return
282  *    0 on success, negative value otherwise and rte_errno is set.
283  */
284 static __rte_always_inline struct mlx5_action_construct_data *
285 __flow_hw_act_data_alloc(struct mlx5_priv *priv,
286                          enum rte_flow_action_type type,
287                          uint16_t action_src,
288                          uint16_t action_dst)
289 {
290         struct mlx5_action_construct_data *act_data;
291         uint32_t idx = 0;
292
293         act_data = mlx5_ipool_zmalloc(priv->acts_ipool, &idx);
294         if (!act_data)
295                 return NULL;
296         act_data->idx = idx;
297         act_data->type = type;
298         act_data->action_src = action_src;
299         act_data->action_dst = action_dst;
300         return act_data;
301 }
302
303 /**
304  * Append dynamic action to the dynamic action list.
305  *
306  * @param[in] priv
307  *   Pointer to the port private data structure.
308  * @param[in] acts
309  *   Pointer to the template HW steering DR actions.
310  * @param[in] type
311  *   Action type.
312  * @param[in] action_src
313  *   Offset of source rte flow action.
314  * @param[in] action_dst
315  *   Offset of destination DR action.
316  *
317  * @return
318  *    0 on success, negative value otherwise and rte_errno is set.
319  */
320 static __rte_always_inline int
321 __flow_hw_act_data_general_append(struct mlx5_priv *priv,
322                                   struct mlx5_hw_actions *acts,
323                                   enum rte_flow_action_type type,
324                                   uint16_t action_src,
325                                   uint16_t action_dst)
326 {       struct mlx5_action_construct_data *act_data;
327
328         act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst);
329         if (!act_data)
330                 return -1;
331         LIST_INSERT_HEAD(&acts->act_list, act_data, next);
332         return 0;
333 }
334
335 /**
336  * Append dynamic encap action to the dynamic action list.
337  *
338  * @param[in] priv
339  *   Pointer to the port private data structure.
340  * @param[in] acts
341  *   Pointer to the template HW steering DR actions.
342  * @param[in] type
343  *   Action type.
344  * @param[in] action_src
345  *   Offset of source rte flow action.
346  * @param[in] action_dst
347  *   Offset of destination DR action.
348  * @param[in] encap_src
349  *   Offset of source encap raw data.
350  * @param[in] encap_dst
351  *   Offset of destination encap raw data.
352  * @param[in] len
353  *   Length of the data to be updated.
354  *
355  * @return
356  *    0 on success, negative value otherwise and rte_errno is set.
357  */
358 static __rte_always_inline int
359 __flow_hw_act_data_encap_append(struct mlx5_priv *priv,
360                                 struct mlx5_hw_actions *acts,
361                                 enum rte_flow_action_type type,
362                                 uint16_t action_src,
363                                 uint16_t action_dst,
364                                 uint16_t encap_src,
365                                 uint16_t encap_dst,
366                                 uint16_t len)
367 {       struct mlx5_action_construct_data *act_data;
368
369         act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst);
370         if (!act_data)
371                 return -1;
372         act_data->encap.src = encap_src;
373         act_data->encap.dst = encap_dst;
374         act_data->encap.len = len;
375         LIST_INSERT_HEAD(&acts->act_list, act_data, next);
376         return 0;
377 }
378
379 /**
380  * Append shared RSS action to the dynamic action list.
381  *
382  * @param[in] priv
383  *   Pointer to the port private data structure.
384  * @param[in] acts
385  *   Pointer to the template HW steering DR actions.
386  * @param[in] type
387  *   Action type.
388  * @param[in] action_src
389  *   Offset of source rte flow action.
390  * @param[in] action_dst
391  *   Offset of destination DR action.
392  * @param[in] idx
393  *   Shared RSS index.
394  * @param[in] rss
395  *   Pointer to the shared RSS info.
396  *
397  * @return
398  *    0 on success, negative value otherwise and rte_errno is set.
399  */
400 static __rte_always_inline int
401 __flow_hw_act_data_shared_rss_append(struct mlx5_priv *priv,
402                                      struct mlx5_hw_actions *acts,
403                                      enum rte_flow_action_type type,
404                                      uint16_t action_src,
405                                      uint16_t action_dst,
406                                      uint32_t idx,
407                                      struct mlx5_shared_action_rss *rss)
408 {       struct mlx5_action_construct_data *act_data;
409
410         act_data = __flow_hw_act_data_alloc(priv, type, action_src, action_dst);
411         if (!act_data)
412                 return -1;
413         act_data->shared_rss.level = rss->origin.level;
414         act_data->shared_rss.types = !rss->origin.types ? RTE_ETH_RSS_IP :
415                                      rss->origin.types;
416         act_data->shared_rss.idx = idx;
417         LIST_INSERT_HEAD(&acts->act_list, act_data, next);
418         return 0;
419 }
420
421 /**
422  * Translate shared indirect action.
423  *
424  * @param[in] dev
425  *   Pointer to the rte_eth_dev data structure.
426  * @param[in] action
427  *   Pointer to the shared indirect rte_flow action.
428  * @param[in] acts
429  *   Pointer to the template HW steering DR actions.
430  * @param[in] action_src
431  *   Offset of source rte flow action.
432  * @param[in] action_dst
433  *   Offset of destination DR action.
434  *
435  * @return
436  *    0 on success, negative value otherwise and rte_errno is set.
437  */
438 static __rte_always_inline int
439 flow_hw_shared_action_translate(struct rte_eth_dev *dev,
440                                 const struct rte_flow_action *action,
441                                 struct mlx5_hw_actions *acts,
442                                 uint16_t action_src,
443                                 uint16_t action_dst)
444 {
445         struct mlx5_priv *priv = dev->data->dev_private;
446         struct mlx5_shared_action_rss *shared_rss;
447         uint32_t act_idx = (uint32_t)(uintptr_t)action->conf;
448         uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
449         uint32_t idx = act_idx &
450                        ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
451
452         switch (type) {
453         case MLX5_INDIRECT_ACTION_TYPE_RSS:
454                 shared_rss = mlx5_ipool_get
455                   (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
456                 if (!shared_rss || __flow_hw_act_data_shared_rss_append
457                     (priv, acts,
458                     (enum rte_flow_action_type)MLX5_RTE_FLOW_ACTION_TYPE_RSS,
459                     action_src, action_dst, idx, shared_rss))
460                         return -1;
461                 break;
462         default:
463                 DRV_LOG(WARNING, "Unsupported shared action type:%d", type);
464                 break;
465         }
466         return 0;
467 }
468
469 /**
470  * Translate encap items to encapsulation list.
471  *
472  * @param[in] dev
473  *   Pointer to the rte_eth_dev data structure.
474  * @param[in] acts
475  *   Pointer to the template HW steering DR actions.
476  * @param[in] type
477  *   Action type.
478  * @param[in] action_src
479  *   Offset of source rte flow action.
480  * @param[in] action_dst
481  *   Offset of destination DR action.
482  * @param[in] items
483  *   Encap item pattern.
484  * @param[in] items_m
485  *   Encap item mask indicates which part are constant and dynamic.
486  *
487  * @return
488  *    0 on success, negative value otherwise and rte_errno is set.
489  */
490 static __rte_always_inline int
491 flow_hw_encap_item_translate(struct rte_eth_dev *dev,
492                              struct mlx5_hw_actions *acts,
493                              enum rte_flow_action_type type,
494                              uint16_t action_src,
495                              uint16_t action_dst,
496                              const struct rte_flow_item *items,
497                              const struct rte_flow_item *items_m)
498 {
499         struct mlx5_priv *priv = dev->data->dev_private;
500         size_t len, total_len = 0;
501         uint32_t i = 0;
502
503         for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++, items_m++, i++) {
504                 len = flow_dv_get_item_hdr_len(items->type);
505                 if ((!items_m->spec ||
506                     memcmp(items_m->spec, items->spec, len)) &&
507                     __flow_hw_act_data_encap_append(priv, acts, type,
508                                                     action_src, action_dst, i,
509                                                     total_len, len))
510                         return -1;
511                 total_len += len;
512         }
513         return 0;
514 }
515
516 /**
517  * Translate rte_flow actions to DR action.
518  *
519  * As the action template has already indicated the actions. Translate
520  * the rte_flow actions to DR action if possbile. So in flow create
521  * stage we will save cycles from handing the actions' organizing.
522  * For the actions with limited information, need to add these to a
523  * list.
524  *
525  * @param[in] dev
526  *   Pointer to the rte_eth_dev structure.
527  * @param[in] table_attr
528  *   Pointer to the table attributes.
529  * @param[in] item_templates
530  *   Item template array to be binded to the table.
531  * @param[in/out] acts
532  *   Pointer to the template HW steering DR actions.
533  * @param[in] at
534  *   Action template.
535  * @param[out] error
536  *   Pointer to error structure.
537  *
538  * @return
539  *    Table on success, NULL otherwise and rte_errno is set.
540  */
541 static int
542 flow_hw_actions_translate(struct rte_eth_dev *dev,
543                           const struct rte_flow_template_table_attr *table_attr,
544                           struct mlx5_hw_actions *acts,
545                           struct rte_flow_actions_template *at,
546                           struct rte_flow_error *error)
547 {
548         struct mlx5_priv *priv = dev->data->dev_private;
549         const struct rte_flow_attr *attr = &table_attr->flow_attr;
550         struct rte_flow_action *actions = at->actions;
551         struct rte_flow_action *action_start = actions;
552         struct rte_flow_action *masks = at->masks;
553         enum mlx5dr_action_reformat_type refmt_type = 0;
554         const struct rte_flow_action_raw_encap *raw_encap_data;
555         const struct rte_flow_item *enc_item = NULL, *enc_item_m = NULL;
556         uint16_t reformat_pos = MLX5_HW_MAX_ACTS, reformat_src = 0;
557         uint8_t *encap_data = NULL;
558         size_t data_size = 0;
559         bool actions_end = false;
560         uint32_t type, i;
561         int err;
562
563         if (attr->transfer)
564                 type = MLX5DR_TABLE_TYPE_FDB;
565         else if (attr->egress)
566                 type = MLX5DR_TABLE_TYPE_NIC_TX;
567         else
568                 type = MLX5DR_TABLE_TYPE_NIC_RX;
569         for (i = 0; !actions_end; actions++, masks++) {
570                 switch (actions->type) {
571                 case RTE_FLOW_ACTION_TYPE_INDIRECT:
572                         if (!attr->group) {
573                                 DRV_LOG(ERR, "Indirect action is not supported in root table.");
574                                 goto err;
575                         }
576                         if (actions->conf && masks->conf) {
577                                 if (flow_hw_shared_action_translate
578                                 (dev, actions, acts, actions - action_start, i))
579                                         goto err;
580                         } else if (__flow_hw_act_data_general_append
581                                         (priv, acts, actions->type,
582                                          actions - action_start, i)){
583                                 goto err;
584                         }
585                         i++;
586                         break;
587                 case RTE_FLOW_ACTION_TYPE_VOID:
588                         break;
589                 case RTE_FLOW_ACTION_TYPE_DROP:
590                         acts->rule_acts[i++].action =
591                                 priv->hw_drop[!!attr->group][type];
592                         break;
593                 case RTE_FLOW_ACTION_TYPE_MARK:
594                         acts->mark = true;
595                         if (masks->conf)
596                                 acts->rule_acts[i].tag.value =
597                                         mlx5_flow_mark_set
598                                         (((const struct rte_flow_action_mark *)
599                                         (masks->conf))->id);
600                         else if (__flow_hw_act_data_general_append(priv, acts,
601                                 actions->type, actions - action_start, i))
602                                 goto err;
603                         acts->rule_acts[i++].action =
604                                 priv->hw_tag[!!attr->group];
605                         flow_hw_rxq_flag_set(dev, true);
606                         break;
607                 case RTE_FLOW_ACTION_TYPE_JUMP:
608                         if (masks->conf) {
609                                 uint32_t jump_group =
610                                         ((const struct rte_flow_action_jump *)
611                                         actions->conf)->group;
612                                 acts->jump = flow_hw_jump_action_register
613                                                 (dev, attr, jump_group, error);
614                                 if (!acts->jump)
615                                         goto err;
616                                 acts->rule_acts[i].action = (!!attr->group) ?
617                                                 acts->jump->hws_action :
618                                                 acts->jump->root_action;
619                         } else if (__flow_hw_act_data_general_append
620                                         (priv, acts, actions->type,
621                                          actions - action_start, i)){
622                                 goto err;
623                         }
624                         i++;
625                         break;
626                 case RTE_FLOW_ACTION_TYPE_QUEUE:
627                         if (masks->conf) {
628                                 acts->tir = flow_hw_tir_action_register
629                                 (dev,
630                                  mlx5_hw_act_flag[!!attr->group][type],
631                                  actions);
632                                 if (!acts->tir)
633                                         goto err;
634                                 acts->rule_acts[i].action =
635                                         acts->tir->action;
636                         } else if (__flow_hw_act_data_general_append
637                                         (priv, acts, actions->type,
638                                          actions - action_start, i)) {
639                                 goto err;
640                         }
641                         i++;
642                         break;
643                 case RTE_FLOW_ACTION_TYPE_RSS:
644                         if (masks->conf) {
645                                 acts->tir = flow_hw_tir_action_register
646                                 (dev,
647                                  mlx5_hw_act_flag[!!attr->group][type],
648                                  actions);
649                                 if (!acts->tir)
650                                         goto err;
651                                 acts->rule_acts[i].action =
652                                         acts->tir->action;
653                         } else if (__flow_hw_act_data_general_append
654                                         (priv, acts, actions->type,
655                                          actions - action_start, i)) {
656                                 goto err;
657                         }
658                         i++;
659                         break;
660                 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
661                         MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS);
662                         enc_item = ((const struct rte_flow_action_vxlan_encap *)
663                                    actions->conf)->definition;
664                         enc_item_m =
665                                 ((const struct rte_flow_action_vxlan_encap *)
666                                  masks->conf)->definition;
667                         reformat_pos = i++;
668                         reformat_src = actions - action_start;
669                         refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2;
670                         break;
671                 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
672                         MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS);
673                         enc_item = ((const struct rte_flow_action_nvgre_encap *)
674                                    actions->conf)->definition;
675                         enc_item_m =
676                                 ((const struct rte_flow_action_nvgre_encap *)
677                                 actions->conf)->definition;
678                         reformat_pos = i++;
679                         reformat_src = actions - action_start;
680                         refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2;
681                         break;
682                 case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
683                 case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
684                         MLX5_ASSERT(reformat_pos == MLX5_HW_MAX_ACTS);
685                         reformat_pos = i++;
686                         refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2;
687                         break;
688                 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
689                         raw_encap_data =
690                                 (const struct rte_flow_action_raw_encap *)
691                                  actions->conf;
692                         encap_data = raw_encap_data->data;
693                         data_size = raw_encap_data->size;
694                         if (reformat_pos != MLX5_HW_MAX_ACTS) {
695                                 refmt_type = data_size <
696                                 MLX5_ENCAPSULATION_DECISION_SIZE ?
697                                 MLX5DR_ACTION_REFORMAT_TYPE_TNL_L3_TO_L2 :
698                                 MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L3;
699                         } else {
700                                 reformat_pos = i++;
701                                 refmt_type =
702                                 MLX5DR_ACTION_REFORMAT_TYPE_L2_TO_TNL_L2;
703                         }
704                         reformat_src = actions - action_start;
705                         break;
706                 case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
707                         reformat_pos = i++;
708                         refmt_type = MLX5DR_ACTION_REFORMAT_TYPE_TNL_L2_TO_L2;
709                         break;
710                 case RTE_FLOW_ACTION_TYPE_END:
711                         actions_end = true;
712                         break;
713                 default:
714                         break;
715                 }
716         }
717         if (reformat_pos != MLX5_HW_MAX_ACTS) {
718                 uint8_t buf[MLX5_ENCAP_MAX_LEN];
719
720                 if (enc_item) {
721                         MLX5_ASSERT(!encap_data);
722                         if (flow_dv_convert_encap_data
723                                 (enc_item, buf, &data_size, error) ||
724                             flow_hw_encap_item_translate
725                                 (dev, acts, (action_start + reformat_src)->type,
726                                  reformat_src, reformat_pos,
727                                  enc_item, enc_item_m))
728                                 goto err;
729                         encap_data = buf;
730                 } else if (encap_data && __flow_hw_act_data_encap_append
731                                 (priv, acts,
732                                  (action_start + reformat_src)->type,
733                                  reformat_src, reformat_pos, 0, 0, data_size)) {
734                         goto err;
735                 }
736                 acts->encap_decap = mlx5_malloc(MLX5_MEM_ZERO,
737                                     sizeof(*acts->encap_decap) + data_size,
738                                     0, SOCKET_ID_ANY);
739                 if (!acts->encap_decap)
740                         goto err;
741                 if (data_size) {
742                         acts->encap_decap->data_size = data_size;
743                         memcpy(acts->encap_decap->data, encap_data, data_size);
744                 }
745                 acts->encap_decap->action = mlx5dr_action_create_reformat
746                                 (priv->dr_ctx, refmt_type,
747                                  data_size, encap_data,
748                                  rte_log2_u32(table_attr->nb_flows),
749                                  mlx5_hw_act_flag[!!attr->group][type]);
750                 if (!acts->encap_decap->action)
751                         goto err;
752                 acts->rule_acts[reformat_pos].action =
753                                                 acts->encap_decap->action;
754                 acts->encap_decap_pos = reformat_pos;
755         }
756         acts->acts_num = i;
757         return 0;
758 err:
759         err = rte_errno;
760         __flow_hw_action_template_destroy(dev, acts);
761         return rte_flow_error_set(error, err,
762                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
763                                   "fail to create rte table");
764 }
765
766 /**
767  * Get shared indirect action.
768  *
769  * @param[in] dev
770  *   Pointer to the rte_eth_dev data structure.
771  * @param[in] act_data
772  *   Pointer to the recorded action construct data.
773  * @param[in] item_flags
774  *   The matcher itme_flags used for RSS lookup.
775  * @param[in] rule_act
776  *   Pointer to the shared action's destination rule DR action.
777  *
778  * @return
779  *    0 on success, negative value otherwise and rte_errno is set.
780  */
781 static __rte_always_inline int
782 flow_hw_shared_action_get(struct rte_eth_dev *dev,
783                           struct mlx5_action_construct_data *act_data,
784                           const uint64_t item_flags,
785                           struct mlx5dr_rule_action *rule_act)
786 {
787         struct mlx5_priv *priv = dev->data->dev_private;
788         struct mlx5_flow_rss_desc rss_desc = { 0 };
789         uint64_t hash_fields = 0;
790         uint32_t hrxq_idx = 0;
791         struct mlx5_hrxq *hrxq = NULL;
792         int act_type = act_data->type;
793
794         switch (act_type) {
795         case MLX5_RTE_FLOW_ACTION_TYPE_RSS:
796                 rss_desc.level = act_data->shared_rss.level;
797                 rss_desc.types = act_data->shared_rss.types;
798                 flow_dv_hashfields_set(item_flags, &rss_desc, &hash_fields);
799                 hrxq_idx = flow_dv_action_rss_hrxq_lookup
800                         (dev, act_data->shared_rss.idx, hash_fields);
801                 if (hrxq_idx)
802                         hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
803                                               hrxq_idx);
804                 if (hrxq) {
805                         rule_act->action = hrxq->action;
806                         return 0;
807                 }
808                 break;
809         default:
810                 DRV_LOG(WARNING, "Unsupported shared action type:%d",
811                         act_data->type);
812                 break;
813         }
814         return -1;
815 }
816
817 /**
818  * Construct shared indirect action.
819  *
820  * @param[in] dev
821  *   Pointer to the rte_eth_dev data structure.
822  * @param[in] action
823  *   Pointer to the shared indirect rte_flow action.
824  * @param[in] table
825  *   Pointer to the flow table.
826  * @param[in] it_idx
827  *   Item template index the action template refer to.
828  * @param[in] rule_act
829  *   Pointer to the shared action's destination rule DR action.
830  *
831  * @return
832  *    0 on success, negative value otherwise and rte_errno is set.
833  */
834 static __rte_always_inline int
835 flow_hw_shared_action_construct(struct rte_eth_dev *dev,
836                                 const struct rte_flow_action *action,
837                                 struct rte_flow_template_table *table,
838                                 const uint8_t it_idx,
839                                 struct mlx5dr_rule_action *rule_act)
840 {
841         struct mlx5_priv *priv = dev->data->dev_private;
842         struct mlx5_action_construct_data act_data;
843         struct mlx5_shared_action_rss *shared_rss;
844         uint32_t act_idx = (uint32_t)(uintptr_t)action->conf;
845         uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
846         uint32_t idx = act_idx &
847                        ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
848         uint64_t item_flags;
849
850         memset(&act_data, 0, sizeof(act_data));
851         switch (type) {
852         case MLX5_INDIRECT_ACTION_TYPE_RSS:
853                 act_data.type = MLX5_RTE_FLOW_ACTION_TYPE_RSS;
854                 shared_rss = mlx5_ipool_get
855                         (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS], idx);
856                 if (!shared_rss)
857                         return -1;
858                 act_data.shared_rss.idx = idx;
859                 act_data.shared_rss.level = shared_rss->origin.level;
860                 act_data.shared_rss.types = !shared_rss->origin.types ?
861                                             RTE_ETH_RSS_IP :
862                                             shared_rss->origin.types;
863                 item_flags = table->its[it_idx]->item_flags;
864                 if (flow_hw_shared_action_get
865                                 (dev, &act_data, item_flags, rule_act))
866                         return -1;
867                 break;
868         default:
869                 DRV_LOG(WARNING, "Unsupported shared action type:%d", type);
870                 break;
871         }
872         return 0;
873 }
874
875 /**
876  * Construct flow action array.
877  *
878  * For action template contains dynamic actions, these actions need to
879  * be updated according to the rte_flow action during flow creation.
880  *
881  * @param[in] dev
882  *   Pointer to the rte_eth_dev structure.
883  * @param[in] job
884  *   Pointer to job descriptor.
885  * @param[in] hw_acts
886  *   Pointer to translated actions from template.
887  * @param[in] it_idx
888  *   Item template index the action template refer to.
889  * @param[in] actions
890  *   Array of rte_flow action need to be checked.
891  * @param[in] rule_acts
892  *   Array of DR rule actions to be used during flow creation..
893  * @param[in] acts_num
894  *   Pointer to the real acts_num flow has.
895  *
896  * @return
897  *    0 on success, negative value otherwise and rte_errno is set.
898  */
899 static __rte_always_inline int
900 flow_hw_actions_construct(struct rte_eth_dev *dev,
901                           struct mlx5_hw_q_job *job,
902                           const struct mlx5_hw_actions *hw_acts,
903                           const uint8_t it_idx,
904                           const struct rte_flow_action actions[],
905                           struct mlx5dr_rule_action *rule_acts,
906                           uint32_t *acts_num)
907 {
908         struct rte_flow_template_table *table = job->flow->table;
909         struct mlx5_action_construct_data *act_data;
910         const struct rte_flow_action *action;
911         const struct rte_flow_action_raw_encap *raw_encap_data;
912         const struct rte_flow_item *enc_item = NULL;
913         uint8_t *buf = job->encap_data;
914         struct rte_flow_attr attr = {
915                         .ingress = 1,
916         };
917         uint32_t ft_flag;
918
919         memcpy(rule_acts, hw_acts->rule_acts,
920                sizeof(*rule_acts) * hw_acts->acts_num);
921         *acts_num = hw_acts->acts_num;
922         if (LIST_EMPTY(&hw_acts->act_list))
923                 return 0;
924         attr.group = table->grp->group_id;
925         ft_flag = mlx5_hw_act_flag[!!table->grp->group_id][table->type];
926         if (table->type == MLX5DR_TABLE_TYPE_FDB) {
927                 attr.transfer = 1;
928                 attr.ingress = 1;
929         } else if (table->type == MLX5DR_TABLE_TYPE_NIC_TX) {
930                 attr.egress = 1;
931                 attr.ingress = 0;
932         } else {
933                 attr.ingress = 1;
934         }
935         if (hw_acts->encap_decap && hw_acts->encap_decap->data_size)
936                 memcpy(buf, hw_acts->encap_decap->data,
937                        hw_acts->encap_decap->data_size);
938         LIST_FOREACH(act_data, &hw_acts->act_list, next) {
939                 uint32_t jump_group;
940                 uint32_t tag;
941                 uint64_t item_flags;
942                 struct mlx5_hw_jump_action *jump;
943                 struct mlx5_hrxq *hrxq;
944
945                 action = &actions[act_data->action_src];
946                 MLX5_ASSERT(action->type == RTE_FLOW_ACTION_TYPE_INDIRECT ||
947                             (int)action->type == act_data->type);
948                 switch (act_data->type) {
949                 case RTE_FLOW_ACTION_TYPE_INDIRECT:
950                         if (flow_hw_shared_action_construct
951                                         (dev, action, table, it_idx,
952                                          &rule_acts[act_data->action_dst]))
953                                 return -1;
954                         break;
955                 case RTE_FLOW_ACTION_TYPE_VOID:
956                         break;
957                 case RTE_FLOW_ACTION_TYPE_MARK:
958                         tag = mlx5_flow_mark_set
959                               (((const struct rte_flow_action_mark *)
960                               (action->conf))->id);
961                         rule_acts[act_data->action_dst].tag.value = tag;
962                         break;
963                 case RTE_FLOW_ACTION_TYPE_JUMP:
964                         jump_group = ((const struct rte_flow_action_jump *)
965                                                 action->conf)->group;
966                         jump = flow_hw_jump_action_register
967                                 (dev, &attr, jump_group, NULL);
968                         if (!jump)
969                                 return -1;
970                         rule_acts[act_data->action_dst].action =
971                         (!!attr.group) ? jump->hws_action : jump->root_action;
972                         job->flow->jump = jump;
973                         job->flow->fate_type = MLX5_FLOW_FATE_JUMP;
974                         break;
975                 case RTE_FLOW_ACTION_TYPE_RSS:
976                 case RTE_FLOW_ACTION_TYPE_QUEUE:
977                         hrxq = flow_hw_tir_action_register(dev,
978                                         ft_flag,
979                                         action);
980                         if (!hrxq)
981                                 return -1;
982                         rule_acts[act_data->action_dst].action = hrxq->action;
983                         job->flow->hrxq = hrxq;
984                         job->flow->fate_type = MLX5_FLOW_FATE_QUEUE;
985                         break;
986                 case MLX5_RTE_FLOW_ACTION_TYPE_RSS:
987                         item_flags = table->its[it_idx]->item_flags;
988                         if (flow_hw_shared_action_get
989                                 (dev, act_data, item_flags,
990                                  &rule_acts[act_data->action_dst]))
991                                 return -1;
992                         break;
993                 case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
994                         enc_item = ((const struct rte_flow_action_vxlan_encap *)
995                                    action->conf)->definition;
996                         rte_memcpy((void *)&buf[act_data->encap.dst],
997                                    enc_item[act_data->encap.src].spec,
998                                    act_data->encap.len);
999                         break;
1000                 case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
1001                         enc_item = ((const struct rte_flow_action_nvgre_encap *)
1002                                    action->conf)->definition;
1003                         rte_memcpy((void *)&buf[act_data->encap.dst],
1004                                    enc_item[act_data->encap.src].spec,
1005                                    act_data->encap.len);
1006                         break;
1007                 case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
1008                         raw_encap_data =
1009                                 (const struct rte_flow_action_raw_encap *)
1010                                  action->conf;
1011                         rte_memcpy((void *)&buf[act_data->encap.dst],
1012                                    raw_encap_data->data, act_data->encap.len);
1013                         MLX5_ASSERT(raw_encap_data->size ==
1014                                     act_data->encap.len);
1015                         break;
1016                 default:
1017                         break;
1018                 }
1019         }
1020         if (hw_acts->encap_decap) {
1021                 rule_acts[hw_acts->encap_decap_pos].reformat.offset =
1022                                 job->flow->idx - 1;
1023                 rule_acts[hw_acts->encap_decap_pos].reformat.data = buf;
1024         }
1025         return 0;
1026 }
1027
1028 /**
1029  * Enqueue HW steering flow creation.
1030  *
1031  * The flow will be applied to the HW only if the postpone bit is not set or
1032  * the extra push function is called.
1033  * The flow creation status should be checked from dequeue result.
1034  *
1035  * @param[in] dev
1036  *   Pointer to the rte_eth_dev structure.
1037  * @param[in] queue
1038  *   The queue to create the flow.
1039  * @param[in] attr
1040  *   Pointer to the flow operation attributes.
1041  * @param[in] items
1042  *   Items with flow spec value.
1043  * @param[in] pattern_template_index
1044  *   The item pattern flow follows from the table.
1045  * @param[in] actions
1046  *   Action with flow spec value.
1047  * @param[in] action_template_index
1048  *   The action pattern flow follows from the table.
1049  * @param[in] user_data
1050  *   Pointer to the user_data.
1051  * @param[out] error
1052  *   Pointer to error structure.
1053  *
1054  * @return
1055  *    Flow pointer on success, NULL otherwise and rte_errno is set.
1056  */
1057 static struct rte_flow *
1058 flow_hw_async_flow_create(struct rte_eth_dev *dev,
1059                           uint32_t queue,
1060                           const struct rte_flow_op_attr *attr,
1061                           struct rte_flow_template_table *table,
1062                           const struct rte_flow_item items[],
1063                           uint8_t pattern_template_index,
1064                           const struct rte_flow_action actions[],
1065                           uint8_t action_template_index,
1066                           void *user_data,
1067                           struct rte_flow_error *error)
1068 {
1069         struct mlx5_priv *priv = dev->data->dev_private;
1070         struct mlx5dr_rule_attr rule_attr = {
1071                 .queue_id = queue,
1072                 .user_data = user_data,
1073                 .burst = attr->postpone,
1074         };
1075         struct mlx5dr_rule_action rule_acts[MLX5_HW_MAX_ACTS];
1076         struct mlx5_hw_actions *hw_acts;
1077         struct rte_flow_hw *flow;
1078         struct mlx5_hw_q_job *job;
1079         uint32_t acts_num, flow_idx;
1080         int ret;
1081
1082         if (unlikely(!priv->hw_q[queue].job_idx)) {
1083                 rte_errno = ENOMEM;
1084                 goto error;
1085         }
1086         flow = mlx5_ipool_zmalloc(table->flow, &flow_idx);
1087         if (!flow)
1088                 goto error;
1089         /*
1090          * Set the table here in order to know the destination table
1091          * when free the flow afterwards.
1092          */
1093         flow->table = table;
1094         flow->idx = flow_idx;
1095         job = priv->hw_q[queue].job[--priv->hw_q[queue].job_idx];
1096         /*
1097          * Set the job type here in order to know if the flow memory
1098          * should be freed or not when get the result from dequeue.
1099          */
1100         job->type = MLX5_HW_Q_JOB_TYPE_CREATE;
1101         job->flow = flow;
1102         job->user_data = user_data;
1103         rule_attr.user_data = job;
1104         hw_acts = &table->ats[action_template_index].acts;
1105         /* Construct the flow action array based on the input actions.*/
1106         flow_hw_actions_construct(dev, job, hw_acts, pattern_template_index,
1107                                   actions, rule_acts, &acts_num);
1108         ret = mlx5dr_rule_create(table->matcher,
1109                                  pattern_template_index, items,
1110                                  rule_acts, acts_num,
1111                                  &rule_attr, &flow->rule);
1112         if (likely(!ret))
1113                 return (struct rte_flow *)flow;
1114         /* Flow created fail, return the descriptor and flow memory. */
1115         mlx5_ipool_free(table->flow, flow_idx);
1116         priv->hw_q[queue].job_idx++;
1117 error:
1118         rte_flow_error_set(error, rte_errno,
1119                            RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1120                            "fail to create rte flow");
1121         return NULL;
1122 }
1123
1124 /**
1125  * Enqueue HW steering flow destruction.
1126  *
1127  * The flow will be applied to the HW only if the postpone bit is not set or
1128  * the extra push function is called.
1129  * The flow destruction status should be checked from dequeue result.
1130  *
1131  * @param[in] dev
1132  *   Pointer to the rte_eth_dev structure.
1133  * @param[in] queue
1134  *   The queue to destroy the flow.
1135  * @param[in] attr
1136  *   Pointer to the flow operation attributes.
1137  * @param[in] flow
1138  *   Pointer to the flow to be destroyed.
1139  * @param[in] user_data
1140  *   Pointer to the user_data.
1141  * @param[out] error
1142  *   Pointer to error structure.
1143  *
1144  * @return
1145  *    0 on success, negative value otherwise and rte_errno is set.
1146  */
1147 static int
1148 flow_hw_async_flow_destroy(struct rte_eth_dev *dev,
1149                            uint32_t queue,
1150                            const struct rte_flow_op_attr *attr,
1151                            struct rte_flow *flow,
1152                            void *user_data,
1153                            struct rte_flow_error *error)
1154 {
1155         struct mlx5_priv *priv = dev->data->dev_private;
1156         struct mlx5dr_rule_attr rule_attr = {
1157                 .queue_id = queue,
1158                 .user_data = user_data,
1159                 .burst = attr->postpone,
1160         };
1161         struct rte_flow_hw *fh = (struct rte_flow_hw *)flow;
1162         struct mlx5_hw_q_job *job;
1163         int ret;
1164
1165         if (unlikely(!priv->hw_q[queue].job_idx)) {
1166                 rte_errno = ENOMEM;
1167                 goto error;
1168         }
1169         job = priv->hw_q[queue].job[--priv->hw_q[queue].job_idx];
1170         job->type = MLX5_HW_Q_JOB_TYPE_DESTROY;
1171         job->user_data = user_data;
1172         job->flow = fh;
1173         rule_attr.user_data = job;
1174         ret = mlx5dr_rule_destroy(&fh->rule, &rule_attr);
1175         if (likely(!ret))
1176                 return 0;
1177         priv->hw_q[queue].job_idx++;
1178 error:
1179         return rte_flow_error_set(error, rte_errno,
1180                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1181                         "fail to create rte flow");
1182 }
1183
1184 /**
1185  * Pull the enqueued flows.
1186  *
1187  * For flows enqueued from creation/destruction, the status should be
1188  * checked from the dequeue result.
1189  *
1190  * @param[in] dev
1191  *   Pointer to the rte_eth_dev structure.
1192  * @param[in] queue
1193  *   The queue to pull the result.
1194  * @param[in/out] res
1195  *   Array to save the results.
1196  * @param[in] n_res
1197  *   Available result with the array.
1198  * @param[out] error
1199  *   Pointer to error structure.
1200  *
1201  * @return
1202  *    Result number on success, negative value otherwise and rte_errno is set.
1203  */
1204 static int
1205 flow_hw_pull(struct rte_eth_dev *dev,
1206              uint32_t queue,
1207              struct rte_flow_op_result res[],
1208              uint16_t n_res,
1209              struct rte_flow_error *error)
1210 {
1211         struct mlx5_priv *priv = dev->data->dev_private;
1212         struct mlx5_hw_q_job *job;
1213         int ret, i;
1214
1215         ret = mlx5dr_send_queue_poll(priv->dr_ctx, queue, res, n_res);
1216         if (ret < 0)
1217                 return rte_flow_error_set(error, rte_errno,
1218                                 RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1219                                 "fail to query flow queue");
1220         for (i = 0; i <  ret; i++) {
1221                 job = (struct mlx5_hw_q_job *)res[i].user_data;
1222                 /* Restore user data. */
1223                 res[i].user_data = job->user_data;
1224                 if (job->type == MLX5_HW_Q_JOB_TYPE_DESTROY) {
1225                         if (job->flow->fate_type == MLX5_FLOW_FATE_JUMP)
1226                                 flow_hw_jump_release(dev, job->flow->jump);
1227                         else if (job->flow->fate_type == MLX5_FLOW_FATE_QUEUE)
1228                                 mlx5_hrxq_obj_release(dev, job->flow->hrxq);
1229                         mlx5_ipool_free(job->flow->table->flow, job->flow->idx);
1230                 }
1231                 priv->hw_q[queue].job[priv->hw_q[queue].job_idx++] = job;
1232         }
1233         return ret;
1234 }
1235
1236 /**
1237  * Push the enqueued flows to HW.
1238  *
1239  * Force apply all the enqueued flows to the HW.
1240  *
1241  * @param[in] dev
1242  *   Pointer to the rte_eth_dev structure.
1243  * @param[in] queue
1244  *   The queue to push the flow.
1245  * @param[out] error
1246  *   Pointer to error structure.
1247  *
1248  * @return
1249  *    0 on success, negative value otherwise and rte_errno is set.
1250  */
1251 static int
1252 flow_hw_push(struct rte_eth_dev *dev,
1253              uint32_t queue,
1254              struct rte_flow_error *error)
1255 {
1256         struct mlx5_priv *priv = dev->data->dev_private;
1257         int ret;
1258
1259         ret = mlx5dr_send_queue_action(priv->dr_ctx, queue,
1260                                        MLX5DR_SEND_QUEUE_ACTION_DRAIN);
1261         if (ret) {
1262                 rte_flow_error_set(error, rte_errno,
1263                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1264                                    "fail to push flows");
1265                 return ret;
1266         }
1267         return 0;
1268 }
1269
1270 /**
1271  * Drain the enqueued flows' completion.
1272  *
1273  * @param[in] dev
1274  *   Pointer to the rte_eth_dev structure.
1275  * @param[in] queue
1276  *   The queue to pull the flow.
1277  * @param[in] pending_rules
1278  *   The pending flow number.
1279  * @param[out] error
1280  *   Pointer to error structure.
1281  *
1282  * @return
1283  *    0 on success, negative value otherwise and rte_errno is set.
1284  */
1285 static int
1286 __flow_hw_pull_comp(struct rte_eth_dev *dev,
1287                     uint32_t queue,
1288                     uint32_t pending_rules,
1289                     struct rte_flow_error *error)
1290 {
1291         struct rte_flow_op_result comp[BURST_THR];
1292         int ret, i, empty_loop = 0;
1293
1294         flow_hw_push(dev, queue, error);
1295         while (pending_rules) {
1296                 ret = flow_hw_pull(dev, queue, comp, BURST_THR, error);
1297                 if (ret < 0)
1298                         return -1;
1299                 if (!ret) {
1300                         rte_delay_us_sleep(20000);
1301                         if (++empty_loop > 5) {
1302                                 DRV_LOG(WARNING, "No available dequeue, quit.");
1303                                 break;
1304                         }
1305                         continue;
1306                 }
1307                 for (i = 0; i < ret; i++) {
1308                         if (comp[i].status == RTE_FLOW_OP_ERROR)
1309                                 DRV_LOG(WARNING, "Flow flush get error CQE.");
1310                 }
1311                 if ((uint32_t)ret > pending_rules) {
1312                         DRV_LOG(WARNING, "Flow flush get extra CQE.");
1313                         return rte_flow_error_set(error, ERANGE,
1314                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1315                                         "get extra CQE");
1316                 }
1317                 pending_rules -= ret;
1318                 empty_loop = 0;
1319         }
1320         return 0;
1321 }
1322
1323 /**
1324  * Flush created flows.
1325  *
1326  * @param[in] dev
1327  *   Pointer to the rte_eth_dev structure.
1328  * @param[out] error
1329  *   Pointer to error structure.
1330  *
1331  * @return
1332  *    0 on success, negative value otherwise and rte_errno is set.
1333  */
1334 int
1335 flow_hw_q_flow_flush(struct rte_eth_dev *dev,
1336                      struct rte_flow_error *error)
1337 {
1338         struct mlx5_priv *priv = dev->data->dev_private;
1339         struct mlx5_hw_q *hw_q;
1340         struct rte_flow_template_table *tbl;
1341         struct rte_flow_hw *flow;
1342         struct rte_flow_op_attr attr = {
1343                 .postpone = 0,
1344         };
1345         uint32_t pending_rules = 0;
1346         uint32_t queue;
1347         uint32_t fidx;
1348
1349         /*
1350          * Ensure to push and dequeue all the enqueued flow
1351          * creation/destruction jobs in case user forgot to
1352          * dequeue. Or the enqueued created flows will be
1353          * leaked. The forgotten dequeues would also cause
1354          * flow flush get extra CQEs as expected and pending_rules
1355          * be minus value.
1356          */
1357         for (queue = 0; queue < priv->nb_queue; queue++) {
1358                 hw_q = &priv->hw_q[queue];
1359                 if (__flow_hw_pull_comp(dev, queue, hw_q->size - hw_q->job_idx,
1360                                         error))
1361                         return -1;
1362         }
1363         /* Flush flow per-table from MLX5_DEFAULT_FLUSH_QUEUE. */
1364         hw_q = &priv->hw_q[MLX5_DEFAULT_FLUSH_QUEUE];
1365         LIST_FOREACH(tbl, &priv->flow_hw_tbl, next) {
1366                 MLX5_IPOOL_FOREACH(tbl->flow, fidx, flow) {
1367                         if (flow_hw_async_flow_destroy(dev,
1368                                                 MLX5_DEFAULT_FLUSH_QUEUE,
1369                                                 &attr,
1370                                                 (struct rte_flow *)flow,
1371                                                 NULL,
1372                                                 error))
1373                                 return -1;
1374                         pending_rules++;
1375                         /* Drain completion with queue size. */
1376                         if (pending_rules >= hw_q->size) {
1377                                 if (__flow_hw_pull_comp(dev,
1378                                                 MLX5_DEFAULT_FLUSH_QUEUE,
1379                                                 pending_rules, error))
1380                                         return -1;
1381                                 pending_rules = 0;
1382                         }
1383                 }
1384         }
1385         /* Drain left completion. */
1386         if (pending_rules &&
1387             __flow_hw_pull_comp(dev, MLX5_DEFAULT_FLUSH_QUEUE, pending_rules,
1388                                 error))
1389                 return -1;
1390         return 0;
1391 }
1392
1393 /**
1394  * Create flow table.
1395  *
1396  * The input item and action templates will be binded to the table.
1397  * Flow memory will also be allocated. Matcher will be created based
1398  * on the item template. Action will be translated to the dedicated
1399  * DR action if possible.
1400  *
1401  * @param[in] dev
1402  *   Pointer to the rte_eth_dev structure.
1403  * @param[in] attr
1404  *   Pointer to the table attributes.
1405  * @param[in] item_templates
1406  *   Item template array to be binded to the table.
1407  * @param[in] nb_item_templates
1408  *   Number of item template.
1409  * @param[in] action_templates
1410  *   Action template array to be binded to the table.
1411  * @param[in] nb_action_templates
1412  *   Number of action template.
1413  * @param[out] error
1414  *   Pointer to error structure.
1415  *
1416  * @return
1417  *    Table on success, NULL otherwise and rte_errno is set.
1418  */
1419 static struct rte_flow_template_table *
1420 flow_hw_table_create(struct rte_eth_dev *dev,
1421                      const struct rte_flow_template_table_attr *attr,
1422                      struct rte_flow_pattern_template *item_templates[],
1423                      uint8_t nb_item_templates,
1424                      struct rte_flow_actions_template *action_templates[],
1425                      uint8_t nb_action_templates,
1426                      struct rte_flow_error *error)
1427 {
1428         struct mlx5_priv *priv = dev->data->dev_private;
1429         struct mlx5dr_matcher_attr matcher_attr = {0};
1430         struct rte_flow_template_table *tbl = NULL;
1431         struct mlx5_flow_group *grp;
1432         struct mlx5dr_match_template *mt[MLX5_HW_TBL_MAX_ITEM_TEMPLATE];
1433         struct rte_flow_attr flow_attr = attr->flow_attr;
1434         struct mlx5_flow_cb_ctx ctx = {
1435                 .dev = dev,
1436                 .error = error,
1437                 .data = &flow_attr,
1438         };
1439         struct mlx5_indexed_pool_config cfg = {
1440                 .size = sizeof(struct rte_flow_hw),
1441                 .trunk_size = 1 << 12,
1442                 .per_core_cache = 1 << 13,
1443                 .need_lock = 1,
1444                 .release_mem_en = !!priv->sh->config.reclaim_mode,
1445                 .malloc = mlx5_malloc,
1446                 .free = mlx5_free,
1447                 .type = "mlx5_hw_table_flow",
1448         };
1449         struct mlx5_list_entry *ge;
1450         uint32_t i, max_tpl = MLX5_HW_TBL_MAX_ITEM_TEMPLATE;
1451         uint32_t nb_flows = rte_align32pow2(attr->nb_flows);
1452         int err;
1453
1454         /* HWS layer accepts only 1 item template with root table. */
1455         if (!attr->flow_attr.group)
1456                 max_tpl = 1;
1457         cfg.max_idx = nb_flows;
1458         /* For table has very limited flows, disable cache. */
1459         if (nb_flows < cfg.trunk_size) {
1460                 cfg.per_core_cache = 0;
1461                 cfg.trunk_size = nb_flows;
1462         }
1463         /* Check if we requires too many templates. */
1464         if (nb_item_templates > max_tpl ||
1465             nb_action_templates > MLX5_HW_TBL_MAX_ACTION_TEMPLATE) {
1466                 rte_errno = EINVAL;
1467                 goto error;
1468         }
1469         /* Allocate the table memory. */
1470         tbl = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*tbl), 0, rte_socket_id());
1471         if (!tbl)
1472                 goto error;
1473         /* Allocate flow indexed pool. */
1474         tbl->flow = mlx5_ipool_create(&cfg);
1475         if (!tbl->flow)
1476                 goto error;
1477         /* Register the flow group. */
1478         ge = mlx5_hlist_register(priv->sh->groups, attr->flow_attr.group, &ctx);
1479         if (!ge)
1480                 goto error;
1481         grp = container_of(ge, struct mlx5_flow_group, entry);
1482         tbl->grp = grp;
1483         /* Prepare matcher information. */
1484         matcher_attr.priority = attr->flow_attr.priority;
1485         matcher_attr.mode = MLX5DR_MATCHER_RESOURCE_MODE_RULE;
1486         matcher_attr.rule.num_log = rte_log2_u32(nb_flows);
1487         /* Build the item template. */
1488         for (i = 0; i < nb_item_templates; i++) {
1489                 uint32_t ret;
1490
1491                 ret = __atomic_add_fetch(&item_templates[i]->refcnt, 1,
1492                                          __ATOMIC_RELAXED);
1493                 if (ret <= 1) {
1494                         rte_errno = EINVAL;
1495                         goto it_error;
1496                 }
1497                 mt[i] = item_templates[i]->mt;
1498                 tbl->its[i] = item_templates[i];
1499         }
1500         tbl->matcher = mlx5dr_matcher_create
1501                 (tbl->grp->tbl, mt, nb_item_templates, &matcher_attr);
1502         if (!tbl->matcher)
1503                 goto it_error;
1504         tbl->nb_item_templates = nb_item_templates;
1505         /* Build the action template. */
1506         for (i = 0; i < nb_action_templates; i++) {
1507                 uint32_t ret;
1508
1509                 ret = __atomic_add_fetch(&action_templates[i]->refcnt, 1,
1510                                          __ATOMIC_RELAXED);
1511                 if (ret <= 1) {
1512                         rte_errno = EINVAL;
1513                         goto at_error;
1514                 }
1515                 LIST_INIT(&tbl->ats[i].acts.act_list);
1516                 err = flow_hw_actions_translate(dev, attr,
1517                                                 &tbl->ats[i].acts,
1518                                                 action_templates[i], error);
1519                 if (err) {
1520                         i++;
1521                         goto at_error;
1522                 }
1523                 tbl->ats[i].action_template = action_templates[i];
1524         }
1525         tbl->nb_action_templates = nb_action_templates;
1526         tbl->type = attr->flow_attr.transfer ? MLX5DR_TABLE_TYPE_FDB :
1527                     (attr->flow_attr.egress ? MLX5DR_TABLE_TYPE_NIC_TX :
1528                     MLX5DR_TABLE_TYPE_NIC_RX);
1529         LIST_INSERT_HEAD(&priv->flow_hw_tbl, tbl, next);
1530         return tbl;
1531 at_error:
1532         while (i--) {
1533                 __flow_hw_action_template_destroy(dev, &tbl->ats[i].acts);
1534                 __atomic_sub_fetch(&action_templates[i]->refcnt,
1535                                    1, __ATOMIC_RELAXED);
1536         }
1537         i = nb_item_templates;
1538 it_error:
1539         while (i--)
1540                 __atomic_sub_fetch(&item_templates[i]->refcnt,
1541                                    1, __ATOMIC_RELAXED);
1542         mlx5dr_matcher_destroy(tbl->matcher);
1543 error:
1544         err = rte_errno;
1545         if (tbl) {
1546                 if (tbl->grp)
1547                         mlx5_hlist_unregister(priv->sh->groups,
1548                                               &tbl->grp->entry);
1549                 if (tbl->flow)
1550                         mlx5_ipool_destroy(tbl->flow);
1551                 mlx5_free(tbl);
1552         }
1553         rte_flow_error_set(error, err,
1554                           RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1555                           "fail to create rte table");
1556         return NULL;
1557 }
1558
1559 /**
1560  * Destroy flow table.
1561  *
1562  * @param[in] dev
1563  *   Pointer to the rte_eth_dev structure.
1564  * @param[in] table
1565  *   Pointer to the table to be destroyed.
1566  * @param[out] error
1567  *   Pointer to error structure.
1568  *
1569  * @return
1570  *   0 on success, a negative errno value otherwise and rte_errno is set.
1571  */
1572 static int
1573 flow_hw_table_destroy(struct rte_eth_dev *dev,
1574                       struct rte_flow_template_table *table,
1575                       struct rte_flow_error *error)
1576 {
1577         struct mlx5_priv *priv = dev->data->dev_private;
1578         int i;
1579
1580         if (table->refcnt) {
1581                 DRV_LOG(WARNING, "Table %p is still in using.", (void *)table);
1582                 return rte_flow_error_set(error, EBUSY,
1583                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1584                                    NULL,
1585                                    "table in using");
1586         }
1587         LIST_REMOVE(table, next);
1588         for (i = 0; i < table->nb_item_templates; i++)
1589                 __atomic_sub_fetch(&table->its[i]->refcnt,
1590                                    1, __ATOMIC_RELAXED);
1591         for (i = 0; i < table->nb_action_templates; i++) {
1592                 if (table->ats[i].acts.mark)
1593                         flow_hw_rxq_flag_set(dev, false);
1594                 __flow_hw_action_template_destroy(dev, &table->ats[i].acts);
1595                 __atomic_sub_fetch(&table->ats[i].action_template->refcnt,
1596                                    1, __ATOMIC_RELAXED);
1597         }
1598         mlx5dr_matcher_destroy(table->matcher);
1599         mlx5_hlist_unregister(priv->sh->groups, &table->grp->entry);
1600         mlx5_ipool_destroy(table->flow);
1601         mlx5_free(table);
1602         return 0;
1603 }
1604
1605 /**
1606  * Create flow action template.
1607  *
1608  * @param[in] dev
1609  *   Pointer to the rte_eth_dev structure.
1610  * @param[in] attr
1611  *   Pointer to the action template attributes.
1612  * @param[in] actions
1613  *   Associated actions (list terminated by the END action).
1614  * @param[in] masks
1615  *   List of actions that marks which of the action's member is constant.
1616  * @param[out] error
1617  *   Pointer to error structure.
1618  *
1619  * @return
1620  *   Action template pointer on success, NULL otherwise and rte_errno is set.
1621  */
1622 static struct rte_flow_actions_template *
1623 flow_hw_actions_template_create(struct rte_eth_dev *dev,
1624                         const struct rte_flow_actions_template_attr *attr,
1625                         const struct rte_flow_action actions[],
1626                         const struct rte_flow_action masks[],
1627                         struct rte_flow_error *error)
1628 {
1629         struct mlx5_priv *priv = dev->data->dev_private;
1630         int len, act_len, mask_len, i;
1631         struct rte_flow_actions_template *at;
1632
1633         act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS,
1634                                 NULL, 0, actions, error);
1635         if (act_len <= 0)
1636                 return NULL;
1637         len = RTE_ALIGN(act_len, 16);
1638         mask_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS,
1639                                  NULL, 0, masks, error);
1640         if (mask_len <= 0)
1641                 return NULL;
1642         len += RTE_ALIGN(mask_len, 16);
1643         at = mlx5_malloc(MLX5_MEM_ZERO, len + sizeof(*at), 64, rte_socket_id());
1644         if (!at) {
1645                 rte_flow_error_set(error, ENOMEM,
1646                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1647                                    NULL,
1648                                    "cannot allocate action template");
1649                 return NULL;
1650         }
1651         at->attr = *attr;
1652         at->actions = (struct rte_flow_action *)(at + 1);
1653         act_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, at->actions, len,
1654                                 actions, error);
1655         if (act_len <= 0)
1656                 goto error;
1657         at->masks = (struct rte_flow_action *)
1658                     (((uint8_t *)at->actions) + act_len);
1659         mask_len = rte_flow_conv(RTE_FLOW_CONV_OP_ACTIONS, at->masks,
1660                                  len - act_len, masks, error);
1661         if (mask_len <= 0)
1662                 goto error;
1663         /*
1664          * mlx5 PMD hacks indirect action index directly to the action conf.
1665          * The rte_flow_conv() function copies the content from conf pointer.
1666          * Need to restore the indirect action index from action conf here.
1667          */
1668         for (i = 0; actions->type != RTE_FLOW_ACTION_TYPE_END;
1669              actions++, masks++, i++) {
1670                 if (actions->type == RTE_FLOW_ACTION_TYPE_INDIRECT) {
1671                         at->actions[i].conf = actions->conf;
1672                         at->masks[i].conf = masks->conf;
1673                 }
1674         }
1675         __atomic_fetch_add(&at->refcnt, 1, __ATOMIC_RELAXED);
1676         LIST_INSERT_HEAD(&priv->flow_hw_at, at, next);
1677         return at;
1678 error:
1679         mlx5_free(at);
1680         return NULL;
1681 }
1682
1683 /**
1684  * Destroy flow action template.
1685  *
1686  * @param[in] dev
1687  *   Pointer to the rte_eth_dev structure.
1688  * @param[in] template
1689  *   Pointer to the action template to be destroyed.
1690  * @param[out] error
1691  *   Pointer to error structure.
1692  *
1693  * @return
1694  *   0 on success, a negative errno value otherwise and rte_errno is set.
1695  */
1696 static int
1697 flow_hw_actions_template_destroy(struct rte_eth_dev *dev __rte_unused,
1698                                  struct rte_flow_actions_template *template,
1699                                  struct rte_flow_error *error __rte_unused)
1700 {
1701         if (__atomic_load_n(&template->refcnt, __ATOMIC_RELAXED) > 1) {
1702                 DRV_LOG(WARNING, "Action template %p is still in use.",
1703                         (void *)template);
1704                 return rte_flow_error_set(error, EBUSY,
1705                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1706                                    NULL,
1707                                    "action template in using");
1708         }
1709         LIST_REMOVE(template, next);
1710         mlx5_free(template);
1711         return 0;
1712 }
1713
1714 /**
1715  * Create flow item template.
1716  *
1717  * @param[in] dev
1718  *   Pointer to the rte_eth_dev structure.
1719  * @param[in] attr
1720  *   Pointer to the item template attributes.
1721  * @param[in] items
1722  *   The template item pattern.
1723  * @param[out] error
1724  *   Pointer to error structure.
1725  *
1726  * @return
1727  *  Item template pointer on success, NULL otherwise and rte_errno is set.
1728  */
1729 static struct rte_flow_pattern_template *
1730 flow_hw_pattern_template_create(struct rte_eth_dev *dev,
1731                              const struct rte_flow_pattern_template_attr *attr,
1732                              const struct rte_flow_item items[],
1733                              struct rte_flow_error *error)
1734 {
1735         struct mlx5_priv *priv = dev->data->dev_private;
1736         struct rte_flow_pattern_template *it;
1737
1738         it = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*it), 0, rte_socket_id());
1739         if (!it) {
1740                 rte_flow_error_set(error, ENOMEM,
1741                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1742                                    NULL,
1743                                    "cannot allocate item template");
1744                 return NULL;
1745         }
1746         it->attr = *attr;
1747         it->mt = mlx5dr_match_template_create(items, attr->relaxed_matching);
1748         if (!it->mt) {
1749                 mlx5_free(it);
1750                 rte_flow_error_set(error, rte_errno,
1751                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1752                                    NULL,
1753                                    "cannot create match template");
1754                 return NULL;
1755         }
1756         it->item_flags = flow_hw_rss_item_flags_get(items);
1757         __atomic_fetch_add(&it->refcnt, 1, __ATOMIC_RELAXED);
1758         LIST_INSERT_HEAD(&priv->flow_hw_itt, it, next);
1759         return it;
1760 }
1761
1762 /**
1763  * Destroy flow item template.
1764  *
1765  * @param[in] dev
1766  *   Pointer to the rte_eth_dev structure.
1767  * @param[in] template
1768  *   Pointer to the item template to be destroyed.
1769  * @param[out] error
1770  *   Pointer to error structure.
1771  *
1772  * @return
1773  *   0 on success, a negative errno value otherwise and rte_errno is set.
1774  */
1775 static int
1776 flow_hw_pattern_template_destroy(struct rte_eth_dev *dev __rte_unused,
1777                               struct rte_flow_pattern_template *template,
1778                               struct rte_flow_error *error __rte_unused)
1779 {
1780         if (__atomic_load_n(&template->refcnt, __ATOMIC_RELAXED) > 1) {
1781                 DRV_LOG(WARNING, "Item template %p is still in use.",
1782                         (void *)template);
1783                 return rte_flow_error_set(error, EBUSY,
1784                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1785                                    NULL,
1786                                    "item template in using");
1787         }
1788         LIST_REMOVE(template, next);
1789         claim_zero(mlx5dr_match_template_destroy(template->mt));
1790         mlx5_free(template);
1791         return 0;
1792 }
1793
1794 /*
1795  * Get information about HWS pre-configurable resources.
1796  *
1797  * @param[in] dev
1798  *   Pointer to the rte_eth_dev structure.
1799  * @param[out] port_info
1800  *   Pointer to port information.
1801  * @param[out] queue_info
1802  *   Pointer to queue information.
1803  * @param[out] error
1804  *   Pointer to error structure.
1805  *
1806  * @return
1807  *   0 on success, a negative errno value otherwise and rte_errno is set.
1808  */
1809 static int
1810 flow_hw_info_get(struct rte_eth_dev *dev __rte_unused,
1811                  struct rte_flow_port_info *port_info __rte_unused,
1812                  struct rte_flow_queue_info *queue_info __rte_unused,
1813                  struct rte_flow_error *error __rte_unused)
1814 {
1815         /* Nothing to be updated currently. */
1816         memset(port_info, 0, sizeof(*port_info));
1817         /* Queue size is unlimited from low-level. */
1818         queue_info->max_size = UINT32_MAX;
1819         return 0;
1820 }
1821
1822 /**
1823  * Create group callback.
1824  *
1825  * @param[in] tool_ctx
1826  *   Pointer to the hash list related context.
1827  * @param[in] cb_ctx
1828  *   Pointer to the group creation context.
1829  *
1830  * @return
1831  *   Group entry on success, NULL otherwise and rte_errno is set.
1832  */
1833 struct mlx5_list_entry *
1834 flow_hw_grp_create_cb(void *tool_ctx, void *cb_ctx)
1835 {
1836         struct mlx5_dev_ctx_shared *sh = tool_ctx;
1837         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
1838         struct rte_eth_dev *dev = ctx->dev;
1839         struct rte_flow_attr *attr = (struct rte_flow_attr *)ctx->data;
1840         struct mlx5_priv *priv = dev->data->dev_private;
1841         struct mlx5dr_table_attr dr_tbl_attr = {0};
1842         struct rte_flow_error *error = ctx->error;
1843         struct mlx5_flow_group *grp_data;
1844         struct mlx5dr_table *tbl = NULL;
1845         struct mlx5dr_action *jump;
1846         uint32_t idx = 0;
1847
1848         grp_data = mlx5_ipool_zmalloc(sh->ipool[MLX5_IPOOL_HW_GRP], &idx);
1849         if (!grp_data) {
1850                 rte_flow_error_set(error, ENOMEM,
1851                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1852                                    NULL,
1853                                    "cannot allocate flow table data entry");
1854                 return NULL;
1855         }
1856         dr_tbl_attr.level = attr->group;
1857         if (attr->transfer)
1858                 dr_tbl_attr.type = MLX5DR_TABLE_TYPE_FDB;
1859         else if (attr->egress)
1860                 dr_tbl_attr.type = MLX5DR_TABLE_TYPE_NIC_TX;
1861         else
1862                 dr_tbl_attr.type = MLX5DR_TABLE_TYPE_NIC_RX;
1863         tbl = mlx5dr_table_create(priv->dr_ctx, &dr_tbl_attr);
1864         if (!tbl)
1865                 goto error;
1866         grp_data->tbl = tbl;
1867         if (attr->group) {
1868                 /* Jump action be used by non-root table. */
1869                 jump = mlx5dr_action_create_dest_table
1870                         (priv->dr_ctx, tbl,
1871                          mlx5_hw_act_flag[!!attr->group][dr_tbl_attr.type]);
1872                 if (!jump)
1873                         goto error;
1874                 grp_data->jump.hws_action = jump;
1875                 /* Jump action be used by root table.  */
1876                 jump = mlx5dr_action_create_dest_table
1877                         (priv->dr_ctx, tbl,
1878                          mlx5_hw_act_flag[MLX5_HW_ACTION_FLAG_ROOT]
1879                                          [dr_tbl_attr.type]);
1880                 if (!jump)
1881                         goto error;
1882                 grp_data->jump.root_action = jump;
1883         }
1884         grp_data->idx = idx;
1885         grp_data->group_id = attr->group;
1886         grp_data->type = dr_tbl_attr.type;
1887         return &grp_data->entry;
1888 error:
1889         if (grp_data->jump.root_action)
1890                 mlx5dr_action_destroy(grp_data->jump.root_action);
1891         if (grp_data->jump.hws_action)
1892                 mlx5dr_action_destroy(grp_data->jump.hws_action);
1893         if (tbl)
1894                 mlx5dr_table_destroy(tbl);
1895         if (idx)
1896                 mlx5_ipool_free(sh->ipool[MLX5_IPOOL_HW_GRP], idx);
1897         rte_flow_error_set(error, ENOMEM,
1898                            RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1899                            NULL,
1900                            "cannot allocate flow dr table");
1901         return NULL;
1902 }
1903
1904 /**
1905  * Remove group callback.
1906  *
1907  * @param[in] tool_ctx
1908  *   Pointer to the hash list related context.
1909  * @param[in] entry
1910  *   Pointer to the entry to be removed.
1911  */
1912 void
1913 flow_hw_grp_remove_cb(void *tool_ctx, struct mlx5_list_entry *entry)
1914 {
1915         struct mlx5_dev_ctx_shared *sh = tool_ctx;
1916         struct mlx5_flow_group *grp_data =
1917                     container_of(entry, struct mlx5_flow_group, entry);
1918
1919         MLX5_ASSERT(entry && sh);
1920         /* To use the wrapper glue functions instead. */
1921         if (grp_data->jump.hws_action)
1922                 mlx5dr_action_destroy(grp_data->jump.hws_action);
1923         if (grp_data->jump.root_action)
1924                 mlx5dr_action_destroy(grp_data->jump.root_action);
1925         mlx5dr_table_destroy(grp_data->tbl);
1926         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_HW_GRP], grp_data->idx);
1927 }
1928
1929 /**
1930  * Match group callback.
1931  *
1932  * @param[in] tool_ctx
1933  *   Pointer to the hash list related context.
1934  * @param[in] entry
1935  *   Pointer to the group to be matched.
1936  * @param[in] cb_ctx
1937  *   Pointer to the group matching context.
1938  *
1939  * @return
1940  *   0 on matched, 1 on miss matched.
1941  */
1942 int
1943 flow_hw_grp_match_cb(void *tool_ctx __rte_unused, struct mlx5_list_entry *entry,
1944                      void *cb_ctx)
1945 {
1946         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
1947         struct mlx5_flow_group *grp_data =
1948                 container_of(entry, struct mlx5_flow_group, entry);
1949         struct rte_flow_attr *attr =
1950                         (struct rte_flow_attr *)ctx->data;
1951
1952         return (grp_data->group_id != attr->group) ||
1953                 ((grp_data->type != MLX5DR_TABLE_TYPE_FDB) &&
1954                 attr->transfer) ||
1955                 ((grp_data->type != MLX5DR_TABLE_TYPE_NIC_TX) &&
1956                 attr->egress) ||
1957                 ((grp_data->type != MLX5DR_TABLE_TYPE_NIC_RX) &&
1958                 attr->ingress);
1959 }
1960
1961 /**
1962  * Clone group entry callback.
1963  *
1964  * @param[in] tool_ctx
1965  *   Pointer to the hash list related context.
1966  * @param[in] entry
1967  *   Pointer to the group to be matched.
1968  * @param[in] cb_ctx
1969  *   Pointer to the group matching context.
1970  *
1971  * @return
1972  *   0 on matched, 1 on miss matched.
1973  */
1974 struct mlx5_list_entry *
1975 flow_hw_grp_clone_cb(void *tool_ctx, struct mlx5_list_entry *oentry,
1976                      void *cb_ctx)
1977 {
1978         struct mlx5_dev_ctx_shared *sh = tool_ctx;
1979         struct mlx5_flow_cb_ctx *ctx = cb_ctx;
1980         struct mlx5_flow_group *grp_data;
1981         struct rte_flow_error *error = ctx->error;
1982         uint32_t idx = 0;
1983
1984         grp_data = mlx5_ipool_malloc(sh->ipool[MLX5_IPOOL_HW_GRP], &idx);
1985         if (!grp_data) {
1986                 rte_flow_error_set(error, ENOMEM,
1987                                    RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
1988                                    NULL,
1989                                    "cannot allocate flow table data entry");
1990                 return NULL;
1991         }
1992         memcpy(grp_data, oentry, sizeof(*grp_data));
1993         grp_data->idx = idx;
1994         return &grp_data->entry;
1995 }
1996
1997 /**
1998  * Free cloned group entry callback.
1999  *
2000  * @param[in] tool_ctx
2001  *   Pointer to the hash list related context.
2002  * @param[in] entry
2003  *   Pointer to the group to be freed.
2004  */
2005 void
2006 flow_hw_grp_clone_free_cb(void *tool_ctx, struct mlx5_list_entry *entry)
2007 {
2008         struct mlx5_dev_ctx_shared *sh = tool_ctx;
2009         struct mlx5_flow_group *grp_data =
2010                     container_of(entry, struct mlx5_flow_group, entry);
2011
2012         mlx5_ipool_free(sh->ipool[MLX5_IPOOL_HW_GRP], grp_data->idx);
2013 }
2014
2015 /**
2016  * Configure port HWS resources.
2017  *
2018  * @param[in] dev
2019  *   Pointer to the rte_eth_dev structure.
2020  * @param[in] port_attr
2021  *   Port configuration attributes.
2022  * @param[in] nb_queue
2023  *   Number of queue.
2024  * @param[in] queue_attr
2025  *   Array that holds attributes for each flow queue.
2026  * @param[out] error
2027  *   Pointer to error structure.
2028  *
2029  * @return
2030  *   0 on success, a negative errno value otherwise and rte_errno is set.
2031  */
2032
2033 static int
2034 flow_hw_configure(struct rte_eth_dev *dev,
2035                   const struct rte_flow_port_attr *port_attr,
2036                   uint16_t nb_queue,
2037                   const struct rte_flow_queue_attr *queue_attr[],
2038                   struct rte_flow_error *error)
2039 {
2040         struct mlx5_priv *priv = dev->data->dev_private;
2041         struct mlx5dr_context *dr_ctx = NULL;
2042         struct mlx5dr_context_attr dr_ctx_attr = {0};
2043         struct mlx5_hw_q *hw_q;
2044         struct mlx5_hw_q_job *job = NULL;
2045         uint32_t mem_size, i, j;
2046         struct mlx5_indexed_pool_config cfg = {
2047                 .size = sizeof(struct rte_flow_hw),
2048                 .trunk_size = 4096,
2049                 .need_lock = 1,
2050                 .release_mem_en = !!priv->sh->config.reclaim_mode,
2051                 .malloc = mlx5_malloc,
2052                 .free = mlx5_free,
2053                 .type = "mlx5_hw_action_construct_data",
2054         };
2055
2056         if (!port_attr || !nb_queue || !queue_attr) {
2057                 rte_errno = EINVAL;
2058                 goto err;
2059         }
2060         /* In case re-configuring, release existing context at first. */
2061         if (priv->dr_ctx) {
2062                 /* */
2063                 for (i = 0; i < nb_queue; i++) {
2064                         hw_q = &priv->hw_q[i];
2065                         /* Make sure all queues are empty. */
2066                         if (hw_q->size != hw_q->job_idx) {
2067                                 rte_errno = EBUSY;
2068                                 goto err;
2069                         }
2070                 }
2071                 flow_hw_resource_release(dev);
2072         }
2073         priv->acts_ipool = mlx5_ipool_create(&cfg);
2074         if (!priv->acts_ipool)
2075                 goto err;
2076         /* Allocate the queue job descriptor LIFO. */
2077         mem_size = sizeof(priv->hw_q[0]) * nb_queue;
2078         for (i = 0; i < nb_queue; i++) {
2079                 /*
2080                  * Check if the queues' size are all the same as the
2081                  * limitation from HWS layer.
2082                  */
2083                 if (queue_attr[i]->size != queue_attr[0]->size) {
2084                         rte_errno = EINVAL;
2085                         goto err;
2086                 }
2087                 mem_size += (sizeof(struct mlx5_hw_q_job *) +
2088                             sizeof(uint8_t) * MLX5_ENCAP_MAX_LEN +
2089                             sizeof(struct mlx5_hw_q_job)) *
2090                             queue_attr[0]->size;
2091         }
2092         priv->hw_q = mlx5_malloc(MLX5_MEM_ZERO, mem_size,
2093                                  64, SOCKET_ID_ANY);
2094         if (!priv->hw_q) {
2095                 rte_errno = ENOMEM;
2096                 goto err;
2097         }
2098         for (i = 0; i < nb_queue; i++) {
2099                 uint8_t *encap = NULL;
2100
2101                 priv->hw_q[i].job_idx = queue_attr[i]->size;
2102                 priv->hw_q[i].size = queue_attr[i]->size;
2103                 if (i == 0)
2104                         priv->hw_q[i].job = (struct mlx5_hw_q_job **)
2105                                             &priv->hw_q[nb_queue];
2106                 else
2107                         priv->hw_q[i].job = (struct mlx5_hw_q_job **)
2108                                             &job[queue_attr[i - 1]->size];
2109                 job = (struct mlx5_hw_q_job *)
2110                       &priv->hw_q[i].job[queue_attr[i]->size];
2111                 encap = (uint8_t *)&job[queue_attr[i]->size];
2112                 for (j = 0; j < queue_attr[i]->size; j++) {
2113                         job[j].encap_data = &encap[j * MLX5_ENCAP_MAX_LEN];
2114                         priv->hw_q[i].job[j] = &job[j];
2115                 }
2116         }
2117         dr_ctx_attr.pd = priv->sh->cdev->pd;
2118         dr_ctx_attr.queues = nb_queue;
2119         /* Queue size should all be the same. Take the first one. */
2120         dr_ctx_attr.queue_size = queue_attr[0]->size;
2121         dr_ctx = mlx5dr_context_open(priv->sh->cdev->ctx, &dr_ctx_attr);
2122         /* rte_errno has been updated by HWS layer. */
2123         if (!dr_ctx)
2124                 goto err;
2125         priv->dr_ctx = dr_ctx;
2126         priv->nb_queue = nb_queue;
2127         /* Add global actions. */
2128         for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) {
2129                 for (j = 0; j < MLX5DR_TABLE_TYPE_MAX; j++) {
2130                         priv->hw_drop[i][j] = mlx5dr_action_create_dest_drop
2131                                 (priv->dr_ctx, mlx5_hw_act_flag[i][j]);
2132                         if (!priv->hw_drop[i][j])
2133                                 goto err;
2134                 }
2135                 priv->hw_tag[i] = mlx5dr_action_create_tag
2136                         (priv->dr_ctx, mlx5_hw_act_flag[i][0]);
2137                 if (!priv->hw_tag[i])
2138                         goto err;
2139         }
2140         return 0;
2141 err:
2142         for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) {
2143                 for (j = 0; j < MLX5DR_TABLE_TYPE_MAX; j++) {
2144                         if (priv->hw_drop[i][j])
2145                                 mlx5dr_action_destroy(priv->hw_drop[i][j]);
2146                 }
2147                 if (priv->hw_tag[i])
2148                         mlx5dr_action_destroy(priv->hw_tag[i]);
2149         }
2150         if (dr_ctx)
2151                 claim_zero(mlx5dr_context_close(dr_ctx));
2152         mlx5_free(priv->hw_q);
2153         priv->hw_q = NULL;
2154         if (priv->acts_ipool) {
2155                 mlx5_ipool_destroy(priv->acts_ipool);
2156                 priv->acts_ipool = NULL;
2157         }
2158         return rte_flow_error_set(error, rte_errno,
2159                                   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
2160                                   "fail to configure port");
2161 }
2162
2163 /**
2164  * Release HWS resources.
2165  *
2166  * @param[in] dev
2167  *   Pointer to the rte_eth_dev structure.
2168  */
2169 void
2170 flow_hw_resource_release(struct rte_eth_dev *dev)
2171 {
2172         struct mlx5_priv *priv = dev->data->dev_private;
2173         struct rte_flow_template_table *tbl;
2174         struct rte_flow_pattern_template *it;
2175         struct rte_flow_actions_template *at;
2176         int i, j;
2177
2178         if (!priv->dr_ctx)
2179                 return;
2180         while (!LIST_EMPTY(&priv->flow_hw_tbl)) {
2181                 tbl = LIST_FIRST(&priv->flow_hw_tbl);
2182                 flow_hw_table_destroy(dev, tbl, NULL);
2183         }
2184         while (!LIST_EMPTY(&priv->flow_hw_itt)) {
2185                 it = LIST_FIRST(&priv->flow_hw_itt);
2186                 flow_hw_pattern_template_destroy(dev, it, NULL);
2187         }
2188         while (!LIST_EMPTY(&priv->flow_hw_at)) {
2189                 at = LIST_FIRST(&priv->flow_hw_at);
2190                 flow_hw_actions_template_destroy(dev, at, NULL);
2191         }
2192         for (i = 0; i < MLX5_HW_ACTION_FLAG_MAX; i++) {
2193                 for (j = 0; j < MLX5DR_TABLE_TYPE_MAX; j++) {
2194                         if (priv->hw_drop[i][j])
2195                                 mlx5dr_action_destroy(priv->hw_drop[i][j]);
2196                 }
2197                 if (priv->hw_tag[i])
2198                         mlx5dr_action_destroy(priv->hw_tag[i]);
2199         }
2200         if (priv->acts_ipool) {
2201                 mlx5_ipool_destroy(priv->acts_ipool);
2202                 priv->acts_ipool = NULL;
2203         }
2204         mlx5_free(priv->hw_q);
2205         priv->hw_q = NULL;
2206         claim_zero(mlx5dr_context_close(priv->dr_ctx));
2207         priv->dr_ctx = NULL;
2208         priv->nb_queue = 0;
2209 }
2210
2211 /**
2212  * Create shared action.
2213  *
2214  * @param[in] dev
2215  *   Pointer to the rte_eth_dev structure.
2216  * @param[in] queue
2217  *   Which queue to be used..
2218  * @param[in] attr
2219  *   Operation attribute.
2220  * @param[in] conf
2221  *   Indirect action configuration.
2222  * @param[in] action
2223  *   rte_flow action detail.
2224  * @param[in] user_data
2225  *   Pointer to the user_data.
2226  * @param[out] error
2227  *   Pointer to error structure.
2228  *
2229  * @return
2230  *   Action handle on success, NULL otherwise and rte_errno is set.
2231  */
2232 static struct rte_flow_action_handle *
2233 flow_hw_action_handle_create(struct rte_eth_dev *dev, uint32_t queue,
2234                              const struct rte_flow_op_attr *attr,
2235                              const struct rte_flow_indir_action_conf *conf,
2236                              const struct rte_flow_action *action,
2237                              void *user_data,
2238                              struct rte_flow_error *error)
2239 {
2240         RTE_SET_USED(queue);
2241         RTE_SET_USED(attr);
2242         RTE_SET_USED(user_data);
2243         return flow_dv_action_create(dev, conf, action, error);
2244 }
2245
2246 /**
2247  * Update shared action.
2248  *
2249  * @param[in] dev
2250  *   Pointer to the rte_eth_dev structure.
2251  * @param[in] queue
2252  *   Which queue to be used..
2253  * @param[in] attr
2254  *   Operation attribute.
2255  * @param[in] handle
2256  *   Action handle to be updated.
2257  * @param[in] update
2258  *   Update value.
2259  * @param[in] user_data
2260  *   Pointer to the user_data.
2261  * @param[out] error
2262  *   Pointer to error structure.
2263  *
2264  * @return
2265  *   0 on success, negative value otherwise and rte_errno is set.
2266  */
2267 static int
2268 flow_hw_action_handle_update(struct rte_eth_dev *dev, uint32_t queue,
2269                              const struct rte_flow_op_attr *attr,
2270                              struct rte_flow_action_handle *handle,
2271                              const void *update,
2272                              void *user_data,
2273                              struct rte_flow_error *error)
2274 {
2275         RTE_SET_USED(queue);
2276         RTE_SET_USED(attr);
2277         RTE_SET_USED(user_data);
2278         return flow_dv_action_update(dev, handle, update, error);
2279 }
2280
2281 /**
2282  * Destroy shared action.
2283  *
2284  * @param[in] dev
2285  *   Pointer to the rte_eth_dev structure.
2286  * @param[in] queue
2287  *   Which queue to be used..
2288  * @param[in] attr
2289  *   Operation attribute.
2290  * @param[in] handle
2291  *   Action handle to be destroyed.
2292  * @param[in] user_data
2293  *   Pointer to the user_data.
2294  * @param[out] error
2295  *   Pointer to error structure.
2296  *
2297  * @return
2298  *   0 on success, negative value otherwise and rte_errno is set.
2299  */
2300 static int
2301 flow_hw_action_handle_destroy(struct rte_eth_dev *dev, uint32_t queue,
2302                               const struct rte_flow_op_attr *attr,
2303                               struct rte_flow_action_handle *handle,
2304                               void *user_data,
2305                               struct rte_flow_error *error)
2306 {
2307         RTE_SET_USED(queue);
2308         RTE_SET_USED(attr);
2309         RTE_SET_USED(user_data);
2310         return flow_dv_action_destroy(dev, handle, error);
2311 }
2312
2313
2314 const struct mlx5_flow_driver_ops mlx5_flow_hw_drv_ops = {
2315         .info_get = flow_hw_info_get,
2316         .configure = flow_hw_configure,
2317         .pattern_template_create = flow_hw_pattern_template_create,
2318         .pattern_template_destroy = flow_hw_pattern_template_destroy,
2319         .actions_template_create = flow_hw_actions_template_create,
2320         .actions_template_destroy = flow_hw_actions_template_destroy,
2321         .template_table_create = flow_hw_table_create,
2322         .template_table_destroy = flow_hw_table_destroy,
2323         .async_flow_create = flow_hw_async_flow_create,
2324         .async_flow_destroy = flow_hw_async_flow_destroy,
2325         .pull = flow_hw_pull,
2326         .push = flow_hw_push,
2327         .async_action_create = flow_hw_action_handle_create,
2328         .async_action_destroy = flow_hw_action_handle_destroy,
2329         .async_action_update = flow_hw_action_handle_update,
2330         .action_validate = flow_dv_action_validate,
2331         .action_create = flow_dv_action_create,
2332         .action_destroy = flow_dv_action_destroy,
2333         .action_update = flow_dv_action_update,
2334         .action_query = flow_dv_action_query,
2335 };
2336
2337 #endif