Commit 248d3b4c authored by Tariq Toukan's avatar Tariq Toukan Committed by Saeed Mahameed

net/mlx5e: Support flow classification into RSS contexts

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: default avatarTariq Toukan <tariqt@nvidia.com>
Reviewed-by: default avatarMaxim Mikityanskiy <maximmi@nvidia.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@nvidia.com>
parent f01cc58c
......@@ -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;
......
......@@ -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);
......
......@@ -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)
......
......@@ -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);
......
......@@ -35,11 +35,19 @@
#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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment