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