net/mlx5e: Support flow classification into RSS contexts
authorTariq Toukan <tariqt@nvidia.com>
Mon, 16 Aug 2021 13:31:57 +0000 (16:31 +0300)
committerSaeed Mahameed <saeedm@nvidia.com>
Mon, 16 Aug 2021 23:17:28 +0000 (16:17 -0700)
Extend the existing flow classification support, to steer
flows not only directly to a receive ring, but also into
the new RSS contexts.

Create needed TIR objects on demand, and hold reference
on the RSS context.

Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
Reviewed-by: Maxim Mikityanskiy <maximmi@nvidia.com>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
drivers/net/ethernet/mellanox/mlx5/core/en/rss.c
drivers/net/ethernet/mellanox/mlx5/core/en/rss.h
drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c
drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h
drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c

index d2c4ace..625cd49 100644 (file)
@@ -367,6 +367,30 @@ u32 mlx5e_rss_get_tirn(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
        return mlx5e_tir_get_tirn(tir);
 }
 
+/* Fill the "tirn" output parameter.
+ * Create the requested TIR if it's its first usage.
+ */
+int mlx5e_rss_obtain_tirn(struct mlx5e_rss *rss,
+                         enum mlx5_traffic_types tt,
+                         const struct mlx5e_lro_param *init_lro_param,
+                         bool inner, u32 *tirn)
+{
+       struct mlx5e_tir *tir;
+
+       tir = rss_get_tir(rss, tt, inner);
+       if (!tir) { /* TIR doesn't exist, create one */
+               int err;
+
+               err = mlx5e_rss_create_tir(rss, tt, init_lro_param, inner);
+               if (err)
+                       return err;
+               tir = rss_get_tir(rss, tt, inner);
+       }
+
+       *tirn = mlx5e_tir_get_tirn(tir);
+       return 0;
+}
+
 static void mlx5e_rss_apply(struct mlx5e_rss *rss, u32 *rqns, unsigned int num_rqns)
 {
        int err;
index 6f52d78..d522a10 100644 (file)
@@ -28,6 +28,11 @@ unsigned int mlx5e_rss_refcnt_read(struct mlx5e_rss *rss);
 
 u32 mlx5e_rss_get_tirn(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
                       bool inner);
+int mlx5e_rss_obtain_tirn(struct mlx5e_rss *rss,
+                         enum mlx5_traffic_types tt,
+                         const struct mlx5e_lro_param *init_lro_param,
+                         bool inner, u32 *tirn);
+
 void mlx5e_rss_enable(struct mlx5e_rss *rss, u32 *rqns, unsigned int num_rqns);
 void mlx5e_rss_disable(struct mlx5e_rss *rss);
 
index 4329635..bf0313e 100644 (file)
@@ -245,6 +245,28 @@ int mlx5e_rx_res_rss_cnt(struct mlx5e_rx_res *res)
        return cnt;
 }
 
+int mlx5e_rx_res_rss_index(struct mlx5e_rx_res *res, struct mlx5e_rss *rss)
+{
+       int i;
+
+       if (!rss)
+               return -EINVAL;
+
+       for (i = 0; i < MLX5E_MAX_NUM_RSS; i++)
+               if (rss == res->rss[i])
+                       return i;
+
+       return -ENOENT;
+}
+
+struct mlx5e_rss *mlx5e_rx_res_rss_get(struct mlx5e_rx_res *res, u32 rss_idx)
+{
+       if (rss_idx >= MLX5E_MAX_NUM_RSS)
+               return NULL;
+
+       return res->rss[rss_idx];
+}
+
 /* End of API rx_res_rss_* */
 
 struct mlx5e_rx_res *mlx5e_rx_res_alloc(void)
