xref: /dpdk/drivers/net/mlx5/mlx5_flow_geneve.c (revision 1caa89ec1891779c234047880a1bbc12b28569c1)
1f5177bdcSMichael Baum /* SPDX-License-Identifier: BSD-3-Clause
2f5177bdcSMichael Baum  * Copyright (c) 2022 NVIDIA Corporation & Affiliates
3f5177bdcSMichael Baum  */
4f5177bdcSMichael Baum 
5f5177bdcSMichael Baum #include <rte_flow.h>
6f5177bdcSMichael Baum 
7f5177bdcSMichael Baum #include <mlx5_malloc.h>
8f5177bdcSMichael Baum #include <stdint.h>
9f5177bdcSMichael Baum 
10f5177bdcSMichael Baum #include "generic/rte_byteorder.h"
11f5177bdcSMichael Baum #include "mlx5.h"
12f5177bdcSMichael Baum #include "mlx5_flow.h"
13f5177bdcSMichael Baum #include "rte_pmd_mlx5.h"
14f5177bdcSMichael Baum 
15f5177bdcSMichael Baum #if defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H)
16f5177bdcSMichael Baum 
17f5177bdcSMichael Baum #define MAX_GENEVE_OPTION_DATA_SIZE 32
18f5177bdcSMichael Baum #define MAX_GENEVE_OPTION_TOTAL_DATA_SIZE \
19f5177bdcSMichael Baum 		(MAX_GENEVE_OPTION_DATA_SIZE * MAX_GENEVE_OPTIONS_RESOURCES)
20f5177bdcSMichael Baum 
212a39dda7SMichael Baum #define INVALID_SAMPLE_ID (UINT8_MAX)
222a39dda7SMichael Baum 
23f5177bdcSMichael Baum /**
24f5177bdcSMichael Baum  * Single DW inside GENEVE TLV option.
25f5177bdcSMichael Baum  */
26f5177bdcSMichael Baum struct mlx5_geneve_tlv_resource {
27f5177bdcSMichael Baum 	struct mlx5_devx_obj *obj; /* FW object returned in parser creation. */
28f5177bdcSMichael Baum 	uint32_t modify_field; /* Modify field ID for this DW. */
29f5177bdcSMichael Baum 	uint8_t offset; /* Offset used in obj creation, from option start. */
30f5177bdcSMichael Baum };
31f5177bdcSMichael Baum 
32f5177bdcSMichael Baum /**
33f5177bdcSMichael Baum  * Single GENEVE TLV option context.
34f5177bdcSMichael Baum  * May include some FW objects for different DWs in same option.
35f5177bdcSMichael Baum  */
36f5177bdcSMichael Baum struct mlx5_geneve_tlv_option {
37f5177bdcSMichael Baum 	uint8_t type;
38f5177bdcSMichael Baum 	uint16_t class;
39f5177bdcSMichael Baum 	uint8_t class_mode;
40f5177bdcSMichael Baum 	struct mlx5_hl_data match_data[MAX_GENEVE_OPTION_DATA_SIZE];
41f5177bdcSMichael Baum 	uint32_t match_data_size;
42f5177bdcSMichael Baum 	struct mlx5_hl_data hl_ok_bit;
43f5177bdcSMichael Baum 	struct mlx5_geneve_tlv_resource resources[MAX_GENEVE_OPTIONS_RESOURCES];
44f5177bdcSMichael Baum 	RTE_ATOMIC(uint32_t) refcnt;
45f5177bdcSMichael Baum };
46f5177bdcSMichael Baum 
47f5177bdcSMichael Baum /**
48f5177bdcSMichael Baum  * List of GENEVE TLV options.
49f5177bdcSMichael Baum  */
50f5177bdcSMichael Baum struct mlx5_geneve_tlv_options {
51f5177bdcSMichael Baum 	/* List of configured GENEVE TLV options. */
52f5177bdcSMichael Baum 	struct mlx5_geneve_tlv_option options[MAX_GENEVE_OPTIONS_RESOURCES];
53f5177bdcSMichael Baum 	/*
54f5177bdcSMichael Baum 	 * Copy of list given in parser creation, use to compare with new
55f5177bdcSMichael Baum 	 * configuration.
56f5177bdcSMichael Baum 	 */
57f5177bdcSMichael Baum 	struct rte_pmd_mlx5_geneve_tlv spec[MAX_GENEVE_OPTIONS_RESOURCES];
58f5177bdcSMichael Baum 	rte_be32_t buffer[MAX_GENEVE_OPTION_TOTAL_DATA_SIZE];
59f5177bdcSMichael Baum 	uint8_t nb_options; /* Number entries in above lists. */
60f5177bdcSMichael Baum 	RTE_ATOMIC(uint32_t) refcnt;
61f5177bdcSMichael Baum };
62f5177bdcSMichael Baum 
63f5177bdcSMichael Baum /**
64232b349bSMichael Baum  * Check if type and class is matching to given GENEVE TLV option.
65232b349bSMichael Baum  *
66232b349bSMichael Baum  * @param type
67232b349bSMichael Baum  *   GENEVE option type.
68232b349bSMichael Baum  * @param class
69232b349bSMichael Baum  *   GENEVE option class.
70232b349bSMichael Baum  * @param option
71232b349bSMichael Baum  *   Pointer to GENEVE TLV option structure.
72232b349bSMichael Baum  *
73232b349bSMichael Baum  * @return
74232b349bSMichael Baum  *   True if this type and class match to this option, false otherwise.
75232b349bSMichael Baum  */
76232b349bSMichael Baum static inline bool
option_match_type_and_class(uint8_t type,uint16_t class,struct mlx5_geneve_tlv_option * option)77232b349bSMichael Baum option_match_type_and_class(uint8_t type, uint16_t class,
78232b349bSMichael Baum 			    struct mlx5_geneve_tlv_option *option)
79232b349bSMichael Baum {
80232b349bSMichael Baum 	if (type != option->type)
81232b349bSMichael Baum 		return false;
82232b349bSMichael Baum 	if (option->class_mode == 1 && option->class != class)
83232b349bSMichael Baum 		return false;
84232b349bSMichael Baum 	return true;
85232b349bSMichael Baum }
86232b349bSMichael Baum 
87232b349bSMichael Baum /**
88232b349bSMichael Baum  * Get GENEVE TLV option matching to given type and class.
89232b349bSMichael Baum  *
90232b349bSMichael Baum  * @param priv
91232b349bSMichael Baum  *   Pointer to port's private data.
92232b349bSMichael Baum  * @param type
93232b349bSMichael Baum  *   GENEVE option type.
94232b349bSMichael Baum  * @param class
95232b349bSMichael Baum  *   GENEVE option class.
96232b349bSMichael Baum  *
97232b349bSMichael Baum  * @return
98232b349bSMichael Baum  *   Pointer to option structure if exist, NULL otherwise and rte_errno is set.
99232b349bSMichael Baum  */
100232b349bSMichael Baum static struct mlx5_geneve_tlv_option *
mlx5_geneve_tlv_option_get(const struct mlx5_priv * priv,uint8_t type,uint16_t class)101232b349bSMichael Baum mlx5_geneve_tlv_option_get(const struct mlx5_priv *priv, uint8_t type,
102232b349bSMichael Baum 			   uint16_t class)
103232b349bSMichael Baum {
104232b349bSMichael Baum 	struct mlx5_geneve_tlv_options *options;
105232b349bSMichael Baum 	uint8_t i;
106232b349bSMichael Baum 
107232b349bSMichael Baum 	if (priv->tlv_options == NULL) {
108232b349bSMichael Baum 		DRV_LOG(ERR,
109232b349bSMichael Baum 			"Port %u doesn't have configured GENEVE TLV options.",
110232b349bSMichael Baum 			priv->dev_data->port_id);
111232b349bSMichael Baum 		rte_errno = EINVAL;
112232b349bSMichael Baum 		return NULL;
113232b349bSMichael Baum 	}
114232b349bSMichael Baum 	options = priv->tlv_options;
115232b349bSMichael Baum 	MLX5_ASSERT(options != NULL);
116232b349bSMichael Baum 	for (i = 0; i < options->nb_options; ++i) {
117232b349bSMichael Baum 		struct mlx5_geneve_tlv_option *option = &options->options[i];
118232b349bSMichael Baum 
119232b349bSMichael Baum 		if (option_match_type_and_class(type, class, option))
120232b349bSMichael Baum 			return option;
121232b349bSMichael Baum 	}
122232b349bSMichael Baum 	DRV_LOG(ERR, "TLV option type %u class %u doesn't exist.", type, class);
123232b349bSMichael Baum 	rte_errno = ENOENT;
124232b349bSMichael Baum 	return NULL;
125232b349bSMichael Baum }
126232b349bSMichael Baum 
127232b349bSMichael Baum int
mlx5_get_geneve_hl_data(const void * dr_ctx,uint8_t type,uint16_t class,struct mlx5_hl_data ** const hl_ok_bit,uint8_t * num_of_dws,struct mlx5_hl_data ** const hl_dws,bool * ok_bit_on_class)128232b349bSMichael Baum mlx5_get_geneve_hl_data(const void *dr_ctx, uint8_t type, uint16_t class,
129232b349bSMichael Baum 			struct mlx5_hl_data ** const hl_ok_bit,
130232b349bSMichael Baum 			uint8_t *num_of_dws,
131232b349bSMichael Baum 			struct mlx5_hl_data ** const hl_dws,
132232b349bSMichael Baum 			bool *ok_bit_on_class)
133232b349bSMichael Baum {
134232b349bSMichael Baum 	uint16_t port_id;
135232b349bSMichael Baum 
136232b349bSMichael Baum 	MLX5_ETH_FOREACH_DEV(port_id, NULL) {
137232b349bSMichael Baum 		struct mlx5_priv *priv;
138232b349bSMichael Baum 		struct mlx5_geneve_tlv_option *option;
139232b349bSMichael Baum 
140232b349bSMichael Baum 		priv = rte_eth_devices[port_id].data->dev_private;
141232b349bSMichael Baum 		if (priv->dr_ctx != dr_ctx)
142232b349bSMichael Baum 			continue;
143232b349bSMichael Baum 		/* Find specific option inside list. */
144232b349bSMichael Baum 		option = mlx5_geneve_tlv_option_get(priv, type, class);
145232b349bSMichael Baum 		if (option == NULL)
146232b349bSMichael Baum 			return -rte_errno;
147232b349bSMichael Baum 		*hl_ok_bit = &option->hl_ok_bit;
148232b349bSMichael Baum 		*hl_dws = option->match_data;
149232b349bSMichael Baum 		*num_of_dws = option->match_data_size;
150232b349bSMichael Baum 		*ok_bit_on_class = !!(option->class_mode == 1);
151232b349bSMichael Baum 		return 0;
152232b349bSMichael Baum 	}
153232b349bSMichael Baum 	DRV_LOG(ERR, "DR CTX %p doesn't belong to any DPDK port.", dr_ctx);
154232b349bSMichael Baum 	return -EINVAL;
155232b349bSMichael Baum }
156232b349bSMichael Baum 
157232b349bSMichael Baum /**
15885738168SMichael Baum  * Calculate total data size.
15985738168SMichael Baum  *
16085738168SMichael Baum  * @param[in] priv
16185738168SMichael Baum  *   Pointer to port's private data.
16285738168SMichael Baum  * @param[in] geneve_opt
16385738168SMichael Baum  *   Pointer to GENEVE option item structure.
16485738168SMichael Baum  * @param[out] error
16585738168SMichael Baum  *   Pointer to error structure.
16685738168SMichael Baum  *
16785738168SMichael Baum  * @return
16885738168SMichael Baum  *   0 on success, a negative errno value otherwise and rte_errno is set.
16985738168SMichael Baum  */
17085738168SMichael Baum int
mlx5_flow_geneve_tlv_option_validate(struct mlx5_priv * priv,const struct rte_flow_item * geneve_opt,struct rte_flow_error * error)17185738168SMichael Baum mlx5_flow_geneve_tlv_option_validate(struct mlx5_priv *priv,
17285738168SMichael Baum 				     const struct rte_flow_item *geneve_opt,
17385738168SMichael Baum 				     struct rte_flow_error *error)
17485738168SMichael Baum {
17585738168SMichael Baum 	const struct rte_flow_item_geneve_opt *spec = geneve_opt->spec;
17685738168SMichael Baum 	const struct rte_flow_item_geneve_opt *mask = geneve_opt->mask;
17785738168SMichael Baum 	struct mlx5_geneve_tlv_option *option;
17885738168SMichael Baum 
17985738168SMichael Baum 	option = mlx5_geneve_tlv_option_get(priv, spec->option_type, spec->option_class);
18085738168SMichael Baum 	if (option == NULL)
18185738168SMichael Baum 		return rte_flow_error_set(error, rte_errno,
18285738168SMichael Baum 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
18385738168SMichael Baum 					  "Unregistered GENEVE option");
18485738168SMichael Baum 	if (mask->option_type != UINT8_MAX)
18585738168SMichael Baum 		return rte_flow_error_set(error, EINVAL,
18685738168SMichael Baum 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
18785738168SMichael Baum 					  "GENEVE option type must be fully masked");
18885738168SMichael Baum 	if (option->class_mode == 1 && mask->option_class != UINT16_MAX)
18985738168SMichael Baum 		return rte_flow_error_set(error, EINVAL,
19085738168SMichael Baum 					  RTE_FLOW_ERROR_TYPE_ITEM, NULL,
19185738168SMichael Baum 					  "GENEVE option class must be fully masked");
19285738168SMichael Baum 	return 0;
19385738168SMichael Baum }
19485738168SMichael Baum 
19585738168SMichael Baum /**
19685738168SMichael Baum  * Register single GENEVE TLV option as used by pattern template.
19785738168SMichael Baum  *
19885738168SMichael Baum  * @param[in] priv
19985738168SMichael Baum  *   Pointer to port's private data.
20085738168SMichael Baum  * @param[in] spec
20185738168SMichael Baum  *   Pointer to GENEVE option item structure.
20285738168SMichael Baum  * @param[out] mng
20385738168SMichael Baum  *   Pointer to GENEVE option manager.
20485738168SMichael Baum  *
20585738168SMichael Baum  * @return
20685738168SMichael Baum  *   0 on success, a negative errno value otherwise and rte_errno is set.
20785738168SMichael Baum  */
20885738168SMichael Baum int
mlx5_geneve_tlv_option_register(struct mlx5_priv * priv,const struct rte_flow_item_geneve_opt * spec,struct mlx5_geneve_tlv_options_mng * mng)20985738168SMichael Baum mlx5_geneve_tlv_option_register(struct mlx5_priv *priv,
21085738168SMichael Baum 				const struct rte_flow_item_geneve_opt *spec,
21185738168SMichael Baum 				struct mlx5_geneve_tlv_options_mng *mng)
21285738168SMichael Baum {
21385738168SMichael Baum 	struct mlx5_geneve_tlv_option *option;
21485738168SMichael Baum 
21585738168SMichael Baum 	option = mlx5_geneve_tlv_option_get(priv, spec->option_type, spec->option_class);
21685738168SMichael Baum 	if (option == NULL)
21785738168SMichael Baum 		return -rte_errno;
21885738168SMichael Baum 	/* Increase the option reference counter. */
21985738168SMichael Baum 	rte_atomic_fetch_add_explicit(&option->refcnt, 1,
22085738168SMichael Baum 				      rte_memory_order_relaxed);
22185738168SMichael Baum 	/* Update the manager with option information. */
22285738168SMichael Baum 	mng->options[mng->nb_options].opt_type = spec->option_type;
22385738168SMichael Baum 	mng->options[mng->nb_options].opt_class = spec->option_class;
22485738168SMichael Baum 	mng->nb_options++;
22585738168SMichael Baum 	return 0;
22685738168SMichael Baum }
22785738168SMichael Baum 
22885738168SMichael Baum /**
22985738168SMichael Baum  * Unregister all GENEVE TLV options used by pattern template.
23085738168SMichael Baum  *
23185738168SMichael Baum  * @param[in] priv
23285738168SMichael Baum  *   Pointer to port's private data.
23385738168SMichael Baum  * @param[in] mng
23485738168SMichael Baum  *   Pointer to GENEVE option manager.
23585738168SMichael Baum  */
23685738168SMichael Baum void
mlx5_geneve_tlv_options_unregister(struct mlx5_priv * priv,struct mlx5_geneve_tlv_options_mng * mng)23785738168SMichael Baum mlx5_geneve_tlv_options_unregister(struct mlx5_priv *priv,
23885738168SMichael Baum 				   struct mlx5_geneve_tlv_options_mng *mng)
23985738168SMichael Baum {
24085738168SMichael Baum 	struct mlx5_geneve_tlv_option *option;
24185738168SMichael Baum 	uint8_t i;
24285738168SMichael Baum 
24385738168SMichael Baum 	for (i = 0; i < mng->nb_options; ++i) {
24485738168SMichael Baum 		option = mlx5_geneve_tlv_option_get(priv,
24585738168SMichael Baum 						    mng->options[i].opt_type,
24685738168SMichael Baum 						    mng->options[i].opt_class);
24785738168SMichael Baum 		MLX5_ASSERT(option != NULL);
24885738168SMichael Baum 		/* Decrease the option reference counter. */
24985738168SMichael Baum 		rte_atomic_fetch_sub_explicit(&option->refcnt, 1,
25085738168SMichael Baum 					      rte_memory_order_relaxed);
25185738168SMichael Baum 		mng->options[i].opt_type = 0;
25285738168SMichael Baum 		mng->options[i].opt_class = 0;
25385738168SMichael Baum 	}
25485738168SMichael Baum 	mng->nb_options = 0;
25585738168SMichael Baum }
25685738168SMichael Baum 
25785738168SMichael Baum /**
258*1caa89ecSMichael Baum  * Get single DW resource from given option.
259*1caa89ecSMichael Baum  *
260*1caa89ecSMichael Baum  * @param option
261*1caa89ecSMichael Baum  *   Pointer to single GENEVE TLV option.
262*1caa89ecSMichael Baum  * @param offset
263*1caa89ecSMichael Baum  *   Offset of DW related to option start.
264*1caa89ecSMichael Baum  *
265*1caa89ecSMichael Baum  * @return
266*1caa89ecSMichael Baum  *   DW resource on success, NULL otherwise and rte_errno is set.
267*1caa89ecSMichael Baum  */
268*1caa89ecSMichael Baum static struct mlx5_geneve_tlv_resource *
mlx5_geneve_tlv_option_get_resource_by_offset(struct mlx5_geneve_tlv_option * option,uint8_t offset)269*1caa89ecSMichael Baum mlx5_geneve_tlv_option_get_resource_by_offset(struct mlx5_geneve_tlv_option *option,
270*1caa89ecSMichael Baum 					      uint8_t offset)
271*1caa89ecSMichael Baum {
272*1caa89ecSMichael Baum 	uint8_t i;
273*1caa89ecSMichael Baum 
274*1caa89ecSMichael Baum 	for (i = 0; option->resources[i].obj != NULL; ++i) {
275*1caa89ecSMichael Baum 		if (option->resources[i].offset < offset)
276*1caa89ecSMichael Baum 			continue;
277*1caa89ecSMichael Baum 		if (option->resources[i].offset == offset)
278*1caa89ecSMichael Baum 			return &option->resources[i];
279*1caa89ecSMichael Baum 		break;
280*1caa89ecSMichael Baum 	}
281*1caa89ecSMichael Baum 	DRV_LOG(ERR, "The DW in offset %u wasn't configured.", offset);
282*1caa89ecSMichael Baum 	rte_errno = EINVAL;
283*1caa89ecSMichael Baum 	return NULL;
284*1caa89ecSMichael Baum }
285*1caa89ecSMichael Baum 
286*1caa89ecSMichael Baum int
mlx5_get_geneve_option_modify_field_id(const void * dr_ctx,uint8_t type,uint16_t class,uint8_t dw_offset)287*1caa89ecSMichael Baum mlx5_get_geneve_option_modify_field_id(const void *dr_ctx, uint8_t type,
288*1caa89ecSMichael Baum 				       uint16_t class, uint8_t dw_offset)
289*1caa89ecSMichael Baum {
290*1caa89ecSMichael Baum 	uint16_t port_id;
291*1caa89ecSMichael Baum 
292*1caa89ecSMichael Baum 	MLX5_ETH_FOREACH_DEV(port_id, NULL) {
293*1caa89ecSMichael Baum 		struct mlx5_priv *priv;
294*1caa89ecSMichael Baum 		struct mlx5_geneve_tlv_option *option;
295*1caa89ecSMichael Baum 		struct mlx5_geneve_tlv_resource *resource;
296*1caa89ecSMichael Baum 
297*1caa89ecSMichael Baum 		priv = rte_eth_devices[port_id].data->dev_private;
298*1caa89ecSMichael Baum 		if (priv->dr_ctx != dr_ctx)
299*1caa89ecSMichael Baum 			continue;
300*1caa89ecSMichael Baum 		/* Find specific option inside list. */
301*1caa89ecSMichael Baum 		option = mlx5_geneve_tlv_option_get(priv, type, class);
302*1caa89ecSMichael Baum 		if (option == NULL)
303*1caa89ecSMichael Baum 			return -rte_errno;
304*1caa89ecSMichael Baum 		/* Find specific FW object inside option resources. */
305*1caa89ecSMichael Baum 		resource = mlx5_geneve_tlv_option_get_resource_by_offset(option,
306*1caa89ecSMichael Baum 									 dw_offset);
307*1caa89ecSMichael Baum 		if (resource == NULL)
308*1caa89ecSMichael Baum 			return -rte_errno;
309*1caa89ecSMichael Baum 		return resource->modify_field;
310*1caa89ecSMichael Baum 	}
311*1caa89ecSMichael Baum 	DRV_LOG(ERR, "DR CTX %p doesn't belong to any DPDK port.", dr_ctx);
312*1caa89ecSMichael Baum 	rte_errno = EINVAL;
313*1caa89ecSMichael Baum 	return -rte_errno;
314*1caa89ecSMichael Baum }
315*1caa89ecSMichael Baum 
316*1caa89ecSMichael Baum /**
317*1caa89ecSMichael Baum  * Get modify field ID for single DW inside configured GENEVE TLV option.
318*1caa89ecSMichael Baum  *
319*1caa89ecSMichael Baum  * @param[in] priv
320*1caa89ecSMichael Baum  *   Pointer to port's private data.
321*1caa89ecSMichael Baum  * @param[in] data
322*1caa89ecSMichael Baum  *   Pointer to modify field data structure.
323*1caa89ecSMichael Baum  *
324*1caa89ecSMichael Baum  * @return
325*1caa89ecSMichael Baum  *   Modify field ID on success, negative errno otherwise and rte_errno is set.
326*1caa89ecSMichael Baum  */
327*1caa89ecSMichael Baum int
mlx5_geneve_opt_modi_field_get(struct mlx5_priv * priv,const struct rte_flow_field_data * data)328*1caa89ecSMichael Baum mlx5_geneve_opt_modi_field_get(struct mlx5_priv *priv,
329*1caa89ecSMichael Baum 			       const struct rte_flow_field_data *data)
330*1caa89ecSMichael Baum {
331*1caa89ecSMichael Baum 	uint16_t class = data->class_id;
332*1caa89ecSMichael Baum 	uint8_t type = data->type;
333*1caa89ecSMichael Baum 	struct mlx5_geneve_tlv_option *option;
334*1caa89ecSMichael Baum 	struct mlx5_geneve_tlv_resource *resource;
335*1caa89ecSMichael Baum 	uint8_t offset;
336*1caa89ecSMichael Baum 
337*1caa89ecSMichael Baum 	option = mlx5_geneve_tlv_option_get(priv, type, class);
338*1caa89ecSMichael Baum 	if (option == NULL)
339*1caa89ecSMichael Baum 		return -rte_errno;
340*1caa89ecSMichael Baum 	switch (data->field) {
341*1caa89ecSMichael Baum 	case RTE_FLOW_FIELD_GENEVE_OPT_TYPE:
342*1caa89ecSMichael Baum 	case RTE_FLOW_FIELD_GENEVE_OPT_CLASS:
343*1caa89ecSMichael Baum 		if (!option->match_data[0].dw_mask) {
344*1caa89ecSMichael Baum 			DRV_LOG(ERR, "DW0 isn't configured");
345*1caa89ecSMichael Baum 			rte_errno = EINVAL;
346*1caa89ecSMichael Baum 			return -rte_errno;
347*1caa89ecSMichael Baum 		}
348*1caa89ecSMichael Baum 		resource = &option->resources[0];
349*1caa89ecSMichael Baum 		MLX5_ASSERT(resource->offset == 0);
350*1caa89ecSMichael Baum 		break;
351*1caa89ecSMichael Baum 	case RTE_FLOW_FIELD_GENEVE_OPT_DATA:
352*1caa89ecSMichael Baum 		/*
353*1caa89ecSMichael Baum 		 * Convert offset twice:
354*1caa89ecSMichael Baum 		 *  - First conversion from bit offset to DW offset.
355*1caa89ecSMichael Baum 		 *  - Second conversion is to be related to data start instead
356*1caa89ecSMichael Baum 		 *    of option start.
357*1caa89ecSMichael Baum 		 */
358*1caa89ecSMichael Baum 		offset = (data->offset >> 5) + 1;
359*1caa89ecSMichael Baum 		resource = mlx5_geneve_tlv_option_get_resource_by_offset(option,
360*1caa89ecSMichael Baum 									 offset);
361*1caa89ecSMichael Baum 		break;
362*1caa89ecSMichael Baum 	default:
363*1caa89ecSMichael Baum 		DRV_LOG(ERR,
364*1caa89ecSMichael Baum 			"Field ID %u doesn't describe GENEVE option header.",
365*1caa89ecSMichael Baum 			data->field);
366*1caa89ecSMichael Baum 		rte_errno = EINVAL;
367*1caa89ecSMichael Baum 		return -rte_errno;
368*1caa89ecSMichael Baum 	}
369*1caa89ecSMichael Baum 	if (resource == NULL)
370*1caa89ecSMichael Baum 		return -rte_errno;
371*1caa89ecSMichael Baum 	return resource->modify_field;
372*1caa89ecSMichael Baum }
373*1caa89ecSMichael Baum 
374*1caa89ecSMichael Baum /**
375f5177bdcSMichael Baum  * Create single GENEVE TLV option sample.
376f5177bdcSMichael Baum  *
377f5177bdcSMichael Baum  * @param ctx
378f5177bdcSMichael Baum  *   Context returned from mlx5 open_device() glue function.
379f5177bdcSMichael Baum  * @param attr
380f5177bdcSMichael Baum  *   Pointer to GENEVE TLV option attributes structure.
381f5177bdcSMichael Baum  * @param query_attr
382f5177bdcSMichael Baum  *   Pointer to match sample info attributes structure.
383f5177bdcSMichael Baum  * @param match_data
384f5177bdcSMichael Baum  *   Pointer to header layout structure to update.
385f5177bdcSMichael Baum  * @param resource
386f5177bdcSMichael Baum  *   Pointer to single sample context to fill.
3872a39dda7SMichael Baum  * @param sample_id
3882a39dda7SMichael Baum  *   The flex parser id for single DW or UINT8_MAX for multiple DWs.
389f5177bdcSMichael Baum  *
390f5177bdcSMichael Baum  * @return
391f5177bdcSMichael Baum  *   0 on success, a negative errno otherwise and rte_errno is set.
392f5177bdcSMichael Baum  */
393f5177bdcSMichael Baum static int
mlx5_geneve_tlv_option_create_sample(void * ctx,struct mlx5_devx_geneve_tlv_option_attr * attr,struct mlx5_devx_match_sample_info_query_attr * query_attr,struct mlx5_hl_data * match_data,struct mlx5_geneve_tlv_resource * resource,uint8_t sample_id)394f5177bdcSMichael Baum mlx5_geneve_tlv_option_create_sample(void *ctx,
395f5177bdcSMichael Baum 		      struct mlx5_devx_geneve_tlv_option_attr *attr,
396f5177bdcSMichael Baum 		      struct mlx5_devx_match_sample_info_query_attr *query_attr,
397f5177bdcSMichael Baum 		      struct mlx5_hl_data *match_data,
3982a39dda7SMichael Baum 		      struct mlx5_geneve_tlv_resource *resource, uint8_t sample_id)
399f5177bdcSMichael Baum {
400f5177bdcSMichael Baum 	struct mlx5_devx_obj *obj;
401f5177bdcSMichael Baum 	int ret;
402f5177bdcSMichael Baum 
403f5177bdcSMichael Baum 	obj = mlx5_devx_cmd_create_geneve_tlv_option(ctx, attr);
404f5177bdcSMichael Baum 	if (obj == NULL)
405f5177bdcSMichael Baum 		return -rte_errno;
4062a39dda7SMichael Baum 	if (sample_id == INVALID_SAMPLE_ID)
407f5177bdcSMichael Baum 		ret = mlx5_devx_cmd_query_geneve_tlv_option(ctx, obj, query_attr);
4082a39dda7SMichael Baum 	else
4092a39dda7SMichael Baum 		ret = mlx5_devx_cmd_match_sample_info_query(ctx, sample_id, query_attr);
410f5177bdcSMichael Baum 	if (ret) {
411f5177bdcSMichael Baum 		claim_zero(mlx5_devx_cmd_destroy(obj));
412f5177bdcSMichael Baum 		return ret;
413f5177bdcSMichael Baum 	}
414f5177bdcSMichael Baum 	resource->obj = obj;
415f5177bdcSMichael Baum 	resource->offset = attr->sample_offset;
416f5177bdcSMichael Baum 	resource->modify_field = query_attr->modify_field_id;
417f5177bdcSMichael Baum 	match_data->dw_offset = query_attr->sample_dw_data;
418f5177bdcSMichael Baum 	match_data->dw_mask = 0xffffffff;
419f5177bdcSMichael Baum 	return 0;
420f5177bdcSMichael Baum }
421f5177bdcSMichael Baum 
422f5177bdcSMichael Baum /**
423f5177bdcSMichael Baum  * Destroy single GENEVE TLV option sample.
424f5177bdcSMichael Baum  *
425f5177bdcSMichael Baum  * @param resource
426f5177bdcSMichael Baum  *   Pointer to single sample context to clean.
427f5177bdcSMichael Baum  */
428f5177bdcSMichael Baum static void
mlx5_geneve_tlv_option_destroy_sample(struct mlx5_geneve_tlv_resource * resource)429f5177bdcSMichael Baum mlx5_geneve_tlv_option_destroy_sample(struct mlx5_geneve_tlv_resource *resource)
430f5177bdcSMichael Baum {
431f5177bdcSMichael Baum 	claim_zero(mlx5_devx_cmd_destroy(resource->obj));
432f5177bdcSMichael Baum 	resource->obj = NULL;
433f5177bdcSMichael Baum }
434f5177bdcSMichael Baum 
43585738168SMichael Baum /*
43685738168SMichael Baum  * Sample for DW0 are created when one of two conditions is met:
43785738168SMichael Baum  * 1. Header is matchable.
43885738168SMichael Baum  * 2. This option doesn't configure any data DW.
43985738168SMichael Baum  */
44085738168SMichael Baum static bool
should_configure_sample_for_dw0(const struct rte_pmd_mlx5_geneve_tlv * spec)44185738168SMichael Baum should_configure_sample_for_dw0(const struct rte_pmd_mlx5_geneve_tlv *spec)
44285738168SMichael Baum {
44385738168SMichael Baum 	uint8_t i;
44485738168SMichael Baum 
44585738168SMichael Baum 	if (spec->match_on_class_mode == 2)
44685738168SMichael Baum 		return true;
44785738168SMichael Baum 	for (i = 0; i < spec->sample_len; ++i)
44885738168SMichael Baum 		if (spec->match_data_mask[i] != 0)
44985738168SMichael Baum 			return false;
45085738168SMichael Baum 	return true;
45185738168SMichael Baum }
45285738168SMichael Baum 
453f5177bdcSMichael Baum /**
454f5177bdcSMichael Baum  * Create single GENEVE TLV option.
455f5177bdcSMichael Baum  *
456f5177bdcSMichael Baum  * @param ctx
457f5177bdcSMichael Baum  *   Context returned from mlx5 open_device() glue function.
458f5177bdcSMichael Baum  * @param spec
459f5177bdcSMichael Baum  *   Pointer to user configuration.
460f5177bdcSMichael Baum  * @param option
461f5177bdcSMichael Baum  *   Pointer to single GENEVE TLV option to fill.
4622a39dda7SMichael Baum  * @param sample_id
4632a39dda7SMichael Baum  *   The flex parser id for single DW or UINT8_MAX for multiple DWs.
464f5177bdcSMichael Baum  *
465f5177bdcSMichael Baum  * @return
466f5177bdcSMichael Baum  *   0 on success, a negative errno otherwise and rte_errno is set.
467f5177bdcSMichael Baum  */
468f5177bdcSMichael Baum static int
mlx5_geneve_tlv_option_create(void * ctx,const struct rte_pmd_mlx5_geneve_tlv * spec,struct mlx5_geneve_tlv_option * option,uint8_t sample_id)469f5177bdcSMichael Baum mlx5_geneve_tlv_option_create(void *ctx, const struct rte_pmd_mlx5_geneve_tlv *spec,
4702a39dda7SMichael Baum 			      struct mlx5_geneve_tlv_option *option, uint8_t sample_id)
471f5177bdcSMichael Baum {
472f5177bdcSMichael Baum 	struct mlx5_devx_geneve_tlv_option_attr attr = {
473f5177bdcSMichael Baum 		.option_class = spec->option_class,
474f5177bdcSMichael Baum 		.option_type = spec->option_type,
475f5177bdcSMichael Baum 		.option_data_len = spec->option_len,
476f5177bdcSMichael Baum 		.option_class_ignore = spec->match_on_class_mode == 1 ? 0 : 1,
4772a39dda7SMichael Baum 		.offset_valid = sample_id == INVALID_SAMPLE_ID ? 1 : 0,
478f5177bdcSMichael Baum 	};
479f5177bdcSMichael Baum 	struct mlx5_devx_match_sample_info_query_attr query_attr = {0};
480f5177bdcSMichael Baum 	struct mlx5_geneve_tlv_resource *resource;
481f5177bdcSMichael Baum 	uint8_t i, resource_id = 0;
482f5177bdcSMichael Baum 	int ret;
483f5177bdcSMichael Baum 
48485738168SMichael Baum 	if (should_configure_sample_for_dw0(spec)) {
4852a39dda7SMichael Baum 		MLX5_ASSERT(sample_id == INVALID_SAMPLE_ID);
486f5177bdcSMichael Baum 		attr.sample_offset = 0;
487f5177bdcSMichael Baum 		resource = &option->resources[resource_id];
488f5177bdcSMichael Baum 		ret = mlx5_geneve_tlv_option_create_sample(ctx, &attr,
489f5177bdcSMichael Baum 							   &query_attr,
490f5177bdcSMichael Baum 							   &option->match_data[0],
4912a39dda7SMichael Baum 							   resource,
4922a39dda7SMichael Baum 							   INVALID_SAMPLE_ID);
493f5177bdcSMichael Baum 		if (ret)
494f5177bdcSMichael Baum 			return ret;
495f5177bdcSMichael Baum 		resource_id++;
496f5177bdcSMichael Baum 	}
497f5177bdcSMichael Baum 	/*
498f5177bdcSMichael Baum 	 * Create FW object for each DW request by user.
499f5177bdcSMichael Baum 	 * Starting from 1 since FW offset starts from header.
500f5177bdcSMichael Baum 	 */
501f5177bdcSMichael Baum 	for (i = 1; i <= spec->sample_len; ++i) {
502f5177bdcSMichael Baum 		if (spec->match_data_mask[i - 1] == 0)
503f5177bdcSMichael Baum 			continue;
504f5177bdcSMichael Baum 		/* offset of data + offset inside data = specific DW offset. */
505f5177bdcSMichael Baum 		attr.sample_offset = spec->offset + i;
506f5177bdcSMichael Baum 		resource = &option->resources[resource_id];
507f5177bdcSMichael Baum 		ret = mlx5_geneve_tlv_option_create_sample(ctx, &attr,
508f5177bdcSMichael Baum 							   &query_attr,
509f5177bdcSMichael Baum 							   &option->match_data[i],
5102a39dda7SMichael Baum 							   resource,
5112a39dda7SMichael Baum 							   sample_id);
512f5177bdcSMichael Baum 		if (ret)
513f5177bdcSMichael Baum 			goto error;
514f5177bdcSMichael Baum 		resource_id++;
515f5177bdcSMichael Baum 	}
516f5177bdcSMichael Baum 	/*
517f5177bdcSMichael Baum 	 * Update the OK bit information according to last query.
518f5177bdcSMichael Baum 	 * It should be same for each query under same option.
519f5177bdcSMichael Baum 	 */
520f5177bdcSMichael Baum 	option->hl_ok_bit.dw_offset = query_attr.sample_dw_ok_bit;
521f5177bdcSMichael Baum 	option->hl_ok_bit.dw_mask = 1 << query_attr.sample_dw_ok_bit_offset;
522f5177bdcSMichael Baum 	option->match_data_size = spec->sample_len + 1;
523f5177bdcSMichael Baum 	option->type = spec->option_type;
524f5177bdcSMichael Baum 	option->class = spec->option_class;
525f5177bdcSMichael Baum 	option->class_mode = spec->match_on_class_mode;
526f5177bdcSMichael Baum 	rte_atomic_store_explicit(&option->refcnt, 0, rte_memory_order_relaxed);
527f5177bdcSMichael Baum 	return 0;
528f5177bdcSMichael Baum error:
529f5177bdcSMichael Baum 	for (i = 0; i < resource_id; ++i) {
530f5177bdcSMichael Baum 		resource = &option->resources[i];
531f5177bdcSMichael Baum 		mlx5_geneve_tlv_option_destroy_sample(resource);
532f5177bdcSMichael Baum 	}
533f5177bdcSMichael Baum 	return ret;
534f5177bdcSMichael Baum }
535f5177bdcSMichael Baum 
536f5177bdcSMichael Baum /**
537f5177bdcSMichael Baum  * Destroy single GENEVE TLV option.
538f5177bdcSMichael Baum  *
539f5177bdcSMichael Baum  * @param option
540f5177bdcSMichael Baum  *   Pointer to single GENEVE TLV option to destroy.
541f5177bdcSMichael Baum  *
542f5177bdcSMichael Baum  * @return
543f5177bdcSMichael Baum  *   0 on success, a negative errno otherwise and rte_errno is set.
544f5177bdcSMichael Baum  */
545f5177bdcSMichael Baum static int
mlx5_geneve_tlv_option_destroy(struct mlx5_geneve_tlv_option * option)546f5177bdcSMichael Baum mlx5_geneve_tlv_option_destroy(struct mlx5_geneve_tlv_option *option)
547f5177bdcSMichael Baum {
548f5177bdcSMichael Baum 	uint8_t i;
549f5177bdcSMichael Baum 
550f5177bdcSMichael Baum 	if (rte_atomic_load_explicit(&option->refcnt, rte_memory_order_relaxed)) {
551f5177bdcSMichael Baum 		DRV_LOG(ERR,
552f5177bdcSMichael Baum 			"Option type %u class %u is still in used by %u tables.",
553f5177bdcSMichael Baum 			option->type, option->class, option->refcnt);
554f5177bdcSMichael Baum 		rte_errno = EBUSY;
555f5177bdcSMichael Baum 		return -rte_errno;
556f5177bdcSMichael Baum 	}
557f5177bdcSMichael Baum 	for (i = 0; option->resources[i].obj != NULL; ++i)
558f5177bdcSMichael Baum 		mlx5_geneve_tlv_option_destroy_sample(&option->resources[i]);
559f5177bdcSMichael Baum 	return 0;
560f5177bdcSMichael Baum }
561f5177bdcSMichael Baum 
562f5177bdcSMichael Baum /**
563f5177bdcSMichael Baum  * Copy the GENEVE TLV option user configuration for future comparing.
564f5177bdcSMichael Baum  *
565f5177bdcSMichael Baum  * @param dst
566f5177bdcSMichael Baum  *   Pointer to internal user configuration copy.
567f5177bdcSMichael Baum  * @param src
568f5177bdcSMichael Baum  *   Pointer to user configuration.
569f5177bdcSMichael Baum  * @param match_data_mask
570f5177bdcSMichael Baum  *   Pointer to allocated data array.
571f5177bdcSMichael Baum  */
572f5177bdcSMichael Baum static void
mlx5_geneve_tlv_option_copy(struct rte_pmd_mlx5_geneve_tlv * dst,const struct rte_pmd_mlx5_geneve_tlv * src,rte_be32_t * match_data_mask)573f5177bdcSMichael Baum mlx5_geneve_tlv_option_copy(struct rte_pmd_mlx5_geneve_tlv *dst,
574f5177bdcSMichael Baum 			    const struct rte_pmd_mlx5_geneve_tlv *src,
575f5177bdcSMichael Baum 			    rte_be32_t *match_data_mask)
576f5177bdcSMichael Baum {
577f5177bdcSMichael Baum 	uint8_t i;
578f5177bdcSMichael Baum 
579f5177bdcSMichael Baum 	dst->option_type = src->option_type;
580f5177bdcSMichael Baum 	dst->option_class = src->option_class;
581f5177bdcSMichael Baum 	dst->option_len = src->option_len;
582f5177bdcSMichael Baum 	dst->offset = src->offset;
583f5177bdcSMichael Baum 	dst->match_on_class_mode = src->match_on_class_mode;
584f5177bdcSMichael Baum 	dst->sample_len = src->sample_len;
585f5177bdcSMichael Baum 	for (i = 0; i < dst->sample_len; ++i)
586f5177bdcSMichael Baum 		match_data_mask[i] = src->match_data_mask[i];
587f5177bdcSMichael Baum 	dst->match_data_mask = match_data_mask;
588f5177bdcSMichael Baum }
589f5177bdcSMichael Baum 
590f5177bdcSMichael Baum /**
591f5177bdcSMichael Baum  * Create list of GENEVE TLV options according to user configuration list.
592f5177bdcSMichael Baum  *
593f5177bdcSMichael Baum  * @param sh
594f5177bdcSMichael Baum  *   Shared context the options are being created on.
595f5177bdcSMichael Baum  * @param tlv_list
596f5177bdcSMichael Baum  *   A list of GENEVE TLV options to create parser for them.
597f5177bdcSMichael Baum  * @param nb_options
598f5177bdcSMichael Baum  *   The number of options in TLV list.
5992a39dda7SMichael Baum  * @param sample_id
6002a39dda7SMichael Baum  *   The flex parser id for single DW or UINT8_MAX for multiple DWs.
601f5177bdcSMichael Baum  *
602f5177bdcSMichael Baum  * @return
603f5177bdcSMichael Baum  *   A pointer to GENEVE TLV options parser structure on success,
604f5177bdcSMichael Baum  *   NULL otherwise and rte_errno is set.
605f5177bdcSMichael Baum  */
606f5177bdcSMichael Baum static struct mlx5_geneve_tlv_options *
mlx5_geneve_tlv_options_create(struct mlx5_dev_ctx_shared * sh,const struct rte_pmd_mlx5_geneve_tlv tlv_list[],uint8_t nb_options,uint8_t sample_id)607f5177bdcSMichael Baum mlx5_geneve_tlv_options_create(struct mlx5_dev_ctx_shared *sh,
608f5177bdcSMichael Baum 			       const struct rte_pmd_mlx5_geneve_tlv tlv_list[],
6092a39dda7SMichael Baum 			       uint8_t nb_options, uint8_t sample_id)
610f5177bdcSMichael Baum {
611f5177bdcSMichael Baum 	struct mlx5_geneve_tlv_options *options;
612f5177bdcSMichael Baum 	const struct rte_pmd_mlx5_geneve_tlv *spec;
613f5177bdcSMichael Baum 	rte_be32_t *data_mask;
614f5177bdcSMichael Baum 	uint8_t i, j;
615f5177bdcSMichael Baum 	int ret;
616f5177bdcSMichael Baum 
617f5177bdcSMichael Baum 	options = mlx5_malloc(MLX5_MEM_ZERO | MLX5_MEM_RTE,
618f5177bdcSMichael Baum 			      sizeof(struct mlx5_geneve_tlv_options),
619f5177bdcSMichael Baum 			      RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
620f5177bdcSMichael Baum 	if (options == NULL) {
621f5177bdcSMichael Baum 		DRV_LOG(ERR,
622f5177bdcSMichael Baum 			"Failed to allocate memory for GENEVE TLV options.");
623f5177bdcSMichael Baum 		rte_errno = ENOMEM;
624f5177bdcSMichael Baum 		return NULL;
625f5177bdcSMichael Baum 	}
626f5177bdcSMichael Baum 	for (i = 0; i < nb_options; ++i) {
627f5177bdcSMichael Baum 		spec = &tlv_list[i];
628f5177bdcSMichael Baum 		ret = mlx5_geneve_tlv_option_create(sh->cdev->ctx, spec,
6292a39dda7SMichael Baum 						    &options->options[i], sample_id);
630f5177bdcSMichael Baum 		if (ret < 0)
631f5177bdcSMichael Baum 			goto error;
632f5177bdcSMichael Baum 		/* Copy the user list for comparing future configuration. */
633f5177bdcSMichael Baum 		data_mask = options->buffer + i * MAX_GENEVE_OPTION_DATA_SIZE;
634f5177bdcSMichael Baum 		mlx5_geneve_tlv_option_copy(&options->spec[i], spec, data_mask);
635f5177bdcSMichael Baum 	}
636f5177bdcSMichael Baum 	MLX5_ASSERT(sh->phdev->sh == NULL);
637f5177bdcSMichael Baum 	sh->phdev->sh = sh;
638f5177bdcSMichael Baum 	options->nb_options = nb_options;
639f5177bdcSMichael Baum 	options->refcnt = 1;
640f5177bdcSMichael Baum 	return options;
641f5177bdcSMichael Baum error:
642f5177bdcSMichael Baum 	for (j = 0; j < i; ++j)
643f5177bdcSMichael Baum 		mlx5_geneve_tlv_option_destroy(&options->options[j]);
644f5177bdcSMichael Baum 	mlx5_free(options);
645f5177bdcSMichael Baum 	return NULL;
646f5177bdcSMichael Baum }
647f5177bdcSMichael Baum 
648f5177bdcSMichael Baum /**
649f5177bdcSMichael Baum  * Destroy GENEVE TLV options structure.
650f5177bdcSMichael Baum  *
651f5177bdcSMichael Baum  * @param options
652f5177bdcSMichael Baum  *   Pointer to GENEVE TLV options structure to destroy.
653f5177bdcSMichael Baum  * @param phdev
654f5177bdcSMichael Baum  *   Pointer physical device options were created on.
655f5177bdcSMichael Baum  *
656f5177bdcSMichael Baum  * @return
657f5177bdcSMichael Baum  *   0 on success, a negative errno otherwise and rte_errno is set.
658f5177bdcSMichael Baum  */
659f5177bdcSMichael Baum int
mlx5_geneve_tlv_options_destroy(struct mlx5_geneve_tlv_options * options,struct mlx5_physical_device * phdev)660f5177bdcSMichael Baum mlx5_geneve_tlv_options_destroy(struct mlx5_geneve_tlv_options *options,
661f5177bdcSMichael Baum 				struct mlx5_physical_device *phdev)
662f5177bdcSMichael Baum {
663f5177bdcSMichael Baum 	uint8_t i;
664f5177bdcSMichael Baum 	int ret;
665f5177bdcSMichael Baum 
666f5177bdcSMichael Baum 	if (--options->refcnt)
667f5177bdcSMichael Baum 		return 0;
668f5177bdcSMichael Baum 	for (i = 0; i < options->nb_options; ++i) {
669f5177bdcSMichael Baum 		ret = mlx5_geneve_tlv_option_destroy(&options->options[i]);
670f5177bdcSMichael Baum 		if (ret < 0) {
671f5177bdcSMichael Baum 			DRV_LOG(ERR,
672f5177bdcSMichael Baum 				"Failed to destroy option %u, %u/%u is already destroyed.",
673f5177bdcSMichael Baum 				i, i, options->nb_options);
674f5177bdcSMichael Baum 			return ret;
675f5177bdcSMichael Baum 		}
676f5177bdcSMichael Baum 	}
677f5177bdcSMichael Baum 	mlx5_free(options);
678f5177bdcSMichael Baum 	phdev->tlv_options = NULL;
679f5177bdcSMichael Baum 	phdev->sh = NULL;
680f5177bdcSMichael Baum 	return 0;
681f5177bdcSMichael Baum }
682f5177bdcSMichael Baum 
683f5177bdcSMichael Baum /**
684f5177bdcSMichael Baum  * Check if GENEVE TLV options are hosted on the current port
685f5177bdcSMichael Baum  * and the port can be closed
686f5177bdcSMichael Baum  *
687f5177bdcSMichael Baum  * @param priv
688f5177bdcSMichael Baum  *   Device private data.
689f5177bdcSMichael Baum  *
690f5177bdcSMichael Baum  * @return
691f5177bdcSMichael Baum  *   0 on success, a negative EBUSY and rte_errno is set.
692f5177bdcSMichael Baum  */
693f5177bdcSMichael Baum int
mlx5_geneve_tlv_options_check_busy(struct mlx5_priv * priv)694f5177bdcSMichael Baum mlx5_geneve_tlv_options_check_busy(struct mlx5_priv *priv)
695f5177bdcSMichael Baum {
696f5177bdcSMichael Baum 	struct mlx5_physical_device *phdev = mlx5_get_locked_physical_device(priv);
697f5177bdcSMichael Baum 	struct mlx5_dev_ctx_shared *sh = priv->sh;
698f5177bdcSMichael Baum 
699f5177bdcSMichael Baum 	if (!phdev || phdev->sh != sh) {
700f5177bdcSMichael Baum 		mlx5_unlock_physical_device();
701f5177bdcSMichael Baum 		return 0;
702f5177bdcSMichael Baum 	}
703f5177bdcSMichael Baum 	if (!sh->phdev->tlv_options || sh->phdev->tlv_options->refcnt == 1) {
704f5177bdcSMichael Baum 		/* Mark port as being closed one */
705f5177bdcSMichael Baum 		sh->phdev->sh = NULL;
706f5177bdcSMichael Baum 		mlx5_unlock_physical_device();
707f5177bdcSMichael Baum 		return 0;
708f5177bdcSMichael Baum 	}
709f5177bdcSMichael Baum 	mlx5_unlock_physical_device();
710f5177bdcSMichael Baum 	rte_errno = EBUSY;
711f5177bdcSMichael Baum 	return -EBUSY;
712f5177bdcSMichael Baum }
713f5177bdcSMichael Baum 
714f5177bdcSMichael Baum /**
715f5177bdcSMichael Baum  * Validate GENEVE TLV option user request structure.
716f5177bdcSMichael Baum  *
717f5177bdcSMichael Baum  * @param attr
718f5177bdcSMichael Baum  *   Pointer to HCA attribute structure.
719f5177bdcSMichael Baum  * @param option
720f5177bdcSMichael Baum  *   Pointer to user configuration.
721f5177bdcSMichael Baum  *
722f5177bdcSMichael Baum  * @return
723f5177bdcSMichael Baum  *   0 on success, a negative errno otherwise and rte_errno is set.
724f5177bdcSMichael Baum  */
725f5177bdcSMichael Baum static int
mlx5_geneve_tlv_option_validate(struct mlx5_hca_attr * attr,const struct rte_pmd_mlx5_geneve_tlv * option)726f5177bdcSMichael Baum mlx5_geneve_tlv_option_validate(struct mlx5_hca_attr *attr,
727f5177bdcSMichael Baum 				const struct rte_pmd_mlx5_geneve_tlv *option)
728f5177bdcSMichael Baum {
729f5177bdcSMichael Baum 	if (option->option_len > attr->max_geneve_tlv_option_data_len) {
730f5177bdcSMichael Baum 		DRV_LOG(ERR,
731f5177bdcSMichael Baum 			"GENEVE TLV option length (%u) exceeds the limit (%u).",
732f5177bdcSMichael Baum 			option->option_len,
733f5177bdcSMichael Baum 			attr->max_geneve_tlv_option_data_len);
734f5177bdcSMichael Baum 		rte_errno = ENOTSUP;
735f5177bdcSMichael Baum 		return -rte_errno;
736f5177bdcSMichael Baum 	}
737f5177bdcSMichael Baum 	if (option->option_len < option->offset + option->sample_len) {
738f5177bdcSMichael Baum 		DRV_LOG(ERR,
739f5177bdcSMichael Baum 			"GENEVE TLV option length is smaller than (offset + sample_len).");
740f5177bdcSMichael Baum 		rte_errno = EINVAL;
741f5177bdcSMichael Baum 		return -rte_errno;
742f5177bdcSMichael Baum 	}
743f5177bdcSMichael Baum 	if (option->match_on_class_mode > 2) {
744f5177bdcSMichael Baum 		DRV_LOG(ERR,
745f5177bdcSMichael Baum 			"GENEVE TLV option match_on_class_mode is invalid.");
746f5177bdcSMichael Baum 		rte_errno = EINVAL;
747f5177bdcSMichael Baum 		return -rte_errno;
748f5177bdcSMichael Baum 	}
749f5177bdcSMichael Baum 	return 0;
750f5177bdcSMichael Baum }
751f5177bdcSMichael Baum 
752f5177bdcSMichael Baum /**
753f5177bdcSMichael Baum  * Get the number of requested DWs in given GENEVE TLV option.
754f5177bdcSMichael Baum  *
755f5177bdcSMichael Baum  * @param option
756f5177bdcSMichael Baum  *   Pointer to user configuration.
757f5177bdcSMichael Baum  *
758f5177bdcSMichael Baum  * @return
759f5177bdcSMichael Baum  *   Number of requested DWs for given GENEVE TLV option.
760f5177bdcSMichael Baum  */
761f5177bdcSMichael Baum static uint8_t
mlx5_geneve_tlv_option_get_nb_dws(const struct rte_pmd_mlx5_geneve_tlv * option)762f5177bdcSMichael Baum mlx5_geneve_tlv_option_get_nb_dws(const struct rte_pmd_mlx5_geneve_tlv *option)
763f5177bdcSMichael Baum {
764f5177bdcSMichael Baum 	uint8_t nb_dws = 0;
765f5177bdcSMichael Baum 	uint8_t i;
766f5177bdcSMichael Baum 
767f5177bdcSMichael Baum 	if (option->match_on_class_mode == 2)
768f5177bdcSMichael Baum 		nb_dws++;
769f5177bdcSMichael Baum 	for (i = 0; i < option->sample_len; ++i) {
770f5177bdcSMichael Baum 		if (option->match_data_mask[i] == 0xffffffff)
771f5177bdcSMichael Baum 			nb_dws++;
772f5177bdcSMichael Baum 	}
773f5177bdcSMichael Baum 	return nb_dws;
774f5177bdcSMichael Baum }
775f5177bdcSMichael Baum 
776f5177bdcSMichael Baum /**
777f5177bdcSMichael Baum  * Compare GENEVE TLV option user request structure.
778f5177bdcSMichael Baum  *
779f5177bdcSMichael Baum  * @param option1
780f5177bdcSMichael Baum  *   Pointer to first user configuration.
781f5177bdcSMichael Baum  * @param option2
782f5177bdcSMichael Baum  *   Pointer to second user configuration.
783f5177bdcSMichael Baum  *
784f5177bdcSMichael Baum  * @return
785f5177bdcSMichael Baum  *   True if the options are equal, false otherwise.
786f5177bdcSMichael Baum  */
787f5177bdcSMichael Baum static bool
mlx5_geneve_tlv_option_compare(const struct rte_pmd_mlx5_geneve_tlv * option1,const struct rte_pmd_mlx5_geneve_tlv * option2)788f5177bdcSMichael Baum mlx5_geneve_tlv_option_compare(const struct rte_pmd_mlx5_geneve_tlv *option1,
789f5177bdcSMichael Baum 			       const struct rte_pmd_mlx5_geneve_tlv *option2)
790f5177bdcSMichael Baum {
791f5177bdcSMichael Baum 	uint8_t i;
792f5177bdcSMichael Baum 
793f5177bdcSMichael Baum 	if (option1->option_type != option2->option_type ||
794f5177bdcSMichael Baum 	    option1->option_class != option2->option_class ||
795f5177bdcSMichael Baum 	    option1->option_len != option2->option_len ||
796f5177bdcSMichael Baum 	    option1->offset != option2->offset ||
797f5177bdcSMichael Baum 	    option1->match_on_class_mode != option2->match_on_class_mode ||
798f5177bdcSMichael Baum 	    option1->sample_len != option2->sample_len)
799f5177bdcSMichael Baum 		return false;
800f5177bdcSMichael Baum 	for (i = 0; i < option1->sample_len; ++i) {
801f5177bdcSMichael Baum 		if (option1->match_data_mask[i] != option2->match_data_mask[i])
802f5177bdcSMichael Baum 			return false;
803f5177bdcSMichael Baum 	}
804f5177bdcSMichael Baum 	return true;
805f5177bdcSMichael Baum }
806f5177bdcSMichael Baum 
807f5177bdcSMichael Baum /**
808f5177bdcSMichael Baum  * Check whether the given GENEVE TLV option list is equal to internal list.
809f5177bdcSMichael Baum  * The lists are equal when they have same size and same options in the same
810f5177bdcSMichael Baum  * order inside the list.
811f5177bdcSMichael Baum  *
812f5177bdcSMichael Baum  * @param options
813f5177bdcSMichael Baum  *   Pointer to GENEVE TLV options structure.
814f5177bdcSMichael Baum  * @param tlv_list
815f5177bdcSMichael Baum  *   A list of GENEVE TLV options to compare.
816f5177bdcSMichael Baum  * @param nb_options
817f5177bdcSMichael Baum  *   The number of options in TLV list.
818f5177bdcSMichael Baum  *
819f5177bdcSMichael Baum  * @return
820f5177bdcSMichael Baum  *   True if the lists are equal, false otherwise.
821f5177bdcSMichael Baum  */
822f5177bdcSMichael Baum static bool
mlx5_is_same_geneve_tlv_options(const struct mlx5_geneve_tlv_options * options,const struct rte_pmd_mlx5_geneve_tlv tlv_list[],uint8_t nb_options)823f5177bdcSMichael Baum mlx5_is_same_geneve_tlv_options(const struct mlx5_geneve_tlv_options *options,
824f5177bdcSMichael Baum 				const struct rte_pmd_mlx5_geneve_tlv tlv_list[],
825f5177bdcSMichael Baum 				uint8_t nb_options)
826f5177bdcSMichael Baum {
827f5177bdcSMichael Baum 	const struct rte_pmd_mlx5_geneve_tlv *spec = options->spec;
828f5177bdcSMichael Baum 	uint8_t i;
829f5177bdcSMichael Baum 
830f5177bdcSMichael Baum 	if (options->nb_options != nb_options)
831f5177bdcSMichael Baum 		return false;
832f5177bdcSMichael Baum 	for (i = 0; i < nb_options; ++i) {
833f5177bdcSMichael Baum 		if (!mlx5_geneve_tlv_option_compare(&spec[i], &tlv_list[i]))
834f5177bdcSMichael Baum 			return false;
835f5177bdcSMichael Baum 	}
836f5177bdcSMichael Baum 	return true;
837f5177bdcSMichael Baum }
838f5177bdcSMichael Baum 
8392a39dda7SMichael Baum static inline bool
multiple_dws_supported(struct mlx5_hca_attr * attr)8402a39dda7SMichael Baum multiple_dws_supported(struct mlx5_hca_attr *attr)
8412a39dda7SMichael Baum {
8422a39dda7SMichael Baum 	return attr->geneve_tlv_option_offset && attr->geneve_tlv_sample;
8432a39dda7SMichael Baum }
8442a39dda7SMichael Baum 
845f5177bdcSMichael Baum void *
mlx5_geneve_tlv_parser_create(uint16_t port_id,const struct rte_pmd_mlx5_geneve_tlv tlv_list[],uint8_t nb_options)846f5177bdcSMichael Baum mlx5_geneve_tlv_parser_create(uint16_t port_id,
847f5177bdcSMichael Baum 			      const struct rte_pmd_mlx5_geneve_tlv tlv_list[],
848f5177bdcSMichael Baum 			      uint8_t nb_options)
849f5177bdcSMichael Baum {
850f5177bdcSMichael Baum 	struct mlx5_geneve_tlv_options *options = NULL;
851f5177bdcSMichael Baum 	struct mlx5_physical_device *phdev;
852f5177bdcSMichael Baum 	struct rte_eth_dev *dev;
853f5177bdcSMichael Baum 	struct mlx5_priv *priv;
854f5177bdcSMichael Baum 	struct mlx5_hca_attr *attr;
8552a39dda7SMichael Baum 	uint8_t sample_id;
856f5177bdcSMichael Baum 
857f5177bdcSMichael Baum 	/*
858f5177bdcSMichael Baum 	 * Validate the input before taking a lock and before any memory
859f5177bdcSMichael Baum 	 * allocation.
860f5177bdcSMichael Baum 	 */
861f5177bdcSMichael Baum 	if (rte_eth_dev_is_valid_port(port_id) < 0) {
862f5177bdcSMichael Baum 		DRV_LOG(ERR, "There is no Ethernet device for port %u.",
863f5177bdcSMichael Baum 			port_id);
864f5177bdcSMichael Baum 		rte_errno = ENODEV;
865f5177bdcSMichael Baum 		return NULL;
866f5177bdcSMichael Baum 	}
867f5177bdcSMichael Baum 	dev = &rte_eth_devices[port_id];
868f5177bdcSMichael Baum 	priv = dev->data->dev_private;
869f5177bdcSMichael Baum 	if (priv->tlv_options) {
870f5177bdcSMichael Baum 		DRV_LOG(ERR, "Port %u already has GENEVE TLV parser.", port_id);
871f5177bdcSMichael Baum 		rte_errno = EEXIST;
872f5177bdcSMichael Baum 		return NULL;
873f5177bdcSMichael Baum 	}
874f5177bdcSMichael Baum 	if (priv->sh->config.dv_flow_en < 2) {
875f5177bdcSMichael Baum 		DRV_LOG(ERR,
876f5177bdcSMichael Baum 			"GENEVE TLV parser is only supported for HW steering.");
877f5177bdcSMichael Baum 		rte_errno = ENOTSUP;
878f5177bdcSMichael Baum 		return NULL;
879f5177bdcSMichael Baum 	}
880f5177bdcSMichael Baum 	attr = &priv->sh->cdev->config.hca_attr;
8812a39dda7SMichael Baum 	if (!attr->query_match_sample_info || !attr->geneve_tlv_opt) {
8822a39dda7SMichael Baum 		DRV_LOG(ERR, "Not enough capabilities to support GENEVE TLV parser, is this device eswitch manager?");
883f5177bdcSMichael Baum 		rte_errno = ENOTSUP;
884f5177bdcSMichael Baum 		return NULL;
885f5177bdcSMichael Baum 	}
8862a39dda7SMichael Baum 	DRV_LOG(DEBUG, "Max DWs supported for GENEVE TLV option is %u",
8872a39dda7SMichael Baum 		attr->max_geneve_tlv_options);
8882a39dda7SMichael Baum 	if (nb_options > attr->max_geneve_tlv_options) {
889f5177bdcSMichael Baum 		DRV_LOG(ERR,
890f5177bdcSMichael Baum 			"GENEVE TLV option number (%u) exceeds the limit (%u).",
8912a39dda7SMichael Baum 			nb_options, attr->max_geneve_tlv_options);
892f5177bdcSMichael Baum 		rte_errno = EINVAL;
893f5177bdcSMichael Baum 		return NULL;
894f5177bdcSMichael Baum 	}
8952a39dda7SMichael Baum 	if (multiple_dws_supported(attr)) {
8962a39dda7SMichael Baum 		uint8_t total_dws = 0;
8972a39dda7SMichael Baum 		uint8_t i;
8982a39dda7SMichael Baum 
8992a39dda7SMichael Baum 		MLX5_ASSERT(attr->max_geneve_tlv_options >= MAX_GENEVE_OPTIONS_RESOURCES);
900f5177bdcSMichael Baum 		for (i = 0; i < nb_options; ++i) {
901f5177bdcSMichael Baum 			if (mlx5_geneve_tlv_option_validate(attr, &tlv_list[i]) < 0) {
902f5177bdcSMichael Baum 				DRV_LOG(ERR, "GENEVE TLV option %u is invalid.", i);
903f5177bdcSMichael Baum 				return NULL;
904f5177bdcSMichael Baum 			}
905f5177bdcSMichael Baum 			total_dws += mlx5_geneve_tlv_option_get_nb_dws(&tlv_list[i]);
906f5177bdcSMichael Baum 		}
907f5177bdcSMichael Baum 		if (total_dws > MAX_GENEVE_OPTIONS_RESOURCES) {
908f5177bdcSMichael Baum 			DRV_LOG(ERR,
909f5177bdcSMichael Baum 				"Total requested DWs (%u) exceeds the limit (%u).",
910f5177bdcSMichael Baum 				total_dws, MAX_GENEVE_OPTIONS_RESOURCES);
911f5177bdcSMichael Baum 			rte_errno = EINVAL;
912f5177bdcSMichael Baum 			return NULL;
913f5177bdcSMichael Baum 		}
9142a39dda7SMichael Baum 		/* Multiple DWs is supported, each of the has sample ID given later. */
9152a39dda7SMichael Baum 		sample_id = INVALID_SAMPLE_ID;
9162a39dda7SMichael Baum 		DRV_LOG(DEBUG, "GENEVE TLV parser supports multiple DWs, FLEX_PARSER_PROFILE_ENABLE == 8");
9172a39dda7SMichael Baum 	} else {
9182a39dda7SMichael Baum 		const struct rte_pmd_mlx5_geneve_tlv *option = &tlv_list[0];
9192a39dda7SMichael Baum 
9202a39dda7SMichael Baum 		if (option->offset != 0) {
9212a39dda7SMichael Baum 			DRV_LOG(ERR,
9222a39dda7SMichael Baum 				"GENEVE TLV option offset %u is required but not supported.",
9232a39dda7SMichael Baum 				option->offset);
9242a39dda7SMichael Baum 			rte_errno = ENOTSUP;
9252a39dda7SMichael Baum 			return NULL;
9262a39dda7SMichael Baum 		}
9272a39dda7SMichael Baum 		if (option->sample_len != option->option_len) {
9282a39dda7SMichael Baum 			DRV_LOG(ERR,
9292a39dda7SMichael Baum 				"GENEVE TLV option length (%u) should be equal to sample length (%u).",
9302a39dda7SMichael Baum 				option->option_len, option->sample_len);
9312a39dda7SMichael Baum 			rte_errno = ENOTSUP;
9322a39dda7SMichael Baum 			return NULL;
9332a39dda7SMichael Baum 		}
9342a39dda7SMichael Baum 		if (option->match_on_class_mode != 1) {
9352a39dda7SMichael Baum 			DRV_LOG(ERR,
9362a39dda7SMichael Baum 				"GENEVE TLV option match_on_class_mode %u is invalid for flex parser profile 0.",
9372a39dda7SMichael Baum 				option->match_on_class_mode);
9382a39dda7SMichael Baum 			rte_errno = EINVAL;
9392a39dda7SMichael Baum 			return NULL;
9402a39dda7SMichael Baum 		}
9412a39dda7SMichael Baum 		if (mlx5_geneve_tlv_option_validate(attr, option) < 0)
9422a39dda7SMichael Baum 			return NULL;
9432a39dda7SMichael Baum 		/* Single DW is supported, its sample ID is given. */
9442a39dda7SMichael Baum 		sample_id = attr->geneve_tlv_option_sample_id;
9452a39dda7SMichael Baum 		DRV_LOG(DEBUG, "GENEVE TLV parser supports only single DW, FLEX_PARSER_PROFILE_ENABLE == 0");
9462a39dda7SMichael Baum 	}
947f5177bdcSMichael Baum 	/* Take lock for this physical device and manage the options. */
948f5177bdcSMichael Baum 	phdev = mlx5_get_locked_physical_device(priv);
949f5177bdcSMichael Baum 	options = priv->sh->phdev->tlv_options;
950f5177bdcSMichael Baum 	if (options) {
951f5177bdcSMichael Baum 		if (!mlx5_is_same_geneve_tlv_options(options, tlv_list,
952f5177bdcSMichael Baum 						     nb_options)) {
953f5177bdcSMichael Baum 			mlx5_unlock_physical_device();
954f5177bdcSMichael Baum 			DRV_LOG(ERR, "Another port has already prepared different GENEVE TLV parser.");
955f5177bdcSMichael Baum 			rte_errno = EEXIST;
956f5177bdcSMichael Baum 			return NULL;
957f5177bdcSMichael Baum 		}
958f5177bdcSMichael Baum 		if (phdev->sh == NULL) {
959f5177bdcSMichael Baum 			mlx5_unlock_physical_device();
960f5177bdcSMichael Baum 			DRV_LOG(ERR, "GENEVE TLV options are hosted on port being closed.");
961f5177bdcSMichael Baum 			rte_errno = EBUSY;
962f5177bdcSMichael Baum 			return NULL;
963f5177bdcSMichael Baum 		}
964f5177bdcSMichael Baum 		/* Use existing options. */
965f5177bdcSMichael Baum 		options->refcnt++;
966f5177bdcSMichael Baum 		goto exit;
967f5177bdcSMichael Baum 	}
968f5177bdcSMichael Baum 	/* Create GENEVE TLV options for this physical device. */
9692a39dda7SMichael Baum 	options = mlx5_geneve_tlv_options_create(priv->sh, tlv_list, nb_options, sample_id);
970f5177bdcSMichael Baum 	if (!options) {
971f5177bdcSMichael Baum 		mlx5_unlock_physical_device();
972f5177bdcSMichael Baum 		return NULL;
973f5177bdcSMichael Baum 	}
974f5177bdcSMichael Baum 	phdev->tlv_options = options;
975f5177bdcSMichael Baum exit:
976f5177bdcSMichael Baum 	mlx5_unlock_physical_device();
977f5177bdcSMichael Baum 	priv->tlv_options = options;
978f5177bdcSMichael Baum 	return priv;
979f5177bdcSMichael Baum }
980f5177bdcSMichael Baum 
981f5177bdcSMichael Baum int
mlx5_geneve_tlv_parser_destroy(void * handle)982f5177bdcSMichael Baum mlx5_geneve_tlv_parser_destroy(void *handle)
983f5177bdcSMichael Baum {
984f5177bdcSMichael Baum 	struct mlx5_priv *priv = (struct mlx5_priv *)handle;
985f5177bdcSMichael Baum 	struct mlx5_physical_device *phdev;
986f5177bdcSMichael Baum 	int ret;
987f5177bdcSMichael Baum 
988f5177bdcSMichael Baum 	if (priv == NULL) {
989f5177bdcSMichael Baum 		DRV_LOG(ERR, "Handle input is invalid (NULL).");
990f5177bdcSMichael Baum 		rte_errno = EINVAL;
991f5177bdcSMichael Baum 		return -rte_errno;
992f5177bdcSMichael Baum 	}
993f5177bdcSMichael Baum 	if (priv->tlv_options == NULL) {
994f5177bdcSMichael Baum 		DRV_LOG(ERR, "This parser has been already released.");
995f5177bdcSMichael Baum 		rte_errno = ENOENT;
996f5177bdcSMichael Baum 		return -rte_errno;
997f5177bdcSMichael Baum 	}
998f5177bdcSMichael Baum 	/* Take lock for this physical device and manage the options. */
999f5177bdcSMichael Baum 	phdev = mlx5_get_locked_physical_device(priv);
1000f5177bdcSMichael Baum 	/* Destroy the options */
1001f5177bdcSMichael Baum 	ret = mlx5_geneve_tlv_options_destroy(phdev->tlv_options, phdev);
1002f5177bdcSMichael Baum 	if (ret < 0) {
1003f5177bdcSMichael Baum 		mlx5_unlock_physical_device();
1004f5177bdcSMichael Baum 		return ret;
1005f5177bdcSMichael Baum 	}
1006f5177bdcSMichael Baum 	priv->tlv_options = NULL;
1007f5177bdcSMichael Baum 	mlx5_unlock_physical_device();
1008f5177bdcSMichael Baum 	return 0;
1009f5177bdcSMichael Baum }
1010f5177bdcSMichael Baum 
1011f5177bdcSMichael Baum #endif /* defined(HAVE_IBV_FLOW_DV_SUPPORT) || !defined(HAVE_INFINIBAND_VERBS_H) */
1012