]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
net/mlx5_core: Managing root flow table
authorMaor Gottlieb <maorg@mellanox.com>
Mon, 11 Jan 2016 08:25:59 +0000 (10:25 +0200)
committerDavid S. Miller <davem@davemloft.net>
Mon, 11 Jan 2016 22:48:52 +0000 (17:48 -0500)
The root Flow Table for each Flow Table Type is defined,
by default, as the Flow Table with level 0.

In order not to use an empty flow tables and introduce new hops,
but still preserve space for flow-tables that have a priority
greater(lower number) than the current flow table, we introduce this
new set root flow table command.
This command tells the HW to start matching packets from the
assigned root flow table.
This command is used when we create new flow table with level lower than the
current lowest flow table or it is the first flow table.

Signed-off-by: Maor Gottlieb <maorg@mellanox.com>
Signed-off-by: Moni Shoua <monis@mellanox.com>
Signed-off-by: Matan Barak <matanb@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.h
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.h
include/linux/mlx5/mlx5_ifc.h

index 5096f4f336bdb58c01d1d48c0912fbb7bb54964f..d8b1195fba3dda53e9029e771828f523ee7b8a87 100644 (file)
 #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)
index f39304ede186d251cf1d9f31f9319865eddebcee..70d18ec145c2df07461e6b576643209d5486a931 100644 (file)
@@ -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
index c5a96e6abe0da590921a6aa612e66a17393ded3c..64bdb54041d183cd27b0d6b05b8fff5d7e66dd82 100644 (file)
@@ -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);
 
index 0f98257c0d31cba0fdf99dc3f1f183889c614594..1a2e08bad5293b6ee20305fd2f82aa230e0bb9cc 100644 (file)
@@ -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)
 
index 1780a85a879768827d445622ba662b34e4c149d6..323e713c44ba0202c7d8413bee1b219ac8c36300 100644 (file)
@@ -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 */