index 8248caa..4a15942 100644 (file)
@@ -62,6 +62,8 @@ int mlx5e_rx_res_lro_set_param(struct mlx5e_rx_res *res, struct mlx5e_lro_param
 int mlx5e_rx_res_rss_init(struct mlx5e_rx_res *res, u32 *rss_idx, unsigned int init_nch);
 int mlx5e_rx_res_rss_destroy(struct mlx5e_rx_res *res, u32 rss_idx);
 int mlx5e_rx_res_rss_cnt(struct mlx5e_rx_res *res);
+int mlx5e_rx_res_rss_index(struct mlx5e_rx_res *res, struct mlx5e_rss *rss);
+struct mlx5e_rss *mlx5e_rx_res_rss_get(struct mlx5e_rx_res *res, u32 rss_idx);
 
 /* Workaround for hairpin */
 struct mlx5e_rss_params_hash mlx5e_rx_res_get_current_hash(struct mlx5e_rx_res *res);
index 3d8918f..03693fa 100644 (file)
 #include "en/params.h"
 #include "en/xsk/pool.h"
 
+static int flow_type_to_traffic_type(u32 flow_type);
+
+static u32 flow_type_mask(u32 flow_type)
+{
+       return flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS);
+}
+
 struct mlx5e_ethtool_rule {
        struct list_head             list;
        struct ethtool_rx_flow_spec  flow_spec;
        struct mlx5_flow_handle      *rule;
        struct mlx5e_ethtool_table   *eth_ft;
+       struct mlx5e_rss             *rss;
 };
 
 static void put_flow_table(struct mlx5e_ethtool_table *eth_ft)
@@ -66,7 +74,7 @@ static struct mlx5e_ethtool_table *get_flow_table(struct mlx5e_priv *priv,
        int table_size;
        int prio;
 
-       switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
+       switch (flow_type_mask(fs->flow_type)) {
        case TCP_V4_FLOW:
        case UDP_V4_FLOW:
        case TCP_V6_FLOW:
@@ -329,7 +337,7 @@ static int set_flow_attrs(u32 *match_c, u32 *match_v,
                                             outer_headers);
        void *outer_headers_v = MLX5_ADDR_OF(fte_match_param, match_v,
                                             outer_headers);
-       u32 flow_type = fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT);
+       u32 flow_type = flow_type_mask(fs->flow_type);
 
        switch (flow_type) {
        case TCP_V4_FLOW:
@@ -397,10 +405,53 @@ static bool outer_header_zero(u32 *match_criteria)
                                                  size - 1);
 }
 
+static int flow_get_tirn(struct mlx5e_priv *priv,
+                        struct mlx5e_ethtool_rule *eth_rule,
+                        struct ethtool_rx_flow_spec *fs,
+                        u32 rss_context, u32 *tirn)
+{
+       if (fs->flow_type & FLOW_RSS) {
+               struct mlx5e_lro_param lro_param;
+               struct mlx5e_rss *rss;
+               u32 flow_type;
+               int err;
+               int tt;
+
+               rss = mlx5e_rx_res_rss_get(priv->rx_res, rss_context);
+               if (!rss)
+                       return -ENOENT;
+
+               flow_type = flow_type_mask(fs->flow_type);
+               tt = flow_type_to_traffic_type(flow_type);
+               if (tt < 0)
+                       return -EINVAL;
+
+               lro_param = mlx5e_get_lro_param(&priv->channels.params);
+               err = mlx5e_rss_obtain_tirn(rss, tt, &lro_param, false, tirn);
+               if (err)
+                       return err;
+               eth_rule->rss = rss;
+               mlx5e_rss_refcnt_inc(eth_rule->rss);
+       } else {
+               struct mlx5e_params *params = &priv->channels.params;
+               enum mlx5e_rq_group group;
+               u16 ix;
+
+               mlx5e_qid_get_ch_and_group(params, fs->ring_cookie, &ix, &group);
+
+               *tirn = group == MLX5E_RQ_GROUP_XSK ?
+                       mlx5e_rx_res_get_tirn_xsk(priv->rx_res, ix) :
+                       mlx5e_rx_res_get_tirn_direct(priv->rx_res, ix);
+       }
+
+       return 0;
+}
+
 static struct mlx5_flow_handle *
 add_ethtool_flow_rule(struct mlx5e_priv *priv,
+                     struct mlx5e_ethtool_rule *eth_rule,
                      struct mlx5_flow_table *ft,
-                     struct ethtool_rx_flow_spec *fs)
+                     struct ethtool_rx_flow_spec *fs, u32 rss_context)
 {
        struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND };
        struct mlx5_flow_destination *dst = NULL;
@@ -419,23 +470,17 @@ add_ethtool_flow_rule(struct mlx5e_priv *priv,
        if (fs->ring_cookie == RX_CLS_FLOW_DISC) {
                flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
        } else {
-               struct mlx5e_params *params = &priv->channels.params;
-               enum mlx5e_rq_group group;
-               u16 ix;
-
-               mlx5e_qid_get_ch_and_group(params, fs->ring_cookie, &ix, &group);
-
                dst = kzalloc(sizeof(*dst), GFP_KERNEL);
                if (!dst) {
                        err = -ENOMEM;
                        goto free;
                }
 
+               err = flow_get_tirn(priv, eth_rule, fs, rss_context, &dst->tir_num);
+               if (err)
+                       goto free;
+
                dst->type = MLX5_FLOW_DESTINATION_TYPE_TIR;
-               if (group == MLX5E_RQ_GROUP_XSK)
-                       dst->tir_num = mlx5e_rx_res_get_tirn_xsk(priv->rx_res, ix);
-               else
-                       dst->tir_num = mlx5e_rx_res_get_tirn_direct(priv->rx_res, ix);
                flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
        }
 
@@ -459,6 +504,8 @@ static void del_ethtool_rule(struct mlx5e_priv *priv,
 {
        if (eth_rule->rule)
                mlx5_del_flow_rules(eth_rule->rule);
+       if (eth_rule->rss)
+               mlx5e_rss_refcnt_dec(eth_rule->rss);
        list_del(&eth_rule->list);
        priv->fs.ethtool.tot_num_rules--;
        put_flow_table(eth_rule->eth_ft);
@@ -619,7 +666,7 @@ static int validate_flow(struct mlx5e_priv *priv,
                                        fs->ring_cookie))
                        return -EINVAL;
 
-       switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
+       switch (flow_type_mask(fs->flow_type)) {
        case ETHER_FLOW:
                num_tuples += validate_ethter(fs);
                break;
@@ -668,7 +715,7 @@ static int validate_flow(struct mlx5e_priv *priv,
 
 static int
 mlx5e_ethtool_flow_replace(struct mlx5e_priv *priv,
-                          struct ethtool_rx_flow_spec *fs)
+                          struct ethtool_rx_flow_spec *fs, u32 rss_context)
 {
        struct mlx5e_ethtool_table *eth_ft;
        struct mlx5e_ethtool_rule *eth_rule;
@@ -699,7 +746,7 @@ mlx5e_ethtool_flow_replace(struct mlx5e_priv *priv,
                err = -EINVAL;
                goto del_ethtool_rule;
        }
-       rule = add_ethtool_flow_rule(priv, eth_ft->ft, fs);
+       rule = add_ethtool_flow_rule(priv, eth_rule, eth_ft->ft, fs, rss_context);
        if (IS_ERR(rule)) {
                err = PTR_ERR(rule);
                goto del_ethtool_rule;
@@ -745,10 +792,20 @@ mlx5e_ethtool_get_flow(struct mlx5e_priv *priv,
                return -EINVAL;
 
        list_for_each_entry(eth_rule, &priv->fs.ethtool.rules, list) {
-               if (eth_rule->flow_spec.location == location) {
-                       info->fs = eth_rule->flow_spec;
+               int index;
+
+               if (eth_rule->flow_spec.location != location)
+                       continue;
+               if (!info)
                        return 0;
-               }
+               info->fs = eth_rule->flow_spec;
+               if (!eth_rule->rss)
+                       return 0;
+               index = mlx5e_rx_res_rss_index(priv->rx_res, eth_rule->rss);
+               if (index < 0)
+                       return index;
+               info->rss_context = index;
+               return 0;
        }
 
        return -ENOENT;
@@ -764,7 +821,7 @@ mlx5e_ethtool_get_all_flows(struct mlx5e_priv *priv,
 
        info->data = MAX_NUM_OF_ETHTOOL_RULES;
        while ((!err || err == -ENOENT) && idx < info->rule_cnt) {
-               err = mlx5e_ethtool_get_flow(priv, info, location);
+               err = mlx5e_ethtool_get_flow(priv, NULL, location);
                if (!err)
                        rule_locs[idx++] = location;
                location++;
@@ -887,7 +944,7 @@ int mlx5e_ethtool_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
 
        switch (cmd->cmd) {
        case ETHTOOL_SRXCLSRLINS:
-               err = mlx5e_ethtool_flow_replace(priv, &cmd->fs);
+               err = mlx5e_ethtool_flow_replace(priv, &cmd->fs, cmd->rss_context);
                break;
        case ETHTOOL_SRXCLSRLDEL:
                err = mlx5e_ethtool_flow_remove(priv, cmd->fs.location);