diff options
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 7 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 104 | 
3 files changed, 104 insertions, 10 deletions
| diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index 2b5562553f2d..a9894d2e8e26 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -58,7 +58,8 @@ int mlx5_cmd_update_root_ft(struct mlx5_core_dev *dev,  int mlx5_cmd_create_flow_table(struct mlx5_core_dev *dev,  			       enum fs_flow_table_type type, unsigned int level, -			       unsigned int log_size, unsigned int *table_id) +			       unsigned int log_size, struct mlx5_flow_table +			       *next_ft, unsigned int *table_id)  {  	u32 out[MLX5_ST_SZ_DW(create_flow_table_out)];  	u32 in[MLX5_ST_SZ_DW(create_flow_table_in)]; @@ -69,6 +70,10 @@ int mlx5_cmd_create_flow_table(struct mlx5_core_dev *dev,  	MLX5_SET(create_flow_table_in, in, opcode,  		 MLX5_CMD_OP_CREATE_FLOW_TABLE); +	if (next_ft) { +		MLX5_SET(create_flow_table_in, in, table_miss_mode, 1); +		MLX5_SET(create_flow_table_in, in, table_miss_id, next_ft->id); +	}  	MLX5_SET(create_flow_table_in, in, table_type, type);  	MLX5_SET(create_flow_table_in, in, level, level);  	MLX5_SET(create_flow_table_in, in, log_size, log_size); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h index 1ae9b685c783..9814d4784803 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h @@ -35,7 +35,8 @@  int mlx5_cmd_create_flow_table(struct mlx5_core_dev *dev,  			       enum fs_flow_table_type type, unsigned int level, -			       unsigned int log_size, unsigned int *table_id); +			       unsigned int log_size, struct mlx5_flow_table +			       *next_ft, unsigned int *table_id);  int mlx5_cmd_destroy_flow_table(struct mlx5_core_dev *dev,  				struct mlx5_flow_table *ft); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index 64bdb54041d1..c6f864d1ad1a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -510,6 +510,48 @@ static struct mlx5_flow_table *find_prev_chained_ft(struct fs_prio *prio)  	return find_closest_ft(prio, true);  } +static int connect_fts_in_prio(struct mlx5_core_dev *dev, +			       struct fs_prio *prio, +			       struct mlx5_flow_table *ft) +{ +	struct mlx5_flow_table *iter; +	int i = 0; +	int err; + +	fs_for_each_ft(iter, prio) { +		i++; +		err = mlx5_cmd_modify_flow_table(dev, +						 iter, +						 ft); +		if (err) { +			mlx5_core_warn(dev, "Failed to modify flow table %d\n", +				       iter->id); +			/* The driver is out of sync with the FW */ +			if (i > 1) +				WARN_ON(true); +			return err; +		} +	} +	return 0; +} + +/* Connect flow tables from previous priority of prio to ft */ +static int connect_prev_fts(struct mlx5_core_dev *dev, +			    struct mlx5_flow_table *ft, +			    struct fs_prio *prio) +{ +	struct mlx5_flow_table *prev_ft; + +	prev_ft = find_prev_chained_ft(prio); +	if (prev_ft) { +		struct fs_prio *prev_prio; + +		fs_get_obj(prev_prio, prev_ft->node.parent); +		return connect_fts_in_prio(dev, prev_prio, ft); +	} +	return 0; +} +  static int update_root_ft_create(struct mlx5_flow_table *ft, struct fs_prio  				 *prio)  { @@ -533,10 +575,30 @@ static int update_root_ft_create(struct mlx5_flow_table *ft, struct fs_prio  	return err;  } +static int connect_flow_table(struct mlx5_core_dev *dev, struct mlx5_flow_table *ft, +			      struct fs_prio *prio) +{ +	int err = 0; + +	/* Connect_prev_fts and update_root_ft_create are mutually exclusive */ + +	if (list_empty(&prio->node.children)) { +		err = connect_prev_fts(dev, ft, prio); +		if (err) +			return err; +	} + +	if (MLX5_CAP_FLOWTABLE(dev, +			       flow_table_properties_nic_receive.modify_root)) +		err = update_root_ft_create(ft, prio); +	return err; +} +  struct mlx5_flow_table *mlx5_create_flow_table(struct mlx5_flow_namespace *ns,  					       int prio,  					       int max_fte)  { +	struct mlx5_flow_table *next_ft = NULL;  	struct mlx5_flow_table *ft;  	int err;  	int log_table_sz; @@ -570,17 +632,15 @@ struct mlx5_flow_table *mlx5_create_flow_table(struct mlx5_flow_namespace *ns,  	tree_init_node(&ft->node, 1, del_flow_table);  	log_table_sz = ilog2(ft->max_fte); +	next_ft = find_next_chained_ft(fs_prio);  	err = mlx5_cmd_create_flow_table(root->dev, ft->type, ft->level, -					 log_table_sz, &ft->id); +					 log_table_sz, next_ft, &ft->id);  	if (err)  		goto free_ft; -	if (MLX5_CAP_FLOWTABLE(root->dev, -			       flow_table_properties_nic_receive.modify_root)) { -		err = update_root_ft_create(ft, fs_prio); -		if (err) -			goto destroy_ft; -	} +	err = connect_flow_table(root->dev, ft, fs_prio); +	if (err) +		goto destroy_ft;  	lock_ref_node(&fs_prio->node);  	tree_add_node(&ft->node, &fs_prio->node);  	list_add_tail(&ft->node.list, &fs_prio->node.children); @@ -967,13 +1027,41 @@ static int update_root_ft_destroy(struct mlx5_flow_table *ft)  	return 0;  } +/* Connect flow table from previous priority to + * the next flow table. + */ +static int disconnect_flow_table(struct mlx5_flow_table *ft) +{ +	struct mlx5_core_dev *dev = get_dev(&ft->node); +	struct mlx5_flow_table *next_ft; +	struct fs_prio *prio; +	int err = 0; + +	err = update_root_ft_destroy(ft); +	if (err) +		return err; + +	fs_get_obj(prio, ft->node.parent); +	if  (!(list_first_entry(&prio->node.children, +				struct mlx5_flow_table, +				node.list) == ft)) +		return 0; + +	next_ft = find_next_chained_ft(prio); +	err = connect_prev_fts(dev, next_ft, prio); +	if (err) +		mlx5_core_warn(dev, "Failed to disconnect flow table %d\n", +			       ft->id); +	return err; +} +  int mlx5_destroy_flow_table(struct mlx5_flow_table *ft)  {  	struct mlx5_flow_root_namespace *root = find_root(&ft->node);  	int err = 0;  	mutex_lock(&root->chain_lock); -	err = update_root_ft_destroy(ft); +	err = disconnect_flow_table(ft);  	if (err) {  		mutex_unlock(&root->chain_lock);  		return err; | 
