xref: /dpdk/drivers/net/mlx5/mlx5_flow_flex.c (revision b04b06f4cb3f3bdd24228f3ca2ec5b3a7b64308d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2021 NVIDIA Corporation & Affiliates
3  */
4 #include <rte_malloc.h>
5 #include <mlx5_devx_cmds.h>
6 #include <mlx5_malloc.h>
7 #include "mlx5.h"
8 #include "mlx5_flow.h"
9 
10 static_assert(sizeof(uint32_t) * CHAR_BIT >= MLX5_PORT_FLEX_ITEM_NUM,
11 	      "Flex item maximal number exceeds uint32_t bit width");
12 
13 /**
14  *  Routine called once on port initialization to init flex item
15  *  related infrastructure initialization
16  *
17  * @param dev
18  *   Ethernet device to perform flex item initialization
19  *
20  * @return
21  *   0 on success, a negative errno value otherwise and rte_errno is set.
22  */
23 int
24 mlx5_flex_item_port_init(struct rte_eth_dev *dev)
25 {
26 	struct mlx5_priv *priv = dev->data->dev_private;
27 
28 	rte_spinlock_init(&priv->flex_item_sl);
29 	MLX5_ASSERT(!priv->flex_item_map);
30 	return 0;
31 }
32 
33 /**
34  *  Routine called once on port close to perform flex item
35  *  related infrastructure cleanup.
36  *
37  * @param dev
38  *   Ethernet device to perform cleanup
39  */
40 void
41 mlx5_flex_item_port_cleanup(struct rte_eth_dev *dev)
42 {
43 	struct mlx5_priv *priv = dev->data->dev_private;
44 	uint32_t i;
45 
46 	for (i = 0; i < MLX5_PORT_FLEX_ITEM_NUM && priv->flex_item_map ; i++) {
47 		if (priv->flex_item_map & (1 << i)) {
48 			struct mlx5_flex_item *flex = &priv->flex_item[i];
49 
50 			claim_zero(mlx5_list_unregister
51 					(priv->sh->flex_parsers_dv,
52 					 &flex->devx_fp->entry));
53 			flex->devx_fp = NULL;
54 			flex->refcnt = 0;
55 			priv->flex_item_map &= ~(1 << i);
56 		}
57 	}
58 }
59 
60 static int
61 mlx5_flex_index(struct mlx5_priv *priv, struct mlx5_flex_item *item)
62 {
63 	uintptr_t start = (uintptr_t)&priv->flex_item[0];
64 	uintptr_t entry = (uintptr_t)item;
65 	uintptr_t idx = (entry - start) / sizeof(struct mlx5_flex_item);
66 
67 	if (entry < start ||
68 	    idx >= MLX5_PORT_FLEX_ITEM_NUM ||
69 	    (entry - start) % sizeof(struct mlx5_flex_item) ||
70 	    !(priv->flex_item_map & (1u << idx)))
71 		return -1;
72 	return (int)idx;
73 }
74 
75 static struct mlx5_flex_item *
76 mlx5_flex_alloc(struct mlx5_priv *priv)
77 {
78 	struct mlx5_flex_item *item = NULL;
79 
80 	rte_spinlock_lock(&priv->flex_item_sl);
81 	if (~priv->flex_item_map) {
82 		uint32_t idx = rte_bsf32(~priv->flex_item_map);
83 
84 		if (idx < MLX5_PORT_FLEX_ITEM_NUM) {
85 			item = &priv->flex_item[idx];
86 			MLX5_ASSERT(!item->refcnt);
87 			MLX5_ASSERT(!item->devx_fp);
88 			item->devx_fp = NULL;
89 			rte_atomic_store_explicit(&item->refcnt, 0, rte_memory_order_release);
90 			priv->flex_item_map |= 1u << idx;
91 		}
92 	}
93 	rte_spinlock_unlock(&priv->flex_item_sl);
94 	return item;
95 }
96 
97 static void
98 mlx5_flex_free(struct mlx5_priv *priv, struct mlx5_flex_item *item)
99 {
100 	int idx = mlx5_flex_index(priv, item);
101 
102 	MLX5_ASSERT(idx >= 0 &&
103 		    idx < MLX5_PORT_FLEX_ITEM_NUM &&
104 		    (priv->flex_item_map & (1u << idx)));
105 	if (idx >= 0) {
106 		rte_spinlock_lock(&priv->flex_item_sl);
107 		MLX5_ASSERT(!item->refcnt);
108 		MLX5_ASSERT(!item->devx_fp);
109 		item->devx_fp = NULL;
110 		rte_atomic_store_explicit(&item->refcnt, 0, rte_memory_order_release);
111 		priv->flex_item_map &= ~(1u << idx);
112 		rte_spinlock_unlock(&priv->flex_item_sl);
113 	}
114 }
115 
116 static uint32_t
117 mlx5_flex_get_bitfield(const struct rte_flow_item_flex *item,
118 		       uint32_t pos, uint32_t width, uint32_t shift)
119 {
120 	const uint8_t *ptr = item->pattern + pos / CHAR_BIT;
121 	uint32_t val, vbits, skip = pos % CHAR_BIT;
122 
123 	/* Proceed the bitfield start byte. */
124 	MLX5_ASSERT(width <= sizeof(uint32_t) * CHAR_BIT && width);
125 	MLX5_ASSERT(width + shift <= sizeof(uint32_t) * CHAR_BIT);
126 	if (item->length <= pos / CHAR_BIT)
127 		return 0;
128 	/* Bits are enumerated in byte in network order: 01234567 */
129 	val = *ptr++;
130 	vbits = CHAR_BIT - pos % CHAR_BIT;
131 	pos = RTE_ALIGN_CEIL(pos, CHAR_BIT) / CHAR_BIT;
132 	vbits = RTE_MIN(vbits, width);
133 	/* Load bytes to cover the field width, checking pattern boundary */
134 	while (vbits < width && pos < item->length) {
135 		uint32_t part = RTE_MIN(width - vbits, (uint32_t)CHAR_BIT);
136 		uint32_t tmp = *ptr++;
137 
138 		val |= tmp << RTE_ALIGN_CEIL(vbits, CHAR_BIT);
139 		vbits += part;
140 		pos++;
141 	}
142 	val = rte_cpu_to_be_32(val);
143 	val <<= skip;
144 	val >>= shift;
145 	val &= (RTE_BIT64(width) - 1) << (sizeof(uint32_t) * CHAR_BIT - shift - width);
146 	return val;
147 }
148 
149 #define SET_FP_MATCH_SAMPLE_ID(x, def, msk, val, sid) \
150 	do { \
151 		uint32_t tmp, out = (def); \
152 		tmp = MLX5_GET(fte_match_set_misc4, misc4_v, \
153 			       prog_sample_field_value_##x); \
154 		tmp = (tmp & ~out) | (val); \
155 		MLX5_SET(fte_match_set_misc4, misc4_v, \
156 			 prog_sample_field_value_##x, tmp); \
157 		tmp = MLX5_GET(fte_match_set_misc4, misc4_m, \
158 			       prog_sample_field_value_##x); \
159 		tmp = (tmp & ~out) | (msk); \
160 		MLX5_SET(fte_match_set_misc4, misc4_m, \
161 			 prog_sample_field_value_##x, tmp); \
162 		tmp = tmp ? (sid) : 0; \
163 		MLX5_SET(fte_match_set_misc4, misc4_v, \
164 			 prog_sample_field_id_##x, tmp);\
165 		MLX5_SET(fte_match_set_misc4, misc4_m, \
166 			 prog_sample_field_id_##x, tmp); \
167 	} while (0)
168 
169 __rte_always_inline static void
170 mlx5_flex_set_match_sample(void *misc4_m, void *misc4_v,
171 			   uint32_t def, uint32_t mask, uint32_t value,
172 			   uint32_t sample_id, uint32_t id)
173 {
174 	switch (id) {
175 	case 0:
176 		SET_FP_MATCH_SAMPLE_ID(0, def, mask, value, sample_id);
177 		break;
178 	case 1:
179 		SET_FP_MATCH_SAMPLE_ID(1, def, mask, value, sample_id);
180 		break;
181 	case 2:
182 		SET_FP_MATCH_SAMPLE_ID(2, def, mask, value, sample_id);
183 		break;
184 	case 3:
185 		SET_FP_MATCH_SAMPLE_ID(3, def, mask, value, sample_id);
186 		break;
187 	case 4:
188 		SET_FP_MATCH_SAMPLE_ID(4, def, mask, value, sample_id);
189 		break;
190 	case 5:
191 		SET_FP_MATCH_SAMPLE_ID(5, def, mask, value, sample_id);
192 		break;
193 	case 6:
194 		SET_FP_MATCH_SAMPLE_ID(6, def, mask, value, sample_id);
195 		break;
196 	case 7:
197 		SET_FP_MATCH_SAMPLE_ID(7, def, mask, value, sample_id);
198 		break;
199 	default:
200 		MLX5_ASSERT(false);
201 		break;
202 	}
203 #undef SET_FP_MATCH_SAMPLE_ID
204 }
205 
206 /**
207  * Get the flex parser sample id and corresponding mask
208  * per shift and width information.
209  *
210  * @param[in] tp
211  *   Mlx5 flex item sample mapping handle.
212  * @param[in] idx
213  *   Mapping index.
214  * @param[in, out] pos
215  *   Where to search the value and mask.
216  * @param[in] is_inner
217  *   For inner matching or not.
218  *
219  * @return
220  *   0 on success, -1 to ignore.
221  */
222 int
223 mlx5_flex_get_sample_id(const struct mlx5_flex_item *tp,
224 			uint32_t idx, uint32_t *pos, bool is_inner)
225 {
226 	const struct mlx5_flex_pattern_field *map = tp->map + idx;
227 	uint32_t id = map->reg_id;
228 
229 	/* Skip placeholders for DUMMY fields. */
230 	if (id == MLX5_INVALID_SAMPLE_REG_ID) {
231 		*pos += map->width;
232 		return -1;
233 	}
234 	MLX5_ASSERT(map->width);
235 	MLX5_ASSERT(id < tp->devx_fp->num_samples);
236 	if (tp->tunnel_mode == FLEX_TUNNEL_MODE_MULTI && is_inner) {
237 		uint32_t num_samples = tp->devx_fp->num_samples / 2;
238 
239 		MLX5_ASSERT(tp->devx_fp->num_samples % 2 == 0);
240 		MLX5_ASSERT(id < num_samples);
241 		id += num_samples;
242 	}
243 	return id;
244 }
245 
246 /**
247  * Get the flex parser mapping value per definer format_select_dw.
248  *
249  * @param[in] item
250  *   Rte flex item pointer.
251  * @param[in] flex
252  *   Mlx5 flex item sample mapping handle.
253  * @param[in] byte_off
254  *   Mlx5 flex item format_select_dw.
255  * @param[in] tunnel
256  *   Tunnel mode or not.
257  * @param[in, def] value
258  *   Value calculated for this flex parser, either spec or mask.
259  *
260  * @return
261  *   0 on success, -1 for error.
262  */
263 int
264 mlx5_flex_get_parser_value_per_byte_off(const struct rte_flow_item_flex *item,
265 					void *flex, uint32_t byte_off,
266 					bool tunnel, uint32_t *value)
267 {
268 	struct mlx5_flex_pattern_field *map;
269 	struct mlx5_flex_item *tp = flex;
270 	uint32_t i, pos, val;
271 	int id;
272 
273 	*value = 0;
274 	for (i = 0, pos = 0; i < tp->mapnum && pos < item->length * CHAR_BIT; i++) {
275 		map = tp->map + i;
276 		id = mlx5_flex_get_sample_id(tp, i, &pos, tunnel);
277 		if (id == -1)
278 			continue;
279 		if (id >= (int)tp->devx_fp->num_samples || id >= MLX5_GRAPH_NODE_SAMPLE_NUM)
280 			return -1;
281 		if (byte_off == tp->devx_fp->sample_info[id].sample_dw_data * sizeof(uint32_t)) {
282 			val = mlx5_flex_get_bitfield(item, pos, map->width, map->shift);
283 			*value |= val;
284 		}
285 		pos += map->width;
286 	}
287 	return 0;
288 }
289 
290 /**
291  * Get the flex parser tunnel mode.
292  *
293  * @param[in] item
294  *   RTE Flex item.
295  * @param[in, out] tunnel_mode
296  *   Pointer to return tunnel mode.
297  *
298  * @return
299  *   0 on success, otherwise negative error code.
300  */
301 int
302 mlx5_flex_get_tunnel_mode(const struct rte_flow_item *item,
303 			  enum rte_flow_item_flex_tunnel_mode *tunnel_mode)
304 {
305 	if (item && item->spec && tunnel_mode) {
306 		const struct rte_flow_item_flex *spec = item->spec;
307 		struct mlx5_flex_item *flex = (struct mlx5_flex_item *)spec->handle;
308 
309 		if (flex) {
310 			*tunnel_mode = flex->tunnel_mode;
311 			return 0;
312 		}
313 	}
314 	return -EINVAL;
315 }
316 
317 /**
318  * Translate item pattern into matcher fields according to translation
319  * array.
320  *
321  * @param dev
322  *   Ethernet device to translate flex item on.
323  * @param[in, out] matcher
324  *   Flow matcher to configure
325  * @param[in, out] key
326  *   Flow matcher value.
327  * @param[in] item
328  *   Flow pattern to translate.
329  * @param[in] is_inner
330  *   Inner Flex Item (follows after tunnel header).
331  *
332  * @return
333  *   0 on success, a negative errno value otherwise and rte_errno is set.
334  */
335 void
336 mlx5_flex_flow_translate_item(struct rte_eth_dev *dev,
337 			      void *matcher, void *key,
338 			      const struct rte_flow_item *item,
339 			      bool is_inner)
340 {
341 	const struct rte_flow_item_flex *spec, *mask;
342 	void *misc4_m = MLX5_ADDR_OF(fte_match_param, matcher,
343 				     misc_parameters_4);
344 	void *misc4_v = MLX5_ADDR_OF(fte_match_param, key, misc_parameters_4);
345 	struct mlx5_flex_item *tp;
346 	uint32_t i, pos = 0;
347 	uint32_t sample_id;
348 
349 	RTE_SET_USED(dev);
350 	MLX5_ASSERT(item->spec && item->mask);
351 	spec = item->spec;
352 	mask = item->mask;
353 	tp = (struct mlx5_flex_item *)spec->handle;
354 	for (i = 0; i < tp->mapnum && pos < (spec->length * CHAR_BIT); i++) {
355 		struct mlx5_flex_pattern_field *map = tp->map + i;
356 		uint32_t val, msk, def;
357 		int id = mlx5_flex_get_sample_id(tp, i, &pos, is_inner);
358 
359 		if (id == -1)
360 			continue;
361 		MLX5_ASSERT(id < (int)tp->devx_fp->num_samples);
362 		if (id >= (int)tp->devx_fp->num_samples ||
363 		    id >= MLX5_GRAPH_NODE_SAMPLE_NUM)
364 			return;
365 		def = (uint32_t)(RTE_BIT64(map->width) - 1);
366 		def <<= (sizeof(uint32_t) * CHAR_BIT - map->shift - map->width);
367 		val = mlx5_flex_get_bitfield(spec, pos, map->width, map->shift);
368 		msk = pos < (mask->length * CHAR_BIT) ?
369 		      mlx5_flex_get_bitfield(mask, pos, map->width, map->shift) : def;
370 		sample_id = tp->devx_fp->sample_ids[id];
371 		mlx5_flex_set_match_sample(misc4_m, misc4_v,
372 					   def, msk, val & msk,
373 					   sample_id, id);
374 		pos += map->width;
375 	}
376 }
377 
378 /**
379  * Convert flex item handle (from the RTE flow) to flex item index on port.
380  * Optionally can increment flex item object reference count.
381  *
382  * @param dev
383  *   Ethernet device to acquire flex item on.
384  * @param[in] handle
385  *   Flow item handle from item spec.
386  * @param[in] acquire
387  *   If set - increment reference counter.
388  *
389  * @return
390  *   >=0 - index on success, a negative errno value otherwise
391  *         and rte_errno is set.
392  */
393 int
394 mlx5_flex_acquire_index(struct rte_eth_dev *dev,
395 			struct rte_flow_item_flex_handle *handle,
396 			bool acquire)
397 {
398 	struct mlx5_priv *priv = dev->data->dev_private;
399 	struct mlx5_flex_item *flex = (struct mlx5_flex_item *)handle;
400 	int ret = mlx5_flex_index(priv, flex);
401 
402 	if (ret < 0) {
403 		errno = -EINVAL;
404 		rte_errno = EINVAL;
405 		return ret;
406 	}
407 	if (acquire)
408 		rte_atomic_fetch_add_explicit(&flex->refcnt, 1, rte_memory_order_release);
409 	return ret;
410 }
411 
412 /**
413  * Release flex item index on port - decrements reference counter by index.
414  *
415  * @param dev
416  *   Ethernet device to acquire flex item on.
417  * @param[in] index
418  *   Flow item index.
419  *
420  * @return
421  *   0 - on success, a negative errno value otherwise and rte_errno is set.
422  */
423 int
424 mlx5_flex_release_index(struct rte_eth_dev *dev,
425 			int index)
426 {
427 	struct mlx5_priv *priv = dev->data->dev_private;
428 	struct mlx5_flex_item *flex;
429 
430 	if (index >= MLX5_PORT_FLEX_ITEM_NUM ||
431 	    !(priv->flex_item_map & (1u << index))) {
432 		errno = EINVAL;
433 		rte_errno = -EINVAL;
434 		return -EINVAL;
435 	}
436 	flex = priv->flex_item + index;
437 	if (flex->refcnt <= 1) {
438 		MLX5_ASSERT(false);
439 		errno = EINVAL;
440 		rte_errno = -EINVAL;
441 		return -EINVAL;
442 	}
443 	rte_atomic_fetch_sub_explicit(&flex->refcnt, 1, rte_memory_order_release);
444 	return 0;
445 }
446 
447 /*
448  * Calculate largest mask value for a given shift.
449  *
450  *   shift      mask
451  * ------- ---------------
452  *    0     b11111100  0x3C
453  *    1     b01111110  0x3E
454  *    2     b00111111  0x3F
455  *    3     b00011111  0x1F
456  *    4     b00001111  0x0F
457  *    5     b00000111  0x07
458  *    6     b00000011  0x03
459  *    7     b00000001  0x01
460  */
461 static uint8_t
462 mlx5_flex_hdr_len_mask(uint8_t shift,
463 		       const struct mlx5_hca_flex_attr *attr)
464 {
465 	uint32_t base_mask;
466 	int diff = shift - MLX5_PARSE_GRAPH_NODE_HDR_LEN_SHIFT_DWORD;
467 
468 	base_mask = mlx5_hca_parse_graph_node_base_hdr_len_mask(attr);
469 	return diff < 0 ? base_mask << -diff : base_mask >> diff;
470 }
471 
472 static int
473 mlx5_flex_translate_length(struct mlx5_hca_flex_attr *attr,
474 			   const struct rte_flow_item_flex_conf *conf,
475 			   struct mlx5_flex_parser_devx *devx,
476 			   struct rte_flow_error *error)
477 {
478 	const struct rte_flow_item_flex_field *field = &conf->next_header;
479 	struct mlx5_devx_graph_node_attr *node = &devx->devx_conf;
480 
481 	if (field->field_base % CHAR_BIT)
482 		return rte_flow_error_set
483 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
484 			 "not byte aligned header length field");
485 	switch (field->field_mode) {
486 	case FIELD_MODE_DUMMY:
487 		return rte_flow_error_set
488 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
489 			 "invalid header length field mode (DUMMY)");
490 	case FIELD_MODE_FIXED:
491 		if (!(attr->header_length_mode &
492 		    RTE_BIT32(MLX5_GRAPH_NODE_LEN_FIXED)))
493 			return rte_flow_error_set
494 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
495 				 "unsupported header length field mode (FIXED)");
496 		if (field->field_size ||
497 		    field->offset_mask || field->offset_shift)
498 			return rte_flow_error_set
499 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
500 				 "invalid fields for fixed mode");
501 		if (field->field_base < 0)
502 			return rte_flow_error_set
503 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
504 				 "negative header length field base (FIXED)");
505 		node->header_length_mode = MLX5_GRAPH_NODE_LEN_FIXED;
506 		break;
507 	case FIELD_MODE_OFFSET: {
508 		uint32_t msb, lsb;
509 		int32_t shift = field->offset_shift;
510 		uint32_t offset = field->offset_base;
511 		uint32_t mask = field->offset_mask;
512 		uint32_t wmax = attr->header_length_mask_width +
513 				MLX5_PARSE_GRAPH_NODE_HDR_LEN_SHIFT_DWORD;
514 
515 		if (!(attr->header_length_mode &
516 		    RTE_BIT32(MLX5_GRAPH_NODE_LEN_FIELD)))
517 			return rte_flow_error_set
518 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
519 				 "unsupported header length field mode (OFFSET)");
520 		if (!field->field_size)
521 			return rte_flow_error_set
522 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
523 				 "field size is a must for offset mode");
524 		if ((offset ^ (field->field_size + offset)) >> 5)
525 			return rte_flow_error_set
526 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
527 				 "field crosses the 32-bit word boundary");
528 		/* Hardware counts in dwords, all shifts done by offset within mask */
529 		if (shift < 0 || (uint32_t)shift >= wmax)
530 			return rte_flow_error_set
531 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
532 				 "header length field shift exceeds limits (OFFSET)");
533 		if (!mask)
534 			return rte_flow_error_set
535 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
536 				 "zero length field offset mask (OFFSET)");
537 		msb = rte_fls_u32(mask) - 1;
538 		lsb = rte_bsf32(mask);
539 		if (!rte_is_power_of_2((mask >> lsb) + 1))
540 			return rte_flow_error_set
541 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
542 				 "length field offset mask not contiguous (OFFSET)");
543 		if (msb >= field->field_size)
544 			return rte_flow_error_set
545 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
546 				 "length field offset mask exceeds field size (OFFSET)");
547 		if (msb >= wmax)
548 			return rte_flow_error_set
549 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
550 				 "length field offset mask exceeds supported width (OFFSET)");
551 		if (mask & ~mlx5_flex_hdr_len_mask(shift, attr))
552 			return rte_flow_error_set
553 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
554 				 "mask and shift combination not supported (OFFSET)");
555 		msb++;
556 		offset += field->field_size - msb;
557 		if (msb < attr->header_length_mask_width) {
558 			if (attr->header_length_mask_width - msb > offset)
559 				return rte_flow_error_set
560 					(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
561 					 "field size plus offset_base is too small");
562 			offset += msb;
563 			/*
564 			 * Here we can move to preceding dword. Hardware does
565 			 * cyclic left shift so we should avoid this and stay
566 			 * at current dword offset.
567 			 */
568 			offset = (offset & ~0x1Fu) |
569 				 ((offset - attr->header_length_mask_width) & 0x1F);
570 		}
571 		node->header_length_mode = MLX5_GRAPH_NODE_LEN_FIELD;
572 		node->header_length_field_mask = mask;
573 		node->header_length_field_shift = shift;
574 		node->header_length_field_offset = offset;
575 		break;
576 	}
577 	case FIELD_MODE_BITMASK:
578 		if (!(attr->header_length_mode &
579 		    RTE_BIT32(MLX5_GRAPH_NODE_LEN_BITMASK)))
580 			return rte_flow_error_set
581 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
582 				 "unsupported header length field mode (BITMASK)");
583 		if (field->offset_shift > 15 || field->offset_shift < 0)
584 			return rte_flow_error_set
585 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
586 				 "header length field shift exceeds limit (BITMASK)");
587 		node->header_length_mode = MLX5_GRAPH_NODE_LEN_BITMASK;
588 		node->header_length_field_mask = field->offset_mask;
589 		node->header_length_field_shift = field->offset_shift;
590 		node->header_length_field_offset = field->offset_base;
591 		break;
592 	default:
593 		return rte_flow_error_set
594 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
595 			 "unknown header length field mode");
596 	}
597 	if (field->field_base / CHAR_BIT >= 0 &&
598 	    field->field_base / CHAR_BIT > attr->max_base_header_length)
599 		return rte_flow_error_set
600 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
601 			 "header length field base exceeds limit");
602 	node->header_length_base_value = field->field_base / CHAR_BIT;
603 	return 0;
604 }
605 
606 static int
607 mlx5_flex_translate_next(struct mlx5_hca_flex_attr *attr,
608 			 const struct rte_flow_item_flex_conf *conf,
609 			 struct mlx5_flex_parser_devx *devx,
610 			 struct rte_flow_error *error)
611 {
612 	const struct rte_flow_item_flex_field *field = &conf->next_protocol;
613 	struct mlx5_devx_graph_node_attr *node = &devx->devx_conf;
614 
615 	switch (field->field_mode) {
616 	case FIELD_MODE_DUMMY:
617 		if (conf->nb_outputs)
618 			return rte_flow_error_set
619 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
620 				 "next protocol field is required (DUMMY)");
621 		return 0;
622 	case FIELD_MODE_FIXED:
623 		break;
624 	case FIELD_MODE_OFFSET:
625 		return rte_flow_error_set
626 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
627 			 "unsupported next protocol field mode (OFFSET)");
628 		break;
629 	case FIELD_MODE_BITMASK:
630 		return rte_flow_error_set
631 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
632 			 "unsupported next protocol field mode (BITMASK)");
633 	default:
634 		return rte_flow_error_set
635 			(error, EINVAL,
636 			 RTE_FLOW_ERROR_TYPE_ITEM, NULL,
637 			 "unknown next protocol field mode");
638 	}
639 	MLX5_ASSERT(field->field_mode == FIELD_MODE_FIXED);
640 	if (!conf->nb_outputs)
641 		return rte_flow_error_set
642 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
643 			 "out link(s) is required if next field present");
644 	if (attr->max_next_header_offset < field->field_base)
645 		return rte_flow_error_set
646 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
647 			 "next protocol field base exceeds limit");
648 	if (field->offset_shift)
649 		return rte_flow_error_set
650 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
651 			 "unsupported next protocol field shift");
652 	node->next_header_field_offset = field->field_base;
653 	node->next_header_field_size = field->field_size;
654 	return 0;
655 }
656 
657 /* Helper structure to handle field bit intervals. */
658 struct mlx5_flex_field_cover {
659 	uint16_t num;
660 	int32_t start[MLX5_FLEX_ITEM_MAPPING_NUM];
661 	int32_t end[MLX5_FLEX_ITEM_MAPPING_NUM];
662 	uint8_t mapped[MLX5_FLEX_ITEM_MAPPING_NUM / CHAR_BIT + 1];
663 };
664 
665 static void
666 mlx5_flex_insert_field(struct mlx5_flex_field_cover *cover,
667 		       uint16_t num, int32_t start, int32_t end)
668 {
669 	MLX5_ASSERT(num < MLX5_FLEX_ITEM_MAPPING_NUM);
670 	MLX5_ASSERT(num <= cover->num);
671 	if (num < cover->num) {
672 		memmove(&cover->start[num + 1],	&cover->start[num],
673 			(cover->num - num) * sizeof(int32_t));
674 		memmove(&cover->end[num + 1],	&cover->end[num],
675 			(cover->num - num) * sizeof(int32_t));
676 	}
677 	cover->start[num] = start;
678 	cover->end[num] = end;
679 	cover->num++;
680 }
681 
682 static void
683 mlx5_flex_merge_field(struct mlx5_flex_field_cover *cover, uint16_t num)
684 {
685 	uint32_t i, del = 0;
686 	int32_t end;
687 
688 	MLX5_ASSERT(num < MLX5_FLEX_ITEM_MAPPING_NUM);
689 	MLX5_ASSERT(num < (cover->num - 1));
690 	end = cover->end[num];
691 	for (i = num + 1; i < cover->num; i++) {
692 		if (end < cover->start[i])
693 			break;
694 		del++;
695 		if (end <= cover->end[i]) {
696 			cover->end[num] = cover->end[i];
697 			break;
698 		}
699 	}
700 	if (del) {
701 		MLX5_ASSERT(del < (cover->num - 1u - num));
702 		cover->num -= del;
703 		MLX5_ASSERT(cover->num > num);
704 		if ((cover->num - num) > 1) {
705 			memmove(&cover->start[num + 1],
706 				&cover->start[num + 1 + del],
707 				(cover->num - num - 1) * sizeof(int32_t));
708 			memmove(&cover->end[num + 1],
709 				&cover->end[num + 1 + del],
710 				(cover->num - num - 1) * sizeof(int32_t));
711 		}
712 	}
713 }
714 
715 /*
716  * Validate the sample field and update interval array
717  * if parameters match with the 'match" field.
718  * Returns:
719  *    < 0  - error
720  *    == 0 - no match, interval array not updated
721  *    > 0  - match, interval array updated
722  */
723 static int
724 mlx5_flex_cover_sample(struct mlx5_flex_field_cover *cover,
725 		       struct rte_flow_item_flex_field *field,
726 		       struct rte_flow_item_flex_field *match,
727 		       struct mlx5_hca_flex_attr *attr,
728 		       struct rte_flow_error *error)
729 {
730 	int32_t start, end;
731 	uint32_t i;
732 
733 	switch (field->field_mode) {
734 	case FIELD_MODE_DUMMY:
735 		return 0;
736 	case FIELD_MODE_FIXED:
737 		if (!(attr->sample_offset_mode &
738 		    RTE_BIT32(MLX5_GRAPH_SAMPLE_OFFSET_FIXED)))
739 			return rte_flow_error_set
740 				(error, EINVAL,
741 				 RTE_FLOW_ERROR_TYPE_ITEM, NULL,
742 				 "unsupported sample field mode (FIXED)");
743 		if (field->offset_shift)
744 			return rte_flow_error_set
745 				(error, EINVAL,
746 				 RTE_FLOW_ERROR_TYPE_ITEM, NULL,
747 				 "invalid sample field shift (FIXED");
748 		if (field->field_base < 0)
749 			return rte_flow_error_set
750 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
751 				 "invalid sample field base (FIXED)");
752 		if (field->field_base / CHAR_BIT > attr->max_sample_base_offset)
753 			return rte_flow_error_set
754 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
755 				 "sample field base exceeds limit (FIXED)");
756 		break;
757 	case FIELD_MODE_OFFSET:
758 		if (!(attr->sample_offset_mode &
759 		    RTE_BIT32(MLX5_GRAPH_SAMPLE_OFFSET_FIELD)))
760 			return rte_flow_error_set
761 				(error, EINVAL,
762 				 RTE_FLOW_ERROR_TYPE_ITEM, NULL,
763 				 "unsupported sample field mode (OFFSET)");
764 		if (field->field_base / CHAR_BIT >= 0 &&
765 		    field->field_base / CHAR_BIT > attr->max_sample_base_offset)
766 			return rte_flow_error_set
767 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
768 				"sample field base exceeds limit");
769 		break;
770 	case FIELD_MODE_BITMASK:
771 		if (!(attr->sample_offset_mode &
772 		    RTE_BIT32(MLX5_GRAPH_SAMPLE_OFFSET_BITMASK)))
773 			return rte_flow_error_set
774 				(error, EINVAL,
775 				 RTE_FLOW_ERROR_TYPE_ITEM, NULL,
776 				 "unsupported sample field mode (BITMASK)");
777 		if (field->field_base / CHAR_BIT >= 0 &&
778 		    field->field_base / CHAR_BIT > attr->max_sample_base_offset)
779 			return rte_flow_error_set
780 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
781 				"sample field base exceeds limit");
782 		break;
783 	default:
784 		return rte_flow_error_set
785 			(error, EINVAL,
786 			 RTE_FLOW_ERROR_TYPE_ITEM, NULL,
787 			 "unknown data sample field mode");
788 	}
789 	if (!match) {
790 		if (!field->field_size)
791 			return rte_flow_error_set
792 				(error, EINVAL,
793 				RTE_FLOW_ERROR_TYPE_ITEM, NULL,
794 				"zero sample field width");
795 		if (field->field_id)
796 			DRV_LOG(DEBUG, "sample field id hint ignored");
797 	} else {
798 		if (field->field_mode != match->field_mode ||
799 		    field->offset_base | match->offset_base ||
800 		    field->offset_mask | match->offset_mask ||
801 		    field->offset_shift | match->offset_shift)
802 			return 0;
803 	}
804 	start = field->field_base;
805 	end = start + field->field_size;
806 	/* Add the new or similar field to interval array. */
807 	if (!cover->num) {
808 		cover->start[cover->num] = start;
809 		cover->end[cover->num] = end;
810 		cover->num = 1;
811 		return 1;
812 	}
813 	for (i = 0; i < cover->num; i++) {
814 		if (start > cover->end[i]) {
815 			if (i >= (cover->num - 1u)) {
816 				mlx5_flex_insert_field(cover, cover->num,
817 						       start, end);
818 				break;
819 			}
820 			continue;
821 		}
822 		if (end < cover->start[i]) {
823 			mlx5_flex_insert_field(cover, i, start, end);
824 			break;
825 		}
826 		if (start < cover->start[i])
827 			cover->start[i] = start;
828 		if (end > cover->end[i]) {
829 			cover->end[i] = end;
830 			if (i < (cover->num - 1u))
831 				mlx5_flex_merge_field(cover, i);
832 		}
833 		break;
834 	}
835 	return 1;
836 }
837 
838 static void
839 mlx5_flex_config_sample(struct mlx5_devx_match_sample_attr *na,
840 			struct rte_flow_item_flex_field *field,
841 			enum rte_flow_item_flex_tunnel_mode tunnel_mode)
842 {
843 	memset(na, 0, sizeof(struct mlx5_devx_match_sample_attr));
844 	na->flow_match_sample_en = 1;
845 	switch (field->field_mode) {
846 	case FIELD_MODE_FIXED:
847 		na->flow_match_sample_offset_mode =
848 			MLX5_GRAPH_SAMPLE_OFFSET_FIXED;
849 		break;
850 	case FIELD_MODE_OFFSET:
851 		na->flow_match_sample_offset_mode =
852 			MLX5_GRAPH_SAMPLE_OFFSET_FIELD;
853 		na->flow_match_sample_field_offset = field->offset_base;
854 		na->flow_match_sample_field_offset_mask = field->offset_mask;
855 		na->flow_match_sample_field_offset_shift = field->offset_shift;
856 		break;
857 	case FIELD_MODE_BITMASK:
858 		na->flow_match_sample_offset_mode =
859 			MLX5_GRAPH_SAMPLE_OFFSET_BITMASK;
860 		na->flow_match_sample_field_offset = field->offset_base;
861 		na->flow_match_sample_field_offset_mask = field->offset_mask;
862 		na->flow_match_sample_field_offset_shift = field->offset_shift;
863 		break;
864 	default:
865 		MLX5_ASSERT(false);
866 		break;
867 	}
868 	switch (tunnel_mode) {
869 	case FLEX_TUNNEL_MODE_SINGLE:
870 		/* Fallthrough */
871 	case FLEX_TUNNEL_MODE_TUNNEL:
872 		na->flow_match_sample_tunnel_mode =
873 			MLX5_GRAPH_SAMPLE_TUNNEL_FIRST;
874 		break;
875 	case FLEX_TUNNEL_MODE_MULTI:
876 		/* Fallthrough */
877 	case FLEX_TUNNEL_MODE_OUTER:
878 		na->flow_match_sample_tunnel_mode =
879 			MLX5_GRAPH_SAMPLE_TUNNEL_OUTER;
880 		break;
881 	case FLEX_TUNNEL_MODE_INNER:
882 		na->flow_match_sample_tunnel_mode =
883 			MLX5_GRAPH_SAMPLE_TUNNEL_INNER;
884 		break;
885 	default:
886 		MLX5_ASSERT(false);
887 		break;
888 	}
889 }
890 
891 /* Map specified field to set/subset of allocated sample registers. */
892 static int
893 mlx5_flex_map_sample(struct rte_flow_item_flex_field *field,
894 		     struct mlx5_flex_parser_devx *parser,
895 		     struct mlx5_flex_item *item,
896 		     struct rte_flow_error *error)
897 {
898 	struct mlx5_devx_match_sample_attr node;
899 	int32_t start = field->field_base;
900 	int32_t end = start + field->field_size;
901 	struct mlx5_flex_pattern_field *trans;
902 	uint32_t i, done_bits = 0;
903 
904 	if (field->field_mode == FIELD_MODE_DUMMY) {
905 		done_bits = field->field_size;
906 		while (done_bits) {
907 			uint32_t part = RTE_MIN(done_bits,
908 						sizeof(uint32_t) * CHAR_BIT);
909 			if (item->mapnum >= MLX5_FLEX_ITEM_MAPPING_NUM)
910 				return rte_flow_error_set
911 					(error,
912 					 EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
913 					 "too many flex item pattern translations");
914 			trans = &item->map[item->mapnum];
915 			trans->reg_id = MLX5_INVALID_SAMPLE_REG_ID;
916 			trans->shift = 0;
917 			trans->width = part;
918 			item->mapnum++;
919 			done_bits -= part;
920 		}
921 		return 0;
922 	}
923 	mlx5_flex_config_sample(&node, field, item->tunnel_mode);
924 	for (i = 0; i < parser->num_samples; i++) {
925 		struct mlx5_devx_match_sample_attr *sample =
926 			&parser->devx_conf.sample[i];
927 		int32_t reg_start, reg_end;
928 		int32_t cov_start, cov_end;
929 
930 		MLX5_ASSERT(sample->flow_match_sample_en);
931 		if (!sample->flow_match_sample_en)
932 			break;
933 		node.flow_match_sample_field_base_offset =
934 			sample->flow_match_sample_field_base_offset;
935 		if (memcmp(&node, sample, sizeof(node)))
936 			continue;
937 		reg_start = (int8_t)sample->flow_match_sample_field_base_offset;
938 		reg_start *= CHAR_BIT;
939 		reg_end = reg_start + 32;
940 		if (end <= reg_start || start >= reg_end)
941 			continue;
942 		cov_start = RTE_MAX(reg_start, start);
943 		cov_end = RTE_MIN(reg_end, end);
944 		MLX5_ASSERT(cov_end > cov_start);
945 		done_bits += cov_end - cov_start;
946 		if (item->mapnum >= MLX5_FLEX_ITEM_MAPPING_NUM)
947 			return rte_flow_error_set
948 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
949 				 "too many flex item pattern translations");
950 		trans = &item->map[item->mapnum];
951 		item->mapnum++;
952 		trans->reg_id = i;
953 		trans->shift = cov_start - reg_start;
954 		trans->width = cov_end - cov_start;
955 	}
956 	if (done_bits != field->field_size) {
957 		MLX5_ASSERT(false);
958 		return rte_flow_error_set
959 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
960 			 "failed to map field to sample register");
961 	}
962 	return 0;
963 }
964 
965 /* Allocate sample registers for the specified field type and interval array. */
966 static int
967 mlx5_flex_alloc_sample(struct mlx5_flex_field_cover *cover,
968 		       struct mlx5_flex_parser_devx *parser,
969 		       struct mlx5_flex_item *item,
970 		       struct rte_flow_item_flex_field *field,
971 		       struct mlx5_hca_flex_attr *attr,
972 		       struct rte_flow_error *error)
973 {
974 	struct mlx5_devx_match_sample_attr node;
975 	uint32_t idx = 0;
976 
977 	mlx5_flex_config_sample(&node, field, item->tunnel_mode);
978 	while (idx < cover->num) {
979 		int32_t start, end;
980 
981 		/*
982 		 * Sample base offsets are in bytes, should be aligned
983 		 * to 32-bit as required by firmware for samples.
984 		 */
985 		start = RTE_ALIGN_FLOOR(cover->start[idx],
986 					sizeof(uint32_t) * CHAR_BIT);
987 		node.flow_match_sample_field_base_offset =
988 						(start / CHAR_BIT) & 0xFF;
989 		/* Allocate sample register. */
990 		if (parser->num_samples >= MLX5_GRAPH_NODE_SAMPLE_NUM ||
991 		    parser->num_samples >= attr->max_num_sample ||
992 		    parser->num_samples >= attr->max_num_prog_sample)
993 			return rte_flow_error_set
994 				(error, EINVAL,
995 				 RTE_FLOW_ERROR_TYPE_ITEM, NULL,
996 				 "no sample registers to handle all flex item fields");
997 		parser->devx_conf.sample[parser->num_samples] = node;
998 		parser->num_samples++;
999 		/* Remove or update covered intervals. */
1000 		end = start + 32;
1001 		while (idx < cover->num) {
1002 			if (end >= cover->end[idx]) {
1003 				idx++;
1004 				continue;
1005 			}
1006 			if (end > cover->start[idx])
1007 				cover->start[idx] = end;
1008 			break;
1009 		}
1010 	}
1011 	return 0;
1012 }
1013 
1014 static int
1015 mlx5_flex_translate_sample(struct mlx5_hca_flex_attr *attr,
1016 			   const struct rte_flow_item_flex_conf *conf,
1017 			   struct mlx5_flex_parser_devx *parser,
1018 			   struct mlx5_flex_item *item,
1019 			   struct rte_flow_error *error)
1020 {
1021 	struct mlx5_flex_field_cover cover;
1022 	uint32_t i, j;
1023 	int ret;
1024 
1025 	switch (conf->tunnel) {
1026 	case FLEX_TUNNEL_MODE_SINGLE:
1027 		/* Fallthrough */
1028 	case FLEX_TUNNEL_MODE_OUTER:
1029 		/* Fallthrough */
1030 	case FLEX_TUNNEL_MODE_INNER:
1031 		/* Fallthrough */
1032 	case FLEX_TUNNEL_MODE_MULTI:
1033 		/* Fallthrough */
1034 	case FLEX_TUNNEL_MODE_TUNNEL:
1035 		break;
1036 	default:
1037 		return rte_flow_error_set
1038 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1039 			 "unrecognized tunnel mode");
1040 	}
1041 	item->tunnel_mode = conf->tunnel;
1042 	if (conf->nb_samples > MLX5_FLEX_ITEM_MAPPING_NUM)
1043 		return rte_flow_error_set
1044 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1045 			 "sample field number exceeds limit");
1046 	/*
1047 	 * The application can specify fields smaller or bigger than 32 bits
1048 	 * covered with single sample register and it can specify field
1049 	 * offsets in any order.
1050 	 *
1051 	 * Gather all similar fields together, build array of bit intervals
1052 	 * in ascending order and try to cover with the smallest set of sample
1053 	 * registers.
1054 	 */
1055 	memset(&cover, 0, sizeof(cover));
1056 	for (i = 0; i < conf->nb_samples; i++) {
1057 		struct rte_flow_item_flex_field *fl = conf->sample_data + i;
1058 
1059 		/* Check whether field was covered in the previous iteration. */
1060 		if (cover.mapped[i / CHAR_BIT] & (1u << (i % CHAR_BIT)))
1061 			continue;
1062 		if (fl->field_mode == FIELD_MODE_DUMMY)
1063 			continue;
1064 		/* Build an interval array for the field and similar ones */
1065 		cover.num = 0;
1066 		/* Add the first field to array unconditionally. */
1067 		ret = mlx5_flex_cover_sample(&cover, fl, NULL, attr, error);
1068 		if (ret < 0)
1069 			return ret;
1070 		MLX5_ASSERT(ret > 0);
1071 		cover.mapped[i / CHAR_BIT] |= 1u << (i % CHAR_BIT);
1072 		for (j = i + 1; j < conf->nb_samples; j++) {
1073 			struct rte_flow_item_flex_field *ft;
1074 
1075 			/* Add field to array if its type matches. */
1076 			ft = conf->sample_data + j;
1077 			ret = mlx5_flex_cover_sample(&cover, ft, fl,
1078 						     attr, error);
1079 			if (ret < 0)
1080 				return ret;
1081 			if (!ret)
1082 				continue;
1083 			cover.mapped[j / CHAR_BIT] |= 1u << (j % CHAR_BIT);
1084 		}
1085 		/* Allocate sample registers to cover array of intervals. */
1086 		ret = mlx5_flex_alloc_sample(&cover, parser, item,
1087 					     fl, attr, error);
1088 		if (ret)
1089 			return ret;
1090 	}
1091 	/* Build the item pattern translating data on flow creation. */
1092 	item->mapnum = 0;
1093 	memset(&item->map, 0, sizeof(item->map));
1094 	for (i = 0; i < conf->nb_samples; i++) {
1095 		struct rte_flow_item_flex_field *fl = conf->sample_data + i;
1096 
1097 		ret = mlx5_flex_map_sample(fl, parser, item, error);
1098 		if (ret) {
1099 			MLX5_ASSERT(false);
1100 			return ret;
1101 		}
1102 	}
1103 	if (conf->tunnel == FLEX_TUNNEL_MODE_MULTI) {
1104 		/*
1105 		 * In FLEX_TUNNEL_MODE_MULTI tunnel mode PMD creates 2 sets
1106 		 * of samples. The first set is for outer and the second set
1107 		 * for inner flex flow item. Outer and inner samples differ
1108 		 * only in tunnel_mode.
1109 		 */
1110 		if (parser->num_samples > MLX5_GRAPH_NODE_SAMPLE_NUM / 2)
1111 			return rte_flow_error_set
1112 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1113 				 "no sample registers for inner");
1114 		rte_memcpy(parser->devx_conf.sample + parser->num_samples,
1115 			   parser->devx_conf.sample,
1116 			   parser->num_samples *
1117 					sizeof(parser->devx_conf.sample[0]));
1118 		for (i = 0; i < parser->num_samples; i++) {
1119 			struct mlx5_devx_match_sample_attr *sm = i +
1120 				parser->devx_conf.sample + parser->num_samples;
1121 
1122 			sm->flow_match_sample_tunnel_mode =
1123 						MLX5_GRAPH_SAMPLE_TUNNEL_INNER;
1124 		}
1125 		parser->num_samples *= 2;
1126 	}
1127 	return 0;
1128 }
1129 
1130 static int
1131 mlx5_flex_arc_type(enum rte_flow_item_type type, int in)
1132 {
1133 	switch (type) {
1134 	case RTE_FLOW_ITEM_TYPE_ETH:
1135 		return  MLX5_GRAPH_ARC_NODE_MAC;
1136 	case RTE_FLOW_ITEM_TYPE_IPV4:
1137 		return in ? MLX5_GRAPH_ARC_NODE_IP : MLX5_GRAPH_ARC_NODE_IPV4;
1138 	case RTE_FLOW_ITEM_TYPE_IPV6:
1139 		return in ? MLX5_GRAPH_ARC_NODE_IP : MLX5_GRAPH_ARC_NODE_IPV6;
1140 	case RTE_FLOW_ITEM_TYPE_UDP:
1141 		return MLX5_GRAPH_ARC_NODE_UDP;
1142 	case RTE_FLOW_ITEM_TYPE_TCP:
1143 		return MLX5_GRAPH_ARC_NODE_TCP;
1144 	case RTE_FLOW_ITEM_TYPE_MPLS:
1145 		return MLX5_GRAPH_ARC_NODE_MPLS;
1146 	case RTE_FLOW_ITEM_TYPE_GRE:
1147 		return MLX5_GRAPH_ARC_NODE_GRE;
1148 	case RTE_FLOW_ITEM_TYPE_GENEVE:
1149 		return MLX5_GRAPH_ARC_NODE_GENEVE;
1150 	case RTE_FLOW_ITEM_TYPE_VXLAN_GPE:
1151 		return MLX5_GRAPH_ARC_NODE_VXLAN_GPE;
1152 	case RTE_FLOW_ITEM_TYPE_ESP:
1153 		return MLX5_GRAPH_ARC_NODE_IPSEC_ESP;
1154 	default:
1155 		return -EINVAL;
1156 	}
1157 }
1158 
1159 static int
1160 mlx5_flex_arc_in_eth(const struct rte_flow_item *item,
1161 		     struct rte_flow_error *error)
1162 {
1163 	const struct rte_flow_item_eth *spec = item->spec;
1164 	const struct rte_flow_item_eth *mask = item->mask;
1165 	struct rte_flow_item_eth eth = { .hdr.ether_type = RTE_BE16(0xFFFF) };
1166 
1167 	if (memcmp(mask, &eth, sizeof(struct rte_flow_item_eth))) {
1168 		return rte_flow_error_set
1169 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item,
1170 			 "invalid eth item mask");
1171 	}
1172 	return rte_be_to_cpu_16(spec->hdr.ether_type);
1173 }
1174 
1175 static int
1176 mlx5_flex_arc_in_udp(const struct rte_flow_item *item,
1177 		     struct rte_flow_error *error)
1178 {
1179 	const struct rte_flow_item_udp *spec = item->spec;
1180 	const struct rte_flow_item_udp *mask = item->mask;
1181 	struct rte_flow_item_udp udp = { .hdr.dst_port = RTE_BE16(0xFFFF) };
1182 
1183 	if (memcmp(mask, &udp, sizeof(struct rte_flow_item_udp))) {
1184 		return rte_flow_error_set
1185 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item,
1186 			 "invalid eth item mask");
1187 	}
1188 	return rte_be_to_cpu_16(spec->hdr.dst_port);
1189 }
1190 
1191 static int
1192 mlx5_flex_arc_in_ipv4(const struct rte_flow_item *item,
1193 		      struct rte_flow_error *error)
1194 {
1195 	const struct rte_flow_item_ipv4 *spec = item->spec;
1196 	const struct rte_flow_item_ipv4 *mask = item->mask;
1197 	struct rte_flow_item_ipv4 ip = { .hdr.next_proto_id = 0xff };
1198 
1199 	if (memcmp(mask, &ip, sizeof(struct rte_flow_item_ipv4))) {
1200 		return rte_flow_error_set
1201 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item,
1202 			 "invalid ipv4 item mask, full mask is desired");
1203 	}
1204 	return spec->hdr.next_proto_id;
1205 }
1206 
1207 static int
1208 mlx5_flex_arc_in_ipv6(const struct rte_flow_item *item,
1209 		      struct rte_flow_error *error)
1210 {
1211 	const struct rte_flow_item_ipv6 *spec = item->spec;
1212 	const struct rte_flow_item_ipv6 *mask = item->mask;
1213 	struct rte_flow_item_ipv6 ip = { .hdr.proto = 0xff };
1214 
1215 	if (memcmp(mask, &ip, sizeof(struct rte_flow_item_ipv6))) {
1216 		return rte_flow_error_set
1217 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, item,
1218 			 "invalid ipv6 item mask, full mask is desired");
1219 	}
1220 	return spec->hdr.proto;
1221 }
1222 
1223 static int
1224 mlx5_flex_translate_arc_in(struct mlx5_hca_flex_attr *attr,
1225 			   const struct rte_flow_item_flex_conf *conf,
1226 			   struct mlx5_flex_parser_devx *devx,
1227 			   struct mlx5_flex_item *item,
1228 			   struct rte_flow_error *error)
1229 {
1230 	struct mlx5_devx_graph_node_attr *node = &devx->devx_conf;
1231 	uint32_t i;
1232 
1233 	RTE_SET_USED(item);
1234 	if (conf->nb_inputs > attr->max_num_arc_in)
1235 		return rte_flow_error_set
1236 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1237 			 "too many input links");
1238 	for (i = 0; i < conf->nb_inputs; i++) {
1239 		struct mlx5_devx_graph_arc_attr *arc = node->in + i;
1240 		struct rte_flow_item_flex_link *link = conf->input_link + i;
1241 		const struct rte_flow_item *rte_item = &link->item;
1242 		int arc_type;
1243 		int ret;
1244 
1245 		if (!rte_item->spec || !rte_item->mask || rte_item->last)
1246 			return rte_flow_error_set
1247 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1248 				 "invalid flex item IN arc format");
1249 		arc_type = mlx5_flex_arc_type(rte_item->type, true);
1250 		if (arc_type < 0 || !(attr->node_in & RTE_BIT32(arc_type)))
1251 			return rte_flow_error_set
1252 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1253 				 "unsupported flex item IN arc type");
1254 		arc->arc_parse_graph_node = arc_type;
1255 		arc->start_inner_tunnel = 0;
1256 		/*
1257 		 * Configure arc IN condition value. The value location depends
1258 		 * on protocol. Current FW version supports IP & UDP for IN
1259 		 * arcs only, and locations for these protocols are defined.
1260 		 * Add more protocols when available.
1261 		 */
1262 		switch (rte_item->type) {
1263 		case RTE_FLOW_ITEM_TYPE_ETH:
1264 			ret = mlx5_flex_arc_in_eth(rte_item, error);
1265 			break;
1266 		case RTE_FLOW_ITEM_TYPE_UDP:
1267 			ret = mlx5_flex_arc_in_udp(rte_item, error);
1268 			break;
1269 		case RTE_FLOW_ITEM_TYPE_IPV4:
1270 			ret = mlx5_flex_arc_in_ipv4(rte_item, error);
1271 			break;
1272 		case RTE_FLOW_ITEM_TYPE_IPV6:
1273 			ret = mlx5_flex_arc_in_ipv6(rte_item, error);
1274 			break;
1275 		default:
1276 			MLX5_ASSERT(false);
1277 			return rte_flow_error_set
1278 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1279 				 "unsupported flex item IN arc type");
1280 		}
1281 		if (ret < 0)
1282 			return ret;
1283 		arc->compare_condition_value = (uint16_t)ret;
1284 	}
1285 	return 0;
1286 }
1287 
1288 static int
1289 mlx5_flex_translate_arc_out(struct mlx5_hca_flex_attr *attr,
1290 			    const struct rte_flow_item_flex_conf *conf,
1291 			    struct mlx5_flex_parser_devx *devx,
1292 			    struct mlx5_flex_item *item,
1293 			    struct rte_flow_error *error)
1294 {
1295 	struct mlx5_devx_graph_node_attr *node = &devx->devx_conf;
1296 	bool is_tunnel = conf->tunnel == FLEX_TUNNEL_MODE_TUNNEL;
1297 	uint32_t i;
1298 
1299 	RTE_SET_USED(item);
1300 	if (conf->nb_outputs > attr->max_num_arc_out)
1301 		return rte_flow_error_set
1302 			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1303 			 "too many output links");
1304 	for (i = 0; i < conf->nb_outputs; i++) {
1305 		struct mlx5_devx_graph_arc_attr *arc = node->out + i;
1306 		struct rte_flow_item_flex_link *link = conf->output_link + i;
1307 		const struct rte_flow_item *rte_item = &link->item;
1308 		int arc_type;
1309 
1310 		if (rte_item->spec || rte_item->mask || rte_item->last)
1311 			return rte_flow_error_set
1312 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1313 				 "flex node: invalid OUT arc format");
1314 		arc_type = mlx5_flex_arc_type(rte_item->type, false);
1315 		if (arc_type < 0 || !(attr->node_out & RTE_BIT32(arc_type)))
1316 			return rte_flow_error_set
1317 				(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1318 				 "unsupported flex item OUT arc type");
1319 		arc->arc_parse_graph_node = arc_type;
1320 		arc->start_inner_tunnel = !!is_tunnel;
1321 		arc->compare_condition_value = link->next;
1322 	}
1323 	return 0;
1324 }
1325 
1326 /* Translate RTE flex item API configuration into flaex parser settings. */
1327 static int
1328 mlx5_flex_translate_conf(struct rte_eth_dev *dev,
1329 			 const struct rte_flow_item_flex_conf *conf,
1330 			 struct mlx5_flex_parser_devx *devx,
1331 			 struct mlx5_flex_item *item,
1332 			 struct rte_flow_error *error)
1333 {
1334 	struct mlx5_priv *priv = dev->data->dev_private;
1335 	struct mlx5_hca_flex_attr *attr = &priv->sh->cdev->config.hca_attr.flex;
1336 	int ret;
1337 
1338 	ret = mlx5_flex_translate_length(attr, conf, devx, error);
1339 	if (ret)
1340 		return ret;
1341 	ret = mlx5_flex_translate_next(attr, conf, devx, error);
1342 	if (ret)
1343 		return ret;
1344 	ret = mlx5_flex_translate_sample(attr, conf, devx, item, error);
1345 	if (ret)
1346 		return ret;
1347 	ret = mlx5_flex_translate_arc_in(attr, conf, devx, item, error);
1348 	if (ret)
1349 		return ret;
1350 	ret = mlx5_flex_translate_arc_out(attr, conf, devx, item, error);
1351 	if (ret)
1352 		return ret;
1353 	return 0;
1354 }
1355 
1356 /**
1357  * Create the flex item with specified configuration over the Ethernet device.
1358  *
1359  * @param dev
1360  *   Ethernet device to create flex item on.
1361  * @param[in] conf
1362  *   Flex item configuration.
1363  * @param[out] error
1364  *   Perform verbose error reporting if not NULL. PMDs initialize this
1365  *   structure in case of error only.
1366  *
1367  * @return
1368  *   Non-NULL opaque pointer on success, NULL otherwise and rte_errno is set.
1369  */
1370 struct rte_flow_item_flex_handle *
1371 flow_dv_item_create(struct rte_eth_dev *dev,
1372 		    const struct rte_flow_item_flex_conf *conf,
1373 		    struct rte_flow_error *error)
1374 {
1375 	struct mlx5_priv *priv = dev->data->dev_private;
1376 	struct mlx5_flex_parser_devx devx_config = { .devx_obj = NULL };
1377 	struct mlx5_flex_item *flex;
1378 	struct mlx5_list_entry *ent;
1379 
1380 	MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
1381 	flex = mlx5_flex_alloc(priv);
1382 	if (!flex) {
1383 		rte_flow_error_set(error, ENOMEM,
1384 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1385 				   "too many flex items created on the port");
1386 		return NULL;
1387 	}
1388 	if (mlx5_flex_translate_conf(dev, conf, &devx_config, flex, error))
1389 		goto error;
1390 	ent = mlx5_list_register(priv->sh->flex_parsers_dv, &devx_config);
1391 	if (!ent) {
1392 		rte_flow_error_set(error, ENOMEM,
1393 				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
1394 				   "flex item creation failure");
1395 		goto error;
1396 	}
1397 	flex->devx_fp = container_of(ent, struct mlx5_flex_parser_devx, entry);
1398 	/* Mark initialized flex item valid. */
1399 	rte_atomic_fetch_add_explicit(&flex->refcnt, 1, rte_memory_order_release);
1400 	return (struct rte_flow_item_flex_handle *)flex;
1401 
1402 error:
1403 	mlx5_flex_free(priv, flex);
1404 	return NULL;
1405 }
1406 
1407 /**
1408  * Release the flex item on the specified Ethernet device.
1409  *
1410  * @param dev
1411  *   Ethernet device to destroy flex item on.
1412  * @param[in] handle
1413  *   Handle of the item existing on the specified device.
1414  * @param[out] error
1415  *   Perform verbose error reporting if not NULL. PMDs initialize this
1416  *   structure in case of error only.
1417  *
1418  * @return
1419  *   0 on success, a negative errno value otherwise and rte_errno is set.
1420  */
1421 int
1422 flow_dv_item_release(struct rte_eth_dev *dev,
1423 		     const struct rte_flow_item_flex_handle *handle,
1424 		     struct rte_flow_error *error)
1425 {
1426 	struct mlx5_priv *priv = dev->data->dev_private;
1427 	struct mlx5_flex_item *flex =
1428 		(struct mlx5_flex_item *)(uintptr_t)handle;
1429 	uint32_t old_refcnt = 1;
1430 	int rc;
1431 
1432 	MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY);
1433 	rte_spinlock_lock(&priv->flex_item_sl);
1434 	if (mlx5_flex_index(priv, flex) < 0) {
1435 		rte_spinlock_unlock(&priv->flex_item_sl);
1436 		return rte_flow_error_set(error, EINVAL,
1437 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1438 					  "invalid flex item handle value");
1439 	}
1440 	if (!rte_atomic_compare_exchange_strong_explicit(&flex->refcnt, &old_refcnt, 0,
1441 					 rte_memory_order_acquire, rte_memory_order_relaxed)) {
1442 		rte_spinlock_unlock(&priv->flex_item_sl);
1443 		return rte_flow_error_set(error, EBUSY,
1444 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1445 					  "flex item has flow references");
1446 	}
1447 	/* Flex item is marked as invalid, we can leave locked section. */
1448 	rte_spinlock_unlock(&priv->flex_item_sl);
1449 	MLX5_ASSERT(flex->devx_fp);
1450 	rc = mlx5_list_unregister(priv->sh->flex_parsers_dv,
1451 				  &flex->devx_fp->entry);
1452 	flex->devx_fp = NULL;
1453 	mlx5_flex_free(priv, flex);
1454 	if (rc < 0)
1455 		return rte_flow_error_set(error, EBUSY,
1456 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
1457 					  "flex item release failure");
1458 	return 0;
1459 }
1460 
1461 /* DevX flex parser list callbacks. */
1462 struct mlx5_list_entry *
1463 mlx5_flex_parser_create_cb(void *list_ctx, void *ctx)
1464 {
1465 	struct mlx5_dev_ctx_shared *sh = list_ctx;
1466 	struct mlx5_flex_parser_devx *fp, *conf = ctx;
1467 	uint32_t i;
1468 	uint8_t sample_info = sh->cdev->config.hca_attr.flex.query_match_sample_info;
1469 	int ret;
1470 
1471 	fp = mlx5_malloc(MLX5_MEM_ZERO,	sizeof(struct mlx5_flex_parser_devx),
1472 			 0, SOCKET_ID_ANY);
1473 	if (!fp)
1474 		return NULL;
1475 	/* Copy the requested configurations. */
1476 	fp->num_samples = conf->num_samples;
1477 	memcpy(&fp->devx_conf, &conf->devx_conf, sizeof(fp->devx_conf));
1478 	/* Create DevX flex parser. */
1479 	fp->devx_obj = mlx5_devx_cmd_create_flex_parser(sh->cdev->ctx,
1480 							&fp->devx_conf);
1481 	if (!fp->devx_obj)
1482 		goto error;
1483 	/* Query the firmware assigned sample ids. */
1484 	ret = mlx5_devx_cmd_query_parse_samples(fp->devx_obj,
1485 						fp->sample_ids,
1486 						fp->num_samples,
1487 						&fp->anchor_id);
1488 	if (ret)
1489 		goto error;
1490 	/* Query sample information per ID. */
1491 	for (i = 0; i < fp->num_samples && sample_info; i++) {
1492 		ret = mlx5_devx_cmd_match_sample_info_query(sh->cdev->ctx, fp->sample_ids[i],
1493 							    &fp->sample_info[i]);
1494 		if (ret)
1495 			goto error;
1496 	}
1497 	DRV_LOG(DEBUG, "DEVx flex parser %p created, samples num: %u",
1498 		(const void *)fp, fp->num_samples);
1499 	return &fp->entry;
1500 error:
1501 	if (fp->devx_obj)
1502 		mlx5_devx_cmd_destroy((void *)(uintptr_t)fp->devx_obj);
1503 	if (fp)
1504 		mlx5_free(fp);
1505 	return NULL;
1506 }
1507 
1508 int
1509 mlx5_flex_parser_match_cb(void *list_ctx,
1510 			  struct mlx5_list_entry *iter, void *ctx)
1511 {
1512 	struct mlx5_flex_parser_devx *fp =
1513 		container_of(iter, struct mlx5_flex_parser_devx, entry);
1514 	struct mlx5_flex_parser_devx *org =
1515 		container_of(ctx, struct mlx5_flex_parser_devx, entry);
1516 
1517 	RTE_SET_USED(list_ctx);
1518 	return !iter || !ctx || memcmp(&fp->devx_conf,
1519 				       &org->devx_conf,
1520 				       sizeof(fp->devx_conf));
1521 }
1522 
1523 void
1524 mlx5_flex_parser_remove_cb(void *list_ctx, struct mlx5_list_entry *entry)
1525 {
1526 	struct mlx5_flex_parser_devx *fp =
1527 		container_of(entry, struct mlx5_flex_parser_devx, entry);
1528 
1529 	RTE_SET_USED(list_ctx);
1530 	MLX5_ASSERT(fp->devx_obj);
1531 	claim_zero(mlx5_devx_cmd_destroy(fp->devx_obj));
1532 	DRV_LOG(DEBUG, "DEVx flex parser %p destroyed", (const void *)fp);
1533 	mlx5_free(entry);
1534 }
1535 
1536 struct mlx5_list_entry *
1537 mlx5_flex_parser_clone_cb(void *list_ctx,
1538 			  struct mlx5_list_entry *entry, void *ctx)
1539 {
1540 	struct mlx5_flex_parser_devx *fp;
1541 
1542 	RTE_SET_USED(list_ctx);
1543 	RTE_SET_USED(entry);
1544 	fp = mlx5_malloc(0, sizeof(struct mlx5_flex_parser_devx),
1545 			 0, SOCKET_ID_ANY);
1546 	if (!fp)
1547 		return NULL;
1548 	memcpy(fp, ctx, sizeof(struct mlx5_flex_parser_devx));
1549 	return &fp->entry;
1550 }
1551 
1552 void
1553 mlx5_flex_parser_clone_free_cb(void *list_ctx, struct mlx5_list_entry *entry)
1554 {
1555 	struct mlx5_flex_parser_devx *fp =
1556 		container_of(entry, struct mlx5_flex_parser_devx, entry);
1557 	RTE_SET_USED(list_ctx);
1558 	mlx5_free(fp);
1559 }
1560