diff options
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c | 18 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/fs_core.c | 97 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/fs_core.h | 6 | ||||
| -rw-r--r-- | include/linux/mlx5/mlx5_ifc.h | 31 | 
5 files changed, 144 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 5096f4f336bd..d8b1195fba3d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -38,6 +38,24 @@  #include "fs_cmd.h"  #include "mlx5_core.h" +int mlx5_cmd_update_root_ft(struct mlx5_core_dev *dev, +			    struct mlx5_flow_table *ft) +{ +	u32 in[MLX5_ST_SZ_DW(set_flow_table_root_in)]; +	u32 out[MLX5_ST_SZ_DW(set_flow_table_root_out)]; + +	memset(in, 0, sizeof(in)); + +	MLX5_SET(set_flow_table_root_in, in, opcode, +		 MLX5_CMD_OP_SET_FLOW_TABLE_ROOT); +	MLX5_SET(set_flow_table_root_in, in, table_type, ft->type); +	MLX5_SET(set_flow_table_root_in, in, table_id, ft->id); + +	memset(out, 0, sizeof(out)); +	return mlx5_cmd_exec_check_status(dev, in, sizeof(in), out, +					  sizeof(out)); +} +  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) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h index f39304ede186..70d18ec145c2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h @@ -62,4 +62,6 @@ int mlx5_cmd_delete_fte(struct mlx5_core_dev *dev,  			struct mlx5_flow_table *ft,  			unsigned int index); +int mlx5_cmd_update_root_ft(struct mlx5_core_dev *dev, +			    struct mlx5_flow_table *ft);  #endif diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index c5a96e6abe0d..64bdb54041d1 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -510,6 +510,29 @@ static struct mlx5_flow_table *find_prev_chained_ft(struct fs_prio *prio)  	return find_closest_ft(prio, true);  } +static int update_root_ft_create(struct mlx5_flow_table *ft, struct fs_prio +				 *prio) +{ +	struct mlx5_flow_root_namespace *root = find_root(&prio->node); +	int min_level = INT_MAX; +	int err; + +	if (root->root_ft) +		min_level = root->root_ft->level; + +	if (ft->level >= min_level) +		return 0; + +	err = mlx5_cmd_update_root_ft(root->dev, ft); +	if (err) +		mlx5_core_warn(root->dev, "Update root flow table of id=%u failed\n", +			       ft->id); +	else +		root->root_ft = ft; + +	return err; +} +  struct mlx5_flow_table *mlx5_create_flow_table(struct mlx5_flow_namespace *ns,  					       int prio,  					       int max_fte) @@ -526,14 +549,15 @@ struct mlx5_flow_table *mlx5_create_flow_table(struct mlx5_flow_namespace *ns,  		return ERR_PTR(-ENODEV);  	} +	mutex_lock(&root->chain_lock);  	fs_prio = find_prio(ns, prio); -	if (!fs_prio) -		return ERR_PTR(-EINVAL); - -	lock_ref_node(&fs_prio->node); +	if (!fs_prio) { +		err = -EINVAL; +		goto unlock_root; +	}  	if (fs_prio->num_ft == fs_prio->max_ft) {  		err = -ENOSPC; -		goto unlock_prio; +		goto unlock_root;  	}  	ft = alloc_flow_table(find_next_free_level(fs_prio), @@ -541,7 +565,7 @@ struct mlx5_flow_table *mlx5_create_flow_table(struct mlx5_flow_namespace *ns,  			      root->table_type);  	if (!ft) {  		err = -ENOMEM; -		goto unlock_prio; +		goto unlock_root;  	}  	tree_init_node(&ft->node, 1, del_flow_table); @@ -551,15 +575,25 @@ struct mlx5_flow_table *mlx5_create_flow_table(struct mlx5_flow_namespace *ns,  	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; +	} +	lock_ref_node(&fs_prio->node);  	tree_add_node(&ft->node, &fs_prio->node);  	list_add_tail(&ft->node.list, &fs_prio->node.children);  	fs_prio->num_ft++;  	unlock_ref_node(&fs_prio->node); +	mutex_unlock(&root->chain_lock);  	return ft; +destroy_ft: +	mlx5_cmd_destroy_flow_table(root->dev, ft);  free_ft:  	kfree(ft); -unlock_prio: -	unlock_ref_node(&fs_prio->node); +unlock_root: +	mutex_unlock(&root->chain_lock);  	return ERR_PTR(err);  } @@ -899,13 +933,57 @@ void mlx5_del_flow_rule(struct mlx5_flow_rule *rule)  	tree_remove_node(&rule->node);  } +/* Assuming prio->node.children(flow tables) is sorted by level */ +static struct mlx5_flow_table *find_next_ft(struct mlx5_flow_table *ft) +{ +	struct fs_prio *prio; + +	fs_get_obj(prio, ft->node.parent); + +	if (!list_is_last(&ft->node.list, &prio->node.children)) +		return list_next_entry(ft, node.list); +	return find_next_chained_ft(prio); +} + +static int update_root_ft_destroy(struct mlx5_flow_table *ft) +{ +	struct mlx5_flow_root_namespace *root = find_root(&ft->node); +	struct mlx5_flow_table *new_root_ft = NULL; + +	if (root->root_ft != ft) +		return 0; + +	new_root_ft = find_next_ft(ft); +	if (new_root_ft) { +		int err = mlx5_cmd_update_root_ft(root->dev, new_root_ft); + +		if (err) { +			mlx5_core_warn(root->dev, "Update root flow table of id=%u failed\n", +				       ft->id); +			return err; +		} +		root->root_ft = new_root_ft; +	} +	return 0; +} +  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); +	if (err) { +		mutex_unlock(&root->chain_lock); +		return err; +	}  	if (tree_remove_node(&ft->node))  		mlx5_core_warn(get_dev(&ft->node), "Flow table %d wasn't destroyed, refcount > 1\n",  			       ft->id); +	mutex_unlock(&root->chain_lock); -	return 0; +	return err;  }  void mlx5_destroy_flow_group(struct mlx5_flow_group *fg) @@ -1072,6 +1150,7 @@ static struct mlx5_flow_root_namespace *create_root_ns(struct mlx5_core_dev *dev  	ns = &root_ns->ns;  	fs_init_namespace(ns); +	mutex_init(&root_ns->chain_lock);  	tree_init_node(&ns->node, 1, NULL);  	tree_add_node(&ns->node, NULL); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h index 0f98257c0d31..1a2e08bad529 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.h @@ -129,6 +129,9 @@ struct mlx5_flow_root_namespace {  	struct mlx5_flow_namespace	ns;  	enum   fs_flow_table_type	table_type;  	struct mlx5_core_dev		*dev; +	struct mlx5_flow_table		*root_ft; +	/* Should be held when chaining flow tables */ +	struct mutex			chain_lock;  };  int mlx5_init_fs(struct mlx5_core_dev *dev); @@ -148,6 +151,9 @@ void mlx5_cleanup_fs(struct mlx5_core_dev *dev);  #define fs_for_each_prio(pos, ns)			\  	fs_list_for_each_entry(pos, &(ns)->node.children) +#define fs_for_each_ft(pos, prio)			\ +	fs_list_for_each_entry(pos, &(prio)->node.children) +  #define fs_for_each_fg(pos, ft)			\  	fs_list_for_each_entry(pos, &(ft)->node.children) diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 1780a85a8797..323e713c44ba 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -185,6 +185,7 @@ enum {  	MLX5_CMD_OP_MODIFY_RQT                    = 0x917,  	MLX5_CMD_OP_DESTROY_RQT                   = 0x918,  	MLX5_CMD_OP_QUERY_RQT                     = 0x919, +	MLX5_CMD_OP_SET_FLOW_TABLE_ROOT		  = 0x92f,  	MLX5_CMD_OP_CREATE_FLOW_TABLE             = 0x930,  	MLX5_CMD_OP_DESTROY_FLOW_TABLE            = 0x931,  	MLX5_CMD_OP_QUERY_FLOW_TABLE              = 0x932, @@ -258,7 +259,8 @@ struct mlx5_ifc_flow_table_prop_layout_bits {  	u8         ft_support[0x1];  	u8         reserved_0[0x2];  	u8	   flow_modify_en[0x1]; -	u8         reserved_1[0x1c]; +	u8         modify_root[0x1]; +	u8         reserved_1[0x1b];  	u8         reserved_2[0x2];  	u8         log_max_ft_size[0x6]; @@ -6946,4 +6948,31 @@ union mlx5_ifc_uplink_pci_interface_document_bits {  	u8         reserved_0[0x20060];  }; +struct mlx5_ifc_set_flow_table_root_out_bits { +	u8         status[0x8]; +	u8         reserved_0[0x18]; + +	u8         syndrome[0x20]; + +	u8         reserved_1[0x40]; +}; + +struct mlx5_ifc_set_flow_table_root_in_bits { +	u8         opcode[0x10]; +	u8         reserved_0[0x10]; + +	u8         reserved_1[0x10]; +	u8         op_mod[0x10]; + +	u8         reserved_2[0x40]; + +	u8         table_type[0x8]; +	u8         reserved_3[0x18]; + +	u8         reserved_4[0x8]; +	u8         table_id[0x18]; + +	u8         reserved_5[0x140]; +}; +  #endif /* MLX5_IFC_H */  | 
