xref: /dpdk/drivers/net/mlx5/mlx5_flow_hw.c (revision 42a8fc7daa46256d150278fc9a7a846e27945a0c)
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 mlx5_action_construct_data),
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
2338