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 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 * 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 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 * 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 * 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 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 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 * 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 * 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 * 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 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 416ae67e3c4SGregory Etelson /* 417ae67e3c4SGregory Etelson * MLX5 HW hashes IPv4 and IPv6 L3 headers and UDP, TCP, ESP L4 headers. 418ae67e3c4SGregory Etelson * RSS expansion is required when RSS action was configured to hash 419ae67e3c4SGregory Etelson * network protocol that was not mentioned in flow pattern. 420ae67e3c4SGregory Etelson * 421ae67e3c4SGregory Etelson */ 422ae67e3c4SGregory Etelson #define MLX5_PTYPE_RSS_OUTER_MASK (RTE_PTYPE_L3_IPV4 | RTE_PTYPE_L3_IPV6 | \ 423ae67e3c4SGregory Etelson RTE_PTYPE_L4_UDP | RTE_PTYPE_L4_TCP | \ 424ae67e3c4SGregory Etelson RTE_PTYPE_TUNNEL_ESP) 425ae67e3c4SGregory Etelson #define MLX5_PTYPE_RSS_INNER_MASK (RTE_PTYPE_INNER_L3_IPV4 | RTE_PTYPE_INNER_L3_IPV6 | \ 426ae67e3c4SGregory Etelson RTE_PTYPE_INNER_L4_TCP | RTE_PTYPE_INNER_L4_UDP) 427ae67e3c4SGregory Etelson 428ae67e3c4SGregory Etelson struct rte_flow_hw * 429ae67e3c4SGregory Etelson flow_nta_handle_rss(struct rte_eth_dev *dev, 430ae67e3c4SGregory Etelson const struct rte_flow_attr *attr, 431ae67e3c4SGregory Etelson const struct rte_flow_item items[], 432ae67e3c4SGregory Etelson const struct rte_flow_action actions[], 433ae67e3c4SGregory Etelson const struct rte_flow_action_rss *rss_conf, 434ae67e3c4SGregory Etelson uint64_t item_flags, uint64_t action_flags, 435ae67e3c4SGregory Etelson bool external, enum mlx5_flow_type flow_type, 436ae67e3c4SGregory Etelson struct rte_flow_error *error) 437ae67e3c4SGregory Etelson { 438ae67e3c4SGregory Etelson struct rte_flow_hw *rss_base = NULL, *rss_next = NULL, *rss_miss = NULL; 439ae67e3c4SGregory Etelson struct rte_flow_action_rss ptype_rss_conf; 440ae67e3c4SGregory Etelson struct mlx5_nta_rss_ctx rss_ctx; 441ae67e3c4SGregory Etelson uint64_t rss_types = rte_eth_rss_hf_refine(rss_conf->types); 442*a233fe1dSGregory Etelson bool expand = true; 443ae67e3c4SGregory Etelson bool inner_rss = rss_conf->level > 1; 444ae67e3c4SGregory Etelson bool outer_rss = !inner_rss; 445ae67e3c4SGregory Etelson bool l3_item = (outer_rss && (item_flags & MLX5_FLOW_LAYER_OUTER_L3)) || 446ae67e3c4SGregory Etelson (inner_rss && (item_flags & MLX5_FLOW_LAYER_INNER_L3)); 447ae67e3c4SGregory Etelson bool l4_item = (outer_rss && (item_flags & MLX5_FLOW_LAYER_OUTER_L4)) || 448ae67e3c4SGregory Etelson (inner_rss && (item_flags & MLX5_FLOW_LAYER_INNER_L4)); 449ae67e3c4SGregory Etelson bool l3_hash = rss_types & (MLX5_IPV4_LAYER_TYPES | MLX5_IPV6_LAYER_TYPES); 450ae67e3c4SGregory Etelson bool l4_hash = rss_types & (RTE_ETH_RSS_UDP | RTE_ETH_RSS_TCP | RTE_ETH_RSS_ESP); 451ae67e3c4SGregory Etelson struct mlx5_nta_rss_flow_head expansion_head = SLIST_HEAD_INITIALIZER(0); 452ae67e3c4SGregory Etelson struct rte_flow_attr ptype_attr = { 453ae67e3c4SGregory Etelson .ingress = 1 454ae67e3c4SGregory Etelson }; 455ae67e3c4SGregory Etelson struct rte_flow_item_ptype ptype_spec = { .packet_type = 0 }; 456ae67e3c4SGregory Etelson const struct rte_flow_item_ptype ptype_mask = { 457ae67e3c4SGregory Etelson .packet_type = outer_rss ? 458ae67e3c4SGregory Etelson MLX5_PTYPE_RSS_OUTER_MASK : MLX5_PTYPE_RSS_INNER_MASK 459ae67e3c4SGregory Etelson }; 460ae67e3c4SGregory Etelson struct rte_flow_item ptype_pattern[MLX5_RSS_PTYPE_ITEMS_NUM] = { 461ae67e3c4SGregory Etelson [MLX5_RSS_PTYPE_ITEM_INDEX] = { 462ae67e3c4SGregory Etelson .type = RTE_FLOW_ITEM_TYPE_PTYPE, 463ae67e3c4SGregory Etelson .spec = &ptype_spec, 464ae67e3c4SGregory Etelson .mask = &ptype_mask 465ae67e3c4SGregory Etelson }, 466ae67e3c4SGregory Etelson [MLX5_RSS_PTYPE_ITEM_INDEX + 1] = { .type = RTE_FLOW_ITEM_TYPE_END } 467ae67e3c4SGregory Etelson }; 468ae67e3c4SGregory Etelson struct rte_flow_action ptype_actions[MLX5_RSS_PTYPE_ACTIONS_NUM] = { 469ae67e3c4SGregory Etelson #ifdef MLX5_RSS_PTYPE_DEBUG 470ae67e3c4SGregory Etelson [MLX5_RSS_PTYPE_ACTION_INDEX - 1] = { 471ae67e3c4SGregory Etelson .type = RTE_FLOW_ACTION_TYPE_MARK, 472ae67e3c4SGregory Etelson .conf = &(const struct rte_flow_action_mark) {.id = 101} 473ae67e3c4SGregory Etelson }, 474ae67e3c4SGregory Etelson #endif 475ae67e3c4SGregory Etelson [MLX5_RSS_PTYPE_ACTION_INDEX] = { 476ae67e3c4SGregory Etelson .type = RTE_FLOW_ACTION_TYPE_RSS, 477ae67e3c4SGregory Etelson .conf = &ptype_rss_conf 478ae67e3c4SGregory Etelson }, 479ae67e3c4SGregory Etelson [MLX5_RSS_PTYPE_ACTION_INDEX + 1] = { .type = RTE_FLOW_ACTION_TYPE_END } 480ae67e3c4SGregory Etelson }; 481ae67e3c4SGregory Etelson 482ae67e3c4SGregory Etelson if (l4_item) { 483ae67e3c4SGregory Etelson /* 484ae67e3c4SGregory Etelson * Original flow pattern extended up to L4 level. 485ae67e3c4SGregory Etelson * L4 is the maximal expansion level. 486ae67e3c4SGregory Etelson * Original pattern does not need expansion. 487ae67e3c4SGregory Etelson */ 488*a233fe1dSGregory Etelson expand = false; 489*a233fe1dSGregory Etelson } else if (!l4_hash) { 490ae67e3c4SGregory Etelson if (!l3_hash) { 491ae67e3c4SGregory Etelson /* 492ae67e3c4SGregory Etelson * RSS action was not configured to hash L3 or L4. 493ae67e3c4SGregory Etelson * No expansion needed. 494ae67e3c4SGregory Etelson */ 495*a233fe1dSGregory Etelson expand = false; 496*a233fe1dSGregory Etelson } else if (l3_item) { 497ae67e3c4SGregory Etelson /* 498ae67e3c4SGregory Etelson * Original flow pattern extended up to L3 level. 499ae67e3c4SGregory Etelson * RSS action was not set for L4 hash. 500ae67e3c4SGregory Etelson * Original pattern does not need expansion. 501ae67e3c4SGregory Etelson */ 502*a233fe1dSGregory Etelson expand = false; 503ae67e3c4SGregory Etelson } 504ae67e3c4SGregory Etelson } 505*a233fe1dSGregory Etelson if (!expand) { 506*a233fe1dSGregory Etelson struct rte_flow_hw *flow = NULL; 507*a233fe1dSGregory Etelson 508*a233fe1dSGregory Etelson flow_hw_create_flow(dev, flow_type, attr, items, 509*a233fe1dSGregory Etelson actions, item_flags, action_flags, 510*a233fe1dSGregory Etelson external, &flow, error); 511*a233fe1dSGregory Etelson return flow; 512*a233fe1dSGregory Etelson } 513ae67e3c4SGregory Etelson /* Create RSS expansions in dedicated PTYPE flow group */ 514ae67e3c4SGregory Etelson ptype_attr.group = mlx5_hw_get_rss_ptype_group(dev); 515ae67e3c4SGregory Etelson if (!ptype_attr.group) { 516ae67e3c4SGregory Etelson rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ATTR_GROUP, 517ae67e3c4SGregory Etelson NULL, "cannot get RSS PTYPE group"); 518ae67e3c4SGregory Etelson return NULL; 519ae67e3c4SGregory Etelson } 520ae67e3c4SGregory Etelson ptype_rss_conf = *rss_conf; 521ae67e3c4SGregory Etelson mlx5_nta_rss_init_ptype_ctx(&rss_ctx, dev, &ptype_attr, ptype_pattern, 522ae67e3c4SGregory Etelson ptype_actions, rss_conf, &expansion_head, 523ae67e3c4SGregory Etelson error, item_flags, flow_type, external); 524ae67e3c4SGregory Etelson rss_miss = mlx5_hw_rss_ptype_create_miss_flow(dev, rss_conf, ptype_attr.group, 525ae67e3c4SGregory Etelson external, error); 526ae67e3c4SGregory Etelson if (!rss_miss) 527ae67e3c4SGregory Etelson goto error; 528ae67e3c4SGregory Etelson if (l4_hash) { 529ae67e3c4SGregory Etelson rss_next = mlx5_hw_rss_expand_l4(&rss_ctx); 530ae67e3c4SGregory Etelson if (!rss_next) 531ae67e3c4SGregory Etelson goto error; 532ae67e3c4SGregory Etelson } else if (l3_hash) { 533ae67e3c4SGregory Etelson rss_next = mlx5_hw_rss_expand_l3(&rss_ctx); 534ae67e3c4SGregory Etelson if (!rss_next) 535ae67e3c4SGregory Etelson goto error; 536ae67e3c4SGregory Etelson } 537ae67e3c4SGregory Etelson rss_base = mlx5_hw_rss_ptype_create_base_flow(dev, attr, items, actions, 538ae67e3c4SGregory Etelson ptype_attr.group, item_flags, 539ae67e3c4SGregory Etelson action_flags, external, 540ae67e3c4SGregory Etelson flow_type, error); 541ae67e3c4SGregory Etelson if (!rss_base) 542ae67e3c4SGregory Etelson goto error; 543ae67e3c4SGregory Etelson SLIST_INSERT_HEAD(&expansion_head, rss_miss, nt2hws->next); 544ae67e3c4SGregory Etelson SLIST_INSERT_HEAD(&expansion_head, rss_base, nt2hws->next); 545ae67e3c4SGregory Etelson /** 546ae67e3c4SGregory Etelson * PMD must return to application a reference to the base flow. 547ae67e3c4SGregory Etelson * This way RSS expansion could work with counter, meter and other 548ae67e3c4SGregory Etelson * flow actions. 549ae67e3c4SGregory Etelson */ 550ae67e3c4SGregory Etelson MLX5_ASSERT(rss_base == SLIST_FIRST(&expansion_head)); 551ae67e3c4SGregory Etelson rss_next = SLIST_NEXT(rss_base, nt2hws->next); 552ae67e3c4SGregory Etelson while (rss_next) { 553ae67e3c4SGregory Etelson rss_next->nt2hws->chaned_flow = 1; 554ae67e3c4SGregory Etelson rss_next = SLIST_NEXT(rss_next, nt2hws->next); 555ae67e3c4SGregory Etelson } 556ae67e3c4SGregory Etelson return SLIST_FIRST(&expansion_head); 557ae67e3c4SGregory Etelson 558ae67e3c4SGregory Etelson error: 559ae67e3c4SGregory Etelson if (rss_miss) 560ae67e3c4SGregory Etelson flow_hw_list_destroy(dev, flow_type, (uintptr_t)rss_miss); 561ae67e3c4SGregory Etelson if (rss_next) 562ae67e3c4SGregory Etelson flow_hw_list_destroy(dev, flow_type, (uintptr_t)rss_next); 563ae67e3c4SGregory Etelson mlx5_hw_release_rss_ptype_group(dev, ptype_attr.group); 564ae67e3c4SGregory Etelson return NULL; 565ae67e3c4SGregory Etelson } 566ae67e3c4SGregory Etelson 567ae67e3c4SGregory Etelson #endif 568ae67e3c4SGregory Etelson 569