1ae67e3c4SGregory Etelson /* SPDX-License-Identifier: BSD-3-Clause
2ae67e3c4SGregory Etelson * Copyright (c) 2024 NVIDIA Corporation & Affiliates
3ae67e3c4SGregory Etelson */
4ae67e3c4SGregory Etelson
5ae67e3c4SGregory Etelson #include <rte_flow.h>
6ae67e3c4SGregory Etelson
7ae67e3c4SGregory Etelson #include <mlx5_malloc.h>
8ae67e3c4SGregory Etelson #include "mlx5.h"
9ae67e3c4SGregory Etelson #include "mlx5_defs.h"
10ae67e3c4SGregory Etelson #include "mlx5_flow.h"
11ae67e3c4SGregory Etelson #include "mlx5_rx.h"
12ae67e3c4SGregory Etelson #include "rte_common.h"
13ae67e3c4SGregory Etelson
14ae67e3c4SGregory Etelson #ifdef HAVE_MLX5_HWS_SUPPORT
15ae67e3c4SGregory Etelson
16ae67e3c4SGregory Etelson struct mlx5_nta_rss_ctx {
17ae67e3c4SGregory Etelson struct rte_eth_dev *dev;
18ae67e3c4SGregory Etelson struct rte_flow_attr *attr;
19ae67e3c4SGregory Etelson struct rte_flow_item *pattern;
20ae67e3c4SGregory Etelson struct rte_flow_action *actions;
21ae67e3c4SGregory Etelson const struct rte_flow_action_rss *rss_conf;
22ae67e3c4SGregory Etelson struct rte_flow_error *error;
23ae67e3c4SGregory Etelson struct mlx5_nta_rss_flow_head *head;
24ae67e3c4SGregory Etelson uint64_t pattern_flags;
25ae67e3c4SGregory Etelson enum mlx5_flow_type flow_type;
26ae67e3c4SGregory Etelson bool external;
27ae67e3c4SGregory Etelson };
28ae67e3c4SGregory Etelson
29ae67e3c4SGregory Etelson #define MLX5_RSS_PTYPE_ITEM_INDEX 0
30ae67e3c4SGregory Etelson #ifdef MLX5_RSS_PTYPE_DEBUG
31ae67e3c4SGregory Etelson #define MLX5_RSS_PTYPE_ACTION_INDEX 1
32ae67e3c4SGregory Etelson #else
33ae67e3c4SGregory Etelson #define MLX5_RSS_PTYPE_ACTION_INDEX 0
34ae67e3c4SGregory Etelson #endif
35ae67e3c4SGregory Etelson
36ae67e3c4SGregory Etelson #define MLX5_RSS_PTYPE_ITEMS_NUM (MLX5_RSS_PTYPE_ITEM_INDEX + 2)
37ae67e3c4SGregory Etelson #define MLX5_RSS_PTYPE_ACTIONS_NUM (MLX5_RSS_PTYPE_ACTION_INDEX + 2)
38ae67e3c4SGregory Etelson
39ae67e3c4SGregory Etelson static int
mlx5_nta_ptype_rss_flow_create(struct mlx5_nta_rss_ctx * ctx,uint32_t ptype,uint64_t rss_type)40ae67e3c4SGregory Etelson mlx5_nta_ptype_rss_flow_create(struct mlx5_nta_rss_ctx *ctx,
41ae67e3c4SGregory Etelson uint32_t ptype, uint64_t rss_type)
42ae67e3c4SGregory Etelson {
43ae67e3c4SGregory Etelson int ret;
44ae67e3c4SGregory Etelson struct rte_flow_hw *flow;
45ae67e3c4SGregory Etelson struct rte_flow_item_ptype *ptype_spec = (void *)(uintptr_t)
46ae67e3c4SGregory Etelson ctx->pattern[MLX5_RSS_PTYPE_ITEM_INDEX].spec;
47ae67e3c4SGregory Etelson struct rte_flow_action_rss *rss_conf = (void *)(uintptr_t)
48ae67e3c4SGregory Etelson ctx->actions[MLX5_RSS_PTYPE_ACTION_INDEX].conf;
49ae67e3c4SGregory Etelson bool dbg_log = rte_log_can_log(mlx5_logtype, RTE_LOG_DEBUG);
50ae67e3c4SGregory Etelson uint32_t mark_id = 0;
51ae67e3c4SGregory Etelson #ifdef MLX5_RSS_PTYPE_DEBUG
52ae67e3c4SGregory Etelson struct rte_flow_action_mark *mark = (void *)(uintptr_t)
53ae67e3c4SGregory Etelson ctx->actions[MLX5_RSS_PTYPE_ACTION_INDEX - 1].conf;
54ae67e3c4SGregory Etelson
55ae67e3c4SGregory Etelson /*
56ae67e3c4SGregory Etelson * Inner L3 and L4 ptype values are too large for 24bit mark
57ae67e3c4SGregory Etelson */
58ae67e3c4SGregory Etelson mark->id =
59ae67e3c4SGregory Etelson ((ptype & (RTE_PTYPE_INNER_L3_MASK | RTE_PTYPE_INNER_L4_MASK)) == ptype) ?
60ae67e3c4SGregory Etelson ptype >> 20 : ptype;
61ae67e3c4SGregory Etelson mark_id = mark->id;
62ae67e3c4SGregory Etelson dbg_log = true;
63ae67e3c4SGregory Etelson #endif
64ae67e3c4SGregory Etelson ptype_spec->packet_type = ptype;
65ae67e3c4SGregory Etelson rss_conf->types = rss_type;
66ae67e3c4SGregory Etelson ret = flow_hw_create_flow(ctx->dev, MLX5_FLOW_TYPE_GEN, ctx->attr,
67ae67e3c4SGregory Etelson ctx->pattern, ctx->actions,
68ae67e3c4SGregory Etelson MLX5_FLOW_ITEM_PTYPE, MLX5_FLOW_ACTION_RSS,
69ae67e3c4SGregory Etelson ctx->external, &flow, ctx->error);
70ae67e3c4SGregory Etelson if (flow) {
71ae67e3c4SGregory Etelson SLIST_INSERT_HEAD(ctx->head, flow, nt2hws->next);
72ae67e3c4SGregory Etelson if (dbg_log) {
73ae67e3c4SGregory Etelson DRV_LOG(NOTICE,
74ae67e3c4SGregory Etelson "PTYPE RSS: group %u ptype spec %#x rss types %#lx mark %#x\n",
75ae67e3c4SGregory Etelson ctx->attr->group, ptype_spec->packet_type,
76ae67e3c4SGregory Etelson (unsigned long)rss_conf->types, mark_id);
77ae67e3c4SGregory Etelson }
78ae67e3c4SGregory Etelson }
79ae67e3c4SGregory Etelson return ret;
80ae67e3c4SGregory Etelson }
81ae67e3c4SGregory Etelson
82ae67e3c4SGregory Etelson /*
83ae67e3c4SGregory Etelson * Call conditions:
84ae67e3c4SGregory Etelson * * Flow pattern did not include outer L3 and L4 items.
85ae67e3c4SGregory Etelson * * RSS configuration had L3 hash types.
86ae67e3c4SGregory Etelson */
87ae67e3c4SGregory Etelson static struct rte_flow_hw *
mlx5_hw_rss_expand_l3(struct mlx5_nta_rss_ctx * rss_ctx)88ae67e3c4SGregory Etelson mlx5_hw_rss_expand_l3(struct mlx5_nta_rss_ctx *rss_ctx)
89ae67e3c4SGregory Etelson {
90ae67e3c4SGregory Etelson int ret;
91ae67e3c4SGregory Etelson int ptype_ip4, ptype_ip6;
92ae67e3c4SGregory Etelson uint64_t rss_types = rte_eth_rss_hf_refine(rss_ctx->rss_conf->types);
93ae67e3c4SGregory Etelson
94ae67e3c4SGregory Etelson if (rss_ctx->rss_conf->level < 2) {
95ae67e3c4SGregory Etelson ptype_ip4 = RTE_PTYPE_L3_IPV4;
96ae67e3c4SGregory Etelson ptype_ip6 = RTE_PTYPE_L3_IPV6;
97ae67e3c4SGregory Etelson } else {
98ae67e3c4SGregory Etelson ptype_ip4 = RTE_PTYPE_INNER_L3_IPV4;
99ae67e3c4SGregory Etelson ptype_ip6 = RTE_PTYPE_INNER_L3_IPV6;
100ae67e3c4SGregory Etelson }
101ae67e3c4SGregory Etelson if (rss_types & MLX5_IPV4_LAYER_TYPES) {
102ae67e3c4SGregory Etelson ret = mlx5_nta_ptype_rss_flow_create
103ae67e3c4SGregory Etelson (rss_ctx, ptype_ip4, (rss_types & ~MLX5_IPV6_LAYER_TYPES));
104ae67e3c4SGregory Etelson if (ret)
105ae67e3c4SGregory Etelson goto error;
106ae67e3c4SGregory Etelson }
107ae67e3c4SGregory Etelson if (rss_types & MLX5_IPV6_LAYER_TYPES) {
108ae67e3c4SGregory Etelson ret = mlx5_nta_ptype_rss_flow_create
109ae67e3c4SGregory Etelson (rss_ctx, ptype_ip6, rss_types & ~MLX5_IPV4_LAYER_TYPES);
110ae67e3c4SGregory Etelson if (ret)
111ae67e3c4SGregory Etelson goto error;
112ae67e3c4SGregory Etelson }
113ae67e3c4SGregory Etelson return SLIST_FIRST(rss_ctx->head);
114ae67e3c4SGregory Etelson
115ae67e3c4SGregory Etelson error:
116ae67e3c4SGregory Etelson flow_hw_list_destroy(rss_ctx->dev, rss_ctx->flow_type,
117ae67e3c4SGregory Etelson (uintptr_t)SLIST_FIRST(rss_ctx->head));
118ae67e3c4SGregory Etelson return NULL;
119ae67e3c4SGregory Etelson }
120ae67e3c4SGregory Etelson
121ae67e3c4SGregory Etelson static void
mlx5_nta_rss_expand_l3_l4(struct mlx5_nta_rss_ctx * rss_ctx,uint64_t rss_types,uint64_t rss_l3_types)122ae67e3c4SGregory Etelson mlx5_nta_rss_expand_l3_l4(struct mlx5_nta_rss_ctx *rss_ctx,
123ae67e3c4SGregory Etelson uint64_t rss_types, uint64_t rss_l3_types)
124ae67e3c4SGregory Etelson {
125ae67e3c4SGregory Etelson int ret;
126ae67e3c4SGregory Etelson int ptype_l3, ptype_l4_udp, ptype_l4_tcp, ptype_l4_esp = 0;
127ae67e3c4SGregory Etelson uint64_t rss = rss_types &
128ae67e3c4SGregory Etelson ~(rss_l3_types == MLX5_IPV4_LAYER_TYPES ?
129ae67e3c4SGregory Etelson MLX5_IPV6_LAYER_TYPES : MLX5_IPV4_LAYER_TYPES);
130ae67e3c4SGregory Etelson
131ae67e3c4SGregory Etelson
132ae67e3c4SGregory Etelson if (rss_ctx->rss_conf->level < 2) {
133ae67e3c4SGregory Etelson ptype_l3 = rss_l3_types == MLX5_IPV4_LAYER_TYPES ?
134ae67e3c4SGregory Etelson RTE_PTYPE_L3_IPV4 : RTE_PTYPE_L3_IPV6;
135ae67e3c4SGregory Etelson ptype_l4_esp = RTE_PTYPE_TUNNEL_ESP;
136ae67e3c4SGregory Etelson ptype_l4_udp = RTE_PTYPE_L4_UDP;
137ae67e3c4SGregory Etelson ptype_l4_tcp = RTE_PTYPE_L4_TCP;
138ae67e3c4SGregory Etelson } else {
139ae67e3c4SGregory Etelson ptype_l3 = rss_l3_types == MLX5_IPV4_LAYER_TYPES ?
140ae67e3c4SGregory Etelson RTE_PTYPE_INNER_L3_IPV4 : RTE_PTYPE_INNER_L3_IPV6;
141ae67e3c4SGregory Etelson ptype_l4_udp = RTE_PTYPE_INNER_L4_UDP;
142ae67e3c4SGregory Etelson ptype_l4_tcp = RTE_PTYPE_INNER_L4_TCP;
143ae67e3c4SGregory Etelson }
144ae67e3c4SGregory Etelson if (rss_types & RTE_ETH_RSS_ESP) {
145ae67e3c4SGregory Etelson ret = mlx5_nta_ptype_rss_flow_create
146ae67e3c4SGregory Etelson (rss_ctx, ptype_l3 | ptype_l4_esp,
147ae67e3c4SGregory Etelson rss & ~(RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP));
148ae67e3c4SGregory Etelson if (ret)
149ae67e3c4SGregory Etelson goto error;
150ae67e3c4SGregory Etelson }
151ae67e3c4SGregory Etelson if (rss_types & RTE_ETH_RSS_UDP) {
152ae67e3c4SGregory Etelson ret = mlx5_nta_ptype_rss_flow_create(rss_ctx,
153ae67e3c4SGregory Etelson ptype_l3 | ptype_l4_udp,
154ae67e3c4SGregory Etelson rss & ~(RTE_ETH_RSS_ESP | RTE_ETH_RSS_TCP));
155ae67e3c4SGregory Etelson if (ret)
156ae67e3c4SGregory Etelson goto error;
157ae67e3c4SGregory Etelson }
158ae67e3c4SGregory Etelson if (rss_types & RTE_ETH_RSS_TCP) {
159ae67e3c4SGregory Etelson ret = mlx5_nta_ptype_rss_flow_create(rss_ctx,
160ae67e3c4SGregory Etelson ptype_l3 | ptype_l4_tcp,
161ae67e3c4SGregory Etelson rss & ~(RTE_ETH_RSS_ESP | RTE_ETH_RSS_UDP));
162ae67e3c4SGregory Etelson if (ret)
163ae67e3c4SGregory Etelson goto error;
164ae67e3c4SGregory Etelson }
165ae67e3c4SGregory Etelson return;
166ae67e3c4SGregory Etelson error:
167ae67e3c4SGregory Etelson flow_hw_list_destroy(rss_ctx->dev, rss_ctx->flow_type,
168ae67e3c4SGregory Etelson (uintptr_t)SLIST_FIRST(rss_ctx->head));
169ae67e3c4SGregory Etelson }
170ae67e3c4SGregory Etelson
171ae67e3c4SGregory Etelson /*
172ae67e3c4SGregory Etelson * Call conditions:
173ae67e3c4SGregory Etelson * * Flow pattern did not include L4 item.
174ae67e3c4SGregory Etelson * * RSS configuration had L4 hash types.
175ae67e3c4SGregory Etelson */
176ae67e3c4SGregory Etelson static struct rte_flow_hw *
mlx5_hw_rss_expand_l4(struct mlx5_nta_rss_ctx * rss_ctx)177ae67e3c4SGregory Etelson mlx5_hw_rss_expand_l4(struct mlx5_nta_rss_ctx *rss_ctx)
178ae67e3c4SGregory Etelson {
179ae67e3c4SGregory Etelson uint64_t rss_types = rte_eth_rss_hf_refine(rss_ctx->rss_conf->types);
180ae67e3c4SGregory Etelson uint64_t l3_item = rss_ctx->pattern_flags &
181ae67e3c4SGregory Etelson (rss_ctx->rss_conf->level < 2 ?
182ae67e3c4SGregory Etelson MLX5_FLOW_LAYER_OUTER_L3 : MLX5_FLOW_LAYER_INNER_L3);
183ae67e3c4SGregory Etelson
184ae67e3c4SGregory Etelson if (l3_item) {
185ae67e3c4SGregory Etelson /*
186ae67e3c4SGregory Etelson * Outer L3 header was present in the original pattern.
187ae67e3c4SGregory Etelson * Expand L4 level only.
188ae67e3c4SGregory Etelson */
189ae67e3c4SGregory Etelson if (l3_item & MLX5_FLOW_LAYER_L3_IPV4)
190ae67e3c4SGregory Etelson mlx5_nta_rss_expand_l3_l4(rss_ctx, rss_types, MLX5_IPV4_LAYER_TYPES);
191ae67e3c4SGregory Etelson else
192ae67e3c4SGregory Etelson mlx5_nta_rss_expand_l3_l4(rss_ctx, rss_types, MLX5_IPV6_LAYER_TYPES);
193ae67e3c4SGregory Etelson } else {
194ae67e3c4SGregory Etelson if (rss_types & (MLX5_IPV4_LAYER_TYPES | MLX5_IPV6_LAYER_TYPES)) {
195ae67e3c4SGregory Etelson mlx5_hw_rss_expand_l3(rss_ctx);
196ae67e3c4SGregory Etelson /*
197ae67e3c4SGregory Etelson * No outer L3 item in application flow pattern.
198ae67e3c4SGregory Etelson * RSS hash types are L3 and L4.
199ae67e3c4SGregory Etelson * ** Expand L3 according to RSS configuration and L4.
200ae67e3c4SGregory Etelson */
201ae67e3c4SGregory Etelson if (rss_types & MLX5_IPV4_LAYER_TYPES)
202ae67e3c4SGregory Etelson mlx5_nta_rss_expand_l3_l4(rss_ctx, rss_types,
203ae67e3c4SGregory Etelson MLX5_IPV4_LAYER_TYPES);
204ae67e3c4SGregory Etelson if (rss_types & MLX5_IPV6_LAYER_TYPES)
205ae67e3c4SGregory Etelson mlx5_nta_rss_expand_l3_l4(rss_ctx, rss_types,
206ae67e3c4SGregory Etelson MLX5_IPV6_LAYER_TYPES);
207ae67e3c4SGregory Etelson } else {
208ae67e3c4SGregory Etelson /*
209ae67e3c4SGregory Etelson * No outer L3 item in application flow pattern,
210ae67e3c4SGregory Etelson * RSS hash type is L4 only.
211ae67e3c4SGregory Etelson */
212ae67e3c4SGregory Etelson mlx5_nta_rss_expand_l3_l4(rss_ctx, rss_types,
213ae67e3c4SGregory Etelson MLX5_IPV4_LAYER_TYPES);
214ae67e3c4SGregory Etelson mlx5_nta_rss_expand_l3_l4(rss_ctx, rss_types,
215ae67e3c4SGregory Etelson MLX5_IPV6_LAYER_TYPES);
216ae67e3c4SGregory Etelson }
217ae67e3c4SGregory Etelson }
218ae67e3c4SGregory Etelson return SLIST_EMPTY(rss_ctx->head) ? NULL : SLIST_FIRST(rss_ctx->head);
219ae67e3c4SGregory Etelson }
220ae67e3c4SGregory Etelson
221ae67e3c4SGregory Etelson static struct mlx5_indexed_pool *
mlx5_nta_ptype_ipool_create(struct rte_eth_dev * dev)222ae67e3c4SGregory Etelson mlx5_nta_ptype_ipool_create(struct rte_eth_dev *dev)
223ae67e3c4SGregory Etelson {
224ae67e3c4SGregory Etelson struct mlx5_priv *priv = dev->data->dev_private;
225ae67e3c4SGregory Etelson struct mlx5_indexed_pool_config ipool_cfg = {
226ae67e3c4SGregory Etelson .size = 1,
227ae67e3c4SGregory Etelson .trunk_size = 32,
228ae67e3c4SGregory Etelson .grow_trunk = 5,
229ae67e3c4SGregory Etelson .grow_shift = 1,
230ae67e3c4SGregory Etelson .need_lock = 1,
231ae67e3c4SGregory Etelson .release_mem_en = !!priv->sh->config.reclaim_mode,
232ae67e3c4SGregory Etelson .malloc = mlx5_malloc,
233ae67e3c4SGregory Etelson .max_idx = MLX5_FLOW_TABLE_PTYPE_RSS_NUM,
234ae67e3c4SGregory Etelson .free = mlx5_free,
235ae67e3c4SGregory Etelson .type = "mlx5_nta_ptype_rss"
236ae67e3c4SGregory Etelson };
237ae67e3c4SGregory Etelson return mlx5_ipool_create(&ipool_cfg);
238ae67e3c4SGregory Etelson }
239ae67e3c4SGregory Etelson
240ae67e3c4SGregory Etelson static void
mlx5_hw_release_rss_ptype_group(struct rte_eth_dev * dev,uint32_t group)241ae67e3c4SGregory Etelson mlx5_hw_release_rss_ptype_group(struct rte_eth_dev *dev, uint32_t group)
242ae67e3c4SGregory Etelson {
243ae67e3c4SGregory Etelson struct mlx5_priv *priv = dev->data->dev_private;
244ae67e3c4SGregory Etelson
245ae67e3c4SGregory Etelson if (!priv->ptype_rss_groups)
246ae67e3c4SGregory Etelson return;
247ae67e3c4SGregory Etelson mlx5_ipool_free(priv->ptype_rss_groups, group);
248ae67e3c4SGregory Etelson }
249ae67e3c4SGregory Etelson
250ae67e3c4SGregory Etelson static uint32_t
mlx5_hw_get_rss_ptype_group(struct rte_eth_dev * dev)251ae67e3c4SGregory Etelson mlx5_hw_get_rss_ptype_group(struct rte_eth_dev *dev)
252ae67e3c4SGregory Etelson {
253ae67e3c4SGregory Etelson void *obj;
254ae67e3c4SGregory Etelson uint32_t idx = 0;
255ae67e3c4SGregory Etelson struct mlx5_priv *priv = dev->data->dev_private;
256ae67e3c4SGregory Etelson
257ae67e3c4SGregory Etelson if (!priv->ptype_rss_groups) {
258ae67e3c4SGregory Etelson priv->ptype_rss_groups = mlx5_nta_ptype_ipool_create(dev);
259ae67e3c4SGregory Etelson if (!priv->ptype_rss_groups) {
260ae67e3c4SGregory Etelson DRV_LOG(DEBUG, "PTYPE RSS: failed to allocate groups pool");
261ae67e3c4SGregory Etelson return 0;
262ae67e3c4SGregory Etelson }
263ae67e3c4SGregory Etelson }
264ae67e3c4SGregory Etelson obj = mlx5_ipool_malloc(priv->ptype_rss_groups, &idx);
265ae67e3c4SGregory Etelson if (!obj) {
266ae67e3c4SGregory Etelson DRV_LOG(DEBUG, "PTYPE RSS: failed to fetch ptype group from the pool");
267ae67e3c4SGregory Etelson return 0;
268ae67e3c4SGregory Etelson }
269ae67e3c4SGregory Etelson return idx + MLX5_FLOW_TABLE_PTYPE_RSS_BASE;
270ae67e3c4SGregory Etelson }
271ae67e3c4SGregory Etelson
272ae67e3c4SGregory Etelson static struct rte_flow_hw *
mlx5_hw_rss_ptype_create_miss_flow(struct rte_eth_dev * dev,const struct rte_flow_action_rss * rss_conf,uint32_t ptype_group,bool external,struct rte_flow_error * error)273ae67e3c4SGregory Etelson mlx5_hw_rss_ptype_create_miss_flow(struct rte_eth_dev *dev,
274ae67e3c4SGregory Etelson const struct rte_flow_action_rss *rss_conf,
275ae67e3c4SGregory Etelson uint32_t ptype_group, bool external,
276ae67e3c4SGregory Etelson struct rte_flow_error *error)
277ae67e3c4SGregory Etelson {
278ae67e3c4SGregory Etelson struct rte_flow_hw *flow = NULL;
279ae67e3c4SGregory Etelson const struct rte_flow_attr miss_attr = {
280ae67e3c4SGregory Etelson .ingress = 1,
281ae67e3c4SGregory Etelson .group = ptype_group,
282ae67e3c4SGregory Etelson .priority = 3
283ae67e3c4SGregory Etelson };
284ae67e3c4SGregory Etelson const struct rte_flow_item miss_pattern[2] = {
285ae67e3c4SGregory Etelson [0] = { .type = RTE_FLOW_ITEM_TYPE_ETH },
286ae67e3c4SGregory Etelson [1] = { .type = RTE_FLOW_ITEM_TYPE_END }
287ae67e3c4SGregory Etelson };
288ae67e3c4SGregory Etelson struct rte_flow_action miss_actions[] = {
289ae67e3c4SGregory Etelson #ifdef MLX5_RSS_PTYPE_DEBUG
290ae67e3c4SGregory Etelson [MLX5_RSS_PTYPE_ACTION_INDEX - 1] = {
291ae67e3c4SGregory Etelson .type = RTE_FLOW_ACTION_TYPE_MARK,
292ae67e3c4SGregory Etelson .conf = &(const struct rte_flow_action_mark){.id = 0xfac}
293ae67e3c4SGregory Etelson },
294ae67e3c4SGregory Etelson #endif
295ae67e3c4SGregory Etelson [MLX5_RSS_PTYPE_ACTION_INDEX] = {
296ae67e3c4SGregory Etelson .type = RTE_FLOW_ACTION_TYPE_RSS,
297ae67e3c4SGregory Etelson .conf = rss_conf
298ae67e3c4SGregory Etelson },
299ae67e3c4SGregory Etelson [MLX5_RSS_PTYPE_ACTION_INDEX + 1] = { .type = RTE_FLOW_ACTION_TYPE_END }
300ae67e3c4SGregory Etelson };
301ae67e3c4SGregory Etelson
302ae67e3c4SGregory Etelson flow_hw_create_flow(dev, MLX5_FLOW_TYPE_GEN, &miss_attr,
303ae67e3c4SGregory Etelson miss_pattern, miss_actions, 0, MLX5_FLOW_ACTION_RSS,
304ae67e3c4SGregory Etelson external, &flow, error);
305ae67e3c4SGregory Etelson return flow;
306ae67e3c4SGregory Etelson }
307ae67e3c4SGregory Etelson
308ae67e3c4SGregory Etelson static struct rte_flow_hw *
mlx5_hw_rss_ptype_create_base_flow(struct rte_eth_dev * dev,const struct rte_flow_attr * attr,const struct rte_flow_item pattern[],const struct rte_flow_action orig_actions[],uint32_t ptype_group,uint64_t item_flags,uint64_t action_flags,bool external,enum mlx5_flow_type flow_type,struct rte_flow_error * error)309ae67e3c4SGregory Etelson mlx5_hw_rss_ptype_create_base_flow(struct rte_eth_dev *dev,
310ae67e3c4SGregory Etelson const struct rte_flow_attr *attr,
311ae67e3c4SGregory Etelson const struct rte_flow_item pattern[],
312ae67e3c4SGregory Etelson const struct rte_flow_action orig_actions[],
313ae67e3c4SGregory Etelson uint32_t ptype_group, uint64_t item_flags,
314ae67e3c4SGregory Etelson uint64_t action_flags, bool external,
315ae67e3c4SGregory Etelson enum mlx5_flow_type flow_type,
316ae67e3c4SGregory Etelson struct rte_flow_error *error)
317ae67e3c4SGregory Etelson {
318ae67e3c4SGregory Etelson int i = 0;
319ae67e3c4SGregory Etelson struct rte_flow_hw *flow = NULL;
320ae67e3c4SGregory Etelson struct rte_flow_action actions[MLX5_HW_MAX_ACTS];
321ae67e3c4SGregory Etelson enum mlx5_indirect_type indirect_type;
322ae67e3c4SGregory Etelson
323ae67e3c4SGregory Etelson do {
324ae67e3c4SGregory Etelson switch (orig_actions[i].type) {
325ae67e3c4SGregory Etelson case RTE_FLOW_ACTION_TYPE_INDIRECT:
326ae67e3c4SGregory Etelson indirect_type = (typeof(indirect_type))
327ae67e3c4SGregory Etelson MLX5_INDIRECT_ACTION_TYPE_GET
328ae67e3c4SGregory Etelson (orig_actions[i].conf);
329ae67e3c4SGregory Etelson if (indirect_type != MLX5_INDIRECT_ACTION_TYPE_RSS) {
330ae67e3c4SGregory Etelson actions[i] = orig_actions[i];
331ae67e3c4SGregory Etelson break;
332ae67e3c4SGregory Etelson }
333ae67e3c4SGregory Etelson /* Fall through */
334ae67e3c4SGregory Etelson case RTE_FLOW_ACTION_TYPE_RSS:
335ae67e3c4SGregory Etelson actions[i].type = RTE_FLOW_ACTION_TYPE_JUMP;
336ae67e3c4SGregory Etelson actions[i].conf = &(const struct rte_flow_action_jump) {
337ae67e3c4SGregory Etelson .group = ptype_group
338ae67e3c4SGregory Etelson };
339ae67e3c4SGregory Etelson break;
340ae67e3c4SGregory Etelson default:
341ae67e3c4SGregory Etelson actions[i] = orig_actions[i];
342ae67e3c4SGregory Etelson }
343ae67e3c4SGregory Etelson
344ae67e3c4SGregory Etelson } while (actions[i++].type != RTE_FLOW_ACTION_TYPE_END);
345ae67e3c4SGregory Etelson action_flags &= ~MLX5_FLOW_ACTION_RSS;
346ae67e3c4SGregory Etelson action_flags |= MLX5_FLOW_ACTION_JUMP;
347ae67e3c4SGregory Etelson flow_hw_create_flow(dev, flow_type, attr, pattern, actions,
348ae67e3c4SGregory Etelson item_flags, action_flags, external, &flow, error);
349ae67e3c4SGregory Etelson return flow;
350ae67e3c4SGregory Etelson }
351ae67e3c4SGregory Etelson
352ae67e3c4SGregory Etelson const struct rte_flow_action_rss *
flow_nta_locate_rss(struct rte_eth_dev * dev,const struct rte_flow_action actions[],struct rte_flow_error * error)353ae67e3c4SGregory Etelson flow_nta_locate_rss(struct rte_eth_dev *dev,
354ae67e3c4SGregory Etelson const struct rte_flow_action actions[],
355ae67e3c4SGregory Etelson struct rte_flow_error *error)
356ae67e3c4SGregory Etelson {
357ae67e3c4SGregory Etelson const struct rte_flow_action *a;
358ae67e3c4SGregory Etelson const struct rte_flow_action_rss *rss_conf = NULL;
359ae67e3c4SGregory Etelson
360ae67e3c4SGregory Etelson for (a = actions; a->type != RTE_FLOW_ACTION_TYPE_END; a++) {
361ae67e3c4SGregory Etelson if (a->type == RTE_FLOW_ACTION_TYPE_RSS) {
362ae67e3c4SGregory Etelson rss_conf = a->conf;
363ae67e3c4SGregory Etelson break;
364ae67e3c4SGregory Etelson }
365ae67e3c4SGregory Etelson if (a->type == RTE_FLOW_ACTION_TYPE_INDIRECT &&
366ae67e3c4SGregory Etelson MLX5_INDIRECT_ACTION_TYPE_GET(a->conf) ==
367ae67e3c4SGregory Etelson MLX5_INDIRECT_ACTION_TYPE_RSS) {
368ae67e3c4SGregory Etelson struct mlx5_priv *priv = dev->data->dev_private;
369ae67e3c4SGregory Etelson struct mlx5_shared_action_rss *shared_rss;
370ae67e3c4SGregory Etelson uint32_t handle = (uint32_t)(uintptr_t)a->conf;
371ae67e3c4SGregory Etelson
372ae67e3c4SGregory Etelson shared_rss = mlx5_ipool_get
373ae67e3c4SGregory Etelson (priv->sh->ipool[MLX5_IPOOL_RSS_SHARED_ACTIONS],
374ae67e3c4SGregory Etelson MLX5_INDIRECT_ACTION_IDX_GET(handle));
375ae67e3c4SGregory Etelson if (!shared_rss) {
376ae67e3c4SGregory Etelson rte_flow_error_set(error, EINVAL,
377ae67e3c4SGregory Etelson RTE_FLOW_ERROR_TYPE_ACTION_CONF,
378ae67e3c4SGregory Etelson a->conf, "invalid shared RSS handle");
379ae67e3c4SGregory Etelson return NULL;
380ae67e3c4SGregory Etelson }
381ae67e3c4SGregory Etelson rss_conf = &shared_rss->origin;
382ae67e3c4SGregory Etelson break;
383ae67e3c4SGregory Etelson }
384ae67e3c4SGregory Etelson }
385ae67e3c4SGregory Etelson if (a->type == RTE_FLOW_ACTION_TYPE_END) {
386ae67e3c4SGregory Etelson rte_flow_error_set(error, 0, RTE_FLOW_ERROR_TYPE_NONE, NULL, NULL);
387ae67e3c4SGregory Etelson return NULL;
388ae67e3c4SGregory Etelson }
389ae67e3c4SGregory Etelson return rss_conf;
390ae67e3c4SGregory Etelson }
391ae67e3c4SGregory Etelson
392ae67e3c4SGregory Etelson static __rte_always_inline void
mlx5_nta_rss_init_ptype_ctx(struct mlx5_nta_rss_ctx * rss_ctx,struct rte_eth_dev * dev,struct rte_flow_attr * ptype_attr,struct rte_flow_item * ptype_pattern,struct rte_flow_action * ptype_actions,const struct rte_flow_action_rss * rss_conf,struct mlx5_nta_rss_flow_head * head,struct rte_flow_error * error,uint64_t item_flags,enum mlx5_flow_type flow_type,bool external)393ae67e3c4SGregory Etelson mlx5_nta_rss_init_ptype_ctx(struct mlx5_nta_rss_ctx *rss_ctx,
394ae67e3c4SGregory Etelson struct rte_eth_dev *dev,
395ae67e3c4SGregory Etelson struct rte_flow_attr *ptype_attr,
396ae67e3c4SGregory Etelson struct rte_flow_item *ptype_pattern,
397ae67e3c4SGregory Etelson struct rte_flow_action *ptype_actions,
398ae67e3c4SGregory Etelson const struct rte_flow_action_rss *rss_conf,
399ae67e3c4SGregory Etelson struct mlx5_nta_rss_flow_head *head,
400ae67e3c4SGregory Etelson struct rte_flow_error *error,
401ae67e3c4SGregory Etelson uint64_t item_flags,
402ae67e3c4SGregory Etelson enum mlx5_flow_type flow_type, bool external)
403ae67e3c4SGregory Etelson {
404ae67e3c4SGregory Etelson rss_ctx->dev = dev;
405ae67e3c4SGregory Etelson rss_ctx->attr = ptype_attr;
406ae67e3c4SGregory Etelson rss_ctx->pattern = ptype_pattern;
407ae67e3c4SGregory Etelson rss_ctx->actions = ptype_actions;
408ae67e3c4SGregory Etelson rss_ctx->rss_conf = rss_conf;
409ae67e3c4SGregory Etelson rss_ctx->error = error;
410ae67e3c4SGregory Etelson rss_ctx->head = head;
411ae67e3c4SGregory Etelson rss_ctx->pattern_flags = item_flags;
412ae67e3c4SGregory Etelson rss_ctx->flow_type = flow_type;
413ae67e3c4SGregory Etelson rss_ctx->external = external;
414ae67e3c4SGregory Etelson }
415ae67e3c4SGregory Etelson
416*f74914c9SGregory Etelson static struct rte_flow_hw *
flow_nta_create_single(struct rte_eth_dev * dev,const struct rte_flow_attr * attr,const struct rte_flow_item items[],const struct rte_flow_action actions[],struct rte_flow_action_rss * rss_conf,int64_t item_flags,uint64_t action_flags,bool external,bool copy_actions,enum mlx5_flow_type flow_type,struct rte_flow_error * error)417*f74914c9SGregory Etelson flow_nta_create_single(struct rte_eth_dev *dev,
418*f74914c9SGregory Etelson const struct rte_flow_attr *attr,
419*f74914c9SGregory Etelson const struct rte_flow_item items[],
420*f74914c9SGregory Etelson const struct rte_flow_action actions[],
421*f74914c9SGregory Etelson struct rte_flow_action_rss *rss_conf,
422*f74914c9SGregory Etelson int64_t item_flags, uint64_t action_flags,
423*f74914c9SGregory Etelson bool external, bool copy_actions,
424*f74914c9SGregory Etelson enum mlx5_flow_type flow_type,
425*f74914c9SGregory Etelson struct rte_flow_error *error)
426*f74914c9SGregory Etelson {
427*f74914c9SGregory Etelson struct rte_flow_hw *flow = NULL;
428*f74914c9SGregory Etelson struct rte_flow_action copy[MLX5_HW_MAX_ACTS];
429*f74914c9SGregory Etelson const struct rte_flow_action *_actions;
430*f74914c9SGregory Etelson
431*f74914c9SGregory Etelson if (copy_actions) {
432*f74914c9SGregory Etelson int i;
433*f74914c9SGregory Etelson
434*f74914c9SGregory Etelson _actions = copy;
435*f74914c9SGregory Etelson for (i = 0; ; i++) {
436*f74914c9SGregory Etelson copy[i] = actions[i];
437*f74914c9SGregory Etelson switch (actions[i].type) {
438*f74914c9SGregory Etelson case RTE_FLOW_ACTION_TYPE_RSS:
439*f74914c9SGregory Etelson copy[i].conf = rss_conf;
440*f74914c9SGregory Etelson break;
441*f74914c9SGregory Etelson case RTE_FLOW_ACTION_TYPE_INDIRECT:
442*f74914c9SGregory Etelson if (MLX5_INDIRECT_ACTION_TYPE_GET(actions[i].conf) ==
443*f74914c9SGregory Etelson MLX5_INDIRECT_ACTION_TYPE_RSS) {
444*f74914c9SGregory Etelson copy[i].type = RTE_FLOW_ACTION_TYPE_RSS;
445*f74914c9SGregory Etelson copy[i].conf = rss_conf;
446*f74914c9SGregory Etelson }
447*f74914c9SGregory Etelson break;
448*f74914c9SGregory Etelson case RTE_FLOW_ACTION_TYPE_END:
449*f74914c9SGregory Etelson goto end;
450*f74914c9SGregory Etelson default:
451*f74914c9SGregory Etelson break;
452*f74914c9SGregory Etelson }
453*f74914c9SGregory Etelson }
454*f74914c9SGregory Etelson } else {
455*f74914c9SGregory Etelson _actions = actions;
456*f74914c9SGregory Etelson }
457*f74914c9SGregory Etelson end:
458*f74914c9SGregory Etelson flow_hw_create_flow(dev, flow_type, attr, items,
459*f74914c9SGregory Etelson _actions, item_flags, action_flags,
460*f74914c9SGregory Etelson external, &flow, error);
461*f74914c9SGregory Etelson return flow;
462*f74914c9SGregory Etelson }
463*f74914c9SGregory Etelson
464ae67e3c4SGregory Etelson /*
465ae67e3c4SGregory Etelson * MLX5 HW hashes IPv4 and IPv6 L3 headers and UDP, TCP, ESP L4 headers.
466ae67e3c4SGregory Etelson * RSS expansion is required when RSS action was configured to hash
467ae67e3c4SGregory Etelson * network protocol that was not mentioned in flow pattern.
468ae67e3c4SGregory Etelson *
469ae67e3c4SGregory Etelson */
470ae67e3c4SGregory Etelson #define MLX5_PTYPE_RSS_OUTER_MASK (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L3_IPV6 | \
471ae67e3c4SGregory Etelson RTE_PTYPE_L4_UDP | RTE_PTYPE_L4_TCP | \
472ae67e3c4SGregory Etelson RTE_PTYPE_TUNNEL_ESP)
473ae67e3c4SGregory Etelson #define MLX5_PTYPE_RSS_INNER_MASK (RTE_PTYPE_INNER_L3_IPV4 | RTE_PTYPE_INNER_L3_IPV6 | \
474ae67e3c4SGregory Etelson RTE_PTYPE_INNER_L4_TCP | RTE_PTYPE_INNER_L4_UDP)
475ae67e3c4SGregory Etelson
476ae67e3c4SGregory Etelson struct rte_flow_hw *
flow_nta_handle_rss(struct rte_eth_dev * dev,const struct rte_flow_attr * attr,const struct rte_flow_item items[],const struct rte_flow_action actions[],const struct rte_flow_action_rss * rss_conf,uint64_t item_flags,uint64_t action_flags,bool external,enum mlx5_flow_type flow_type,struct rte_flow_error * error)477ae67e3c4SGregory Etelson flow_nta_handle_rss(struct rte_eth_dev *dev,
478ae67e3c4SGregory Etelson const struct rte_flow_attr *attr,
479ae67e3c4SGregory Etelson const struct rte_flow_item items[],
480ae67e3c4SGregory Etelson const struct rte_flow_action actions[],
481ae67e3c4SGregory Etelson const struct rte_flow_action_rss *rss_conf,
482ae67e3c4SGregory Etelson uint64_t item_flags, uint64_t action_flags,
483ae67e3c4SGregory Etelson bool external, enum mlx5_flow_type flow_type,
484ae67e3c4SGregory Etelson struct rte_flow_error *error)
485ae67e3c4SGregory Etelson {
486ae67e3c4SGregory Etelson struct rte_flow_hw *rss_base = NULL, *rss_next = NULL, *rss_miss = NULL;
487*f74914c9SGregory Etelson struct rte_flow_action_rss ptype_rss_conf = *rss_conf;
488ae67e3c4SGregory Etelson struct mlx5_nta_rss_ctx rss_ctx;
489ae67e3c4SGregory Etelson uint64_t rss_types = rte_eth_rss_hf_refine(rss_conf->types);
490a233fe1dSGregory Etelson bool expand = true;
491*f74914c9SGregory Etelson bool copy_actions = false;
492ae67e3c4SGregory Etelson bool inner_rss = rss_conf->level > 1;
493ae67e3c4SGregory Etelson bool outer_rss = !inner_rss;
494ae67e3c4SGregory Etelson bool l3_item = (outer_rss && (item_flags & MLX5_FLOW_LAYER_OUTER_L3)) ||
495ae67e3c4SGregory Etelson (inner_rss && (item_flags & MLX5_FLOW_LAYER_INNER_L3));
496ae67e3c4SGregory Etelson bool l4_item = (outer_rss && (item_flags & MLX5_FLOW_LAYER_OUTER_L4)) ||
497ae67e3c4SGregory Etelson (inner_rss && (item_flags & MLX5_FLOW_LAYER_INNER_L4));
498ae67e3c4SGregory Etelson bool l3_hash = rss_types & (MLX5_IPV4_LAYER_TYPES | MLX5_IPV6_LAYER_TYPES);
499ae67e3c4SGregory Etelson bool l4_hash = rss_types & (RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_ESP);
500ae67e3c4SGregory Etelson struct mlx5_nta_rss_flow_head expansion_head = SLIST_HEAD_INITIALIZER(0);
501ae67e3c4SGregory Etelson struct rte_flow_attr ptype_attr = {
502ae67e3c4SGregory Etelson .ingress = 1
503ae67e3c4SGregory Etelson };
504ae67e3c4SGregory Etelson struct rte_flow_item_ptype ptype_spec = { .packet_type = 0 };
505ae67e3c4SGregory Etelson const struct rte_flow_item_ptype ptype_mask = {
506ae67e3c4SGregory Etelson .packet_type = outer_rss ?
507ae67e3c4SGregory Etelson MLX5_PTYPE_RSS_OUTER_MASK : MLX5_PTYPE_RSS_INNER_MASK
508ae67e3c4SGregory Etelson };
509ae67e3c4SGregory Etelson struct rte_flow_item ptype_pattern[MLX5_RSS_PTYPE_ITEMS_NUM] = {
510ae67e3c4SGregory Etelson [MLX5_RSS_PTYPE_ITEM_INDEX] = {
511ae67e3c4SGregory Etelson .type = RTE_FLOW_ITEM_TYPE_PTYPE,
512ae67e3c4SGregory Etelson .spec = &ptype_spec,
513ae67e3c4SGregory Etelson .mask = &ptype_mask
514ae67e3c4SGregory Etelson },
515ae67e3c4SGregory Etelson [MLX5_RSS_PTYPE_ITEM_INDEX + 1] = { .type = RTE_FLOW_ITEM_TYPE_END }
516ae67e3c4SGregory Etelson };
517ae67e3c4SGregory Etelson struct rte_flow_action ptype_actions[MLX5_RSS_PTYPE_ACTIONS_NUM] = {
518ae67e3c4SGregory Etelson #ifdef MLX5_RSS_PTYPE_DEBUG
519ae67e3c4SGregory Etelson [MLX5_RSS_PTYPE_ACTION_INDEX - 1] = {
520ae67e3c4SGregory Etelson .type = RTE_FLOW_ACTION_TYPE_MARK,
521ae67e3c4SGregory Etelson .conf = &(const struct rte_flow_action_mark) {.id = 101}
522ae67e3c4SGregory Etelson },
523ae67e3c4SGregory Etelson #endif
524ae67e3c4SGregory Etelson [MLX5_RSS_PTYPE_ACTION_INDEX] = {
525ae67e3c4SGregory Etelson .type = RTE_FLOW_ACTION_TYPE_RSS,
526ae67e3c4SGregory Etelson .conf = &ptype_rss_conf
527ae67e3c4SGregory Etelson },
528ae67e3c4SGregory Etelson [MLX5_RSS_PTYPE_ACTION_INDEX + 1] = { .type = RTE_FLOW_ACTION_TYPE_END }
529ae67e3c4SGregory Etelson };
530ae67e3c4SGregory Etelson
531*f74914c9SGregory Etelson ptype_rss_conf.types = rss_types;
532ae67e3c4SGregory Etelson if (l4_item) {
533ae67e3c4SGregory Etelson /*
534ae67e3c4SGregory Etelson * Original flow pattern extended up to L4 level.
535ae67e3c4SGregory Etelson * L4 is the maximal expansion level.
536ae67e3c4SGregory Etelson * Original pattern does not need expansion.
537ae67e3c4SGregory Etelson */
538a233fe1dSGregory Etelson expand = false;
539a233fe1dSGregory Etelson } else if (!l4_hash) {
540ae67e3c4SGregory Etelson if (!l3_hash) {
541ae67e3c4SGregory Etelson /*
542ae67e3c4SGregory Etelson * RSS action was not configured to hash L3 or L4.
543ae67e3c4SGregory Etelson * No expansion needed.
544ae67e3c4SGregory Etelson */
545a233fe1dSGregory Etelson expand = false;
546a233fe1dSGregory Etelson } else if (l3_item) {
547ae67e3c4SGregory Etelson /*
548ae67e3c4SGregory Etelson * Original flow pattern extended up to L3 level.
549ae67e3c4SGregory Etelson * RSS action was not set for L4 hash.
550ae67e3c4SGregory Etelson */
551*f74914c9SGregory Etelson bool ip4_item =
552*f74914c9SGregory Etelson (outer_rss && (item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV4)) ||
553*f74914c9SGregory Etelson (inner_rss && (item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV4));
554*f74914c9SGregory Etelson bool ip6_item =
555*f74914c9SGregory Etelson (outer_rss && (item_flags & MLX5_FLOW_LAYER_OUTER_L3_IPV6)) ||
556*f74914c9SGregory Etelson (inner_rss && (item_flags & MLX5_FLOW_LAYER_INNER_L3_IPV6));
557*f74914c9SGregory Etelson bool ip4_hash = rss_types & MLX5_IPV4_LAYER_TYPES;
558*f74914c9SGregory Etelson bool ip6_hash = rss_types & MLX5_IPV6_LAYER_TYPES;
559a233fe1dSGregory Etelson
560*f74914c9SGregory Etelson expand = false;
561*f74914c9SGregory Etelson if (ip4_item && ip4_hash) {
562*f74914c9SGregory Etelson ptype_rss_conf.types &= ~MLX5_IPV6_LAYER_TYPES;
563*f74914c9SGregory Etelson copy_actions = true;
564*f74914c9SGregory Etelson } else if (ip6_item && ip6_hash) {
565*f74914c9SGregory Etelson /*
566*f74914c9SGregory Etelson * MLX5 HW will not activate TIR IPv6 hash
567*f74914c9SGregory Etelson * if that TIR has also IPv4 hash
568*f74914c9SGregory Etelson */
569*f74914c9SGregory Etelson ptype_rss_conf.types &= ~MLX5_IPV4_LAYER_TYPES;
570*f74914c9SGregory Etelson copy_actions = true;
571a233fe1dSGregory Etelson }
572*f74914c9SGregory Etelson }
573*f74914c9SGregory Etelson }
574*f74914c9SGregory Etelson if (!expand)
575*f74914c9SGregory Etelson return flow_nta_create_single(dev, attr, items, actions,
576*f74914c9SGregory Etelson &ptype_rss_conf, item_flags,
577*f74914c9SGregory Etelson action_flags, external,
578*f74914c9SGregory Etelson copy_actions, flow_type, error);
579ae67e3c4SGregory Etelson /* Create RSS expansions in dedicated PTYPE flow group */
580ae67e3c4SGregory Etelson ptype_attr.group = mlx5_hw_get_rss_ptype_group(dev);
581ae67e3c4SGregory Etelson if (!ptype_attr.group) {
582ae67e3c4SGregory Etelson rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ATTR_GROUP,
583ae67e3c4SGregory Etelson NULL, "cannot get RSS PTYPE group");
584ae67e3c4SGregory Etelson return NULL;
585ae67e3c4SGregory Etelson }
586ae67e3c4SGregory Etelson mlx5_nta_rss_init_ptype_ctx(&rss_ctx, dev, &ptype_attr, ptype_pattern,
587*f74914c9SGregory Etelson ptype_actions, &ptype_rss_conf, &expansion_head,
588ae67e3c4SGregory Etelson error, item_flags, flow_type, external);
589*f74914c9SGregory Etelson rss_miss = mlx5_hw_rss_ptype_create_miss_flow(dev, &ptype_rss_conf, ptype_attr.group,
590ae67e3c4SGregory Etelson external, error);
591ae67e3c4SGregory Etelson if (!rss_miss)
592ae67e3c4SGregory Etelson goto error;
593ae67e3c4SGregory Etelson if (l4_hash) {
594ae67e3c4SGregory Etelson rss_next = mlx5_hw_rss_expand_l4(&rss_ctx);
595ae67e3c4SGregory Etelson if (!rss_next)
596ae67e3c4SGregory Etelson goto error;
597ae67e3c4SGregory Etelson } else if (l3_hash) {
598ae67e3c4SGregory Etelson rss_next = mlx5_hw_rss_expand_l3(&rss_ctx);
599ae67e3c4SGregory Etelson if (!rss_next)
600ae67e3c4SGregory Etelson goto error;
601ae67e3c4SGregory Etelson }
602ae67e3c4SGregory Etelson rss_base = mlx5_hw_rss_ptype_create_base_flow(dev, attr, items, actions,
603ae67e3c4SGregory Etelson ptype_attr.group, item_flags,
604ae67e3c4SGregory Etelson action_flags, external,
605ae67e3c4SGregory Etelson flow_type, error);
606ae67e3c4SGregory Etelson if (!rss_base)
607ae67e3c4SGregory Etelson goto error;
608ae67e3c4SGregory Etelson SLIST_INSERT_HEAD(&expansion_head, rss_miss, nt2hws->next);
609ae67e3c4SGregory Etelson SLIST_INSERT_HEAD(&expansion_head, rss_base, nt2hws->next);
610ae67e3c4SGregory Etelson /**
611ae67e3c4SGregory Etelson * PMD must return to application a reference to the base flow.
612ae67e3c4SGregory Etelson * This way RSS expansion could work with counter, meter and other
613ae67e3c4SGregory Etelson * flow actions.
614ae67e3c4SGregory Etelson */
615ae67e3c4SGregory Etelson MLX5_ASSERT(rss_base == SLIST_FIRST(&expansion_head));
616ae67e3c4SGregory Etelson rss_next = SLIST_NEXT(rss_base, nt2hws->next);
617ae67e3c4SGregory Etelson while (rss_next) {
618ae67e3c4SGregory Etelson rss_next->nt2hws->chaned_flow = 1;
619ae67e3c4SGregory Etelson rss_next = SLIST_NEXT(rss_next, nt2hws->next);
620ae67e3c4SGregory Etelson }
621ae67e3c4SGregory Etelson return SLIST_FIRST(&expansion_head);
622ae67e3c4SGregory Etelson
623ae67e3c4SGregory Etelson error:
624ae67e3c4SGregory Etelson if (rss_miss)
625ae67e3c4SGregory Etelson flow_hw_list_destroy(dev, flow_type, (uintptr_t)rss_miss);
626ae67e3c4SGregory Etelson if (rss_next)
627ae67e3c4SGregory Etelson flow_hw_list_destroy(dev, flow_type, (uintptr_t)rss_next);
628ae67e3c4SGregory Etelson mlx5_hw_release_rss_ptype_group(dev, ptype_attr.group);
629ae67e3c4SGregory Etelson return NULL;
630ae67e3c4SGregory Etelson }
631ae67e3c4SGregory Etelson
632ae67e3c4SGregory Etelson #endif
633ae67e3c4SGregory Etelson
634