net/mlx5: Split FDB fast path prio to multiple namespaces
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlx5 / core / fs_core.c
index 37d114c668b7ba70ca968f76c88c42af84967f25..7eb6d58733accb64ffa679a3c20d68d7fa7c2bf1 100644 (file)
@@ -40,6 +40,7 @@
 #include "diag/fs_tracepoint.h"
 #include "accel/ipsec.h"
 #include "fpga/ipsec.h"
+#include "eswitch.h"
 
 #define INIT_TREE_NODE_ARRAY_SIZE(...) (sizeof((struct init_tree_node[]){__VA_ARGS__}) /\
                                         sizeof(struct init_tree_node))
                                           FS_CAP(flow_table_properties_nic_receive.identified_miss_table_mode), \
                                           FS_CAP(flow_table_properties_nic_receive.flow_table_modify))
 
+#define FS_CHAINING_CAPS_EGRESS                                                \
+       FS_REQUIRED_CAPS(                                                      \
+               FS_CAP(flow_table_properties_nic_transmit.flow_modify_en),     \
+               FS_CAP(flow_table_properties_nic_transmit.modify_root),        \
+               FS_CAP(flow_table_properties_nic_transmit                      \
+                              .identified_miss_table_mode),                   \
+               FS_CAP(flow_table_properties_nic_transmit.flow_table_modify))
+
 #define LEFTOVERS_NUM_LEVELS 1
 #define LEFTOVERS_NUM_PRIOS 1
 
@@ -151,6 +160,17 @@ static struct init_tree_node {
        }
 };
 
+static struct init_tree_node egress_root_fs = {
+       .type = FS_TYPE_NAMESPACE,
+       .ar_size = 1,
+       .children = (struct init_tree_node[]) {
+               ADD_PRIO(0, MLX5_BY_PASS_NUM_PRIOS, 0,
+                        FS_CHAINING_CAPS_EGRESS,
+                        ADD_NS(ADD_MULTIPLE_PRIO(MLX5_BY_PASS_NUM_PRIOS,
+                                                 BY_PASS_PRIO_NUM_LEVELS))),
+       }
+};
+
 enum fs_i_lock_class {
        FS_LOCK_GRANDPARENT,
        FS_LOCK_PARENT,
@@ -694,7 +714,7 @@ static struct mlx5_flow_table *find_closest_ft_recursive(struct fs_node  *root,
        struct fs_node *iter = list_entry(start, struct fs_node, list);
        struct mlx5_flow_table *ft = NULL;
 
-       if (!root)
+       if (!root || root->type == FS_TYPE_PRIO_CHAINS)
                return NULL;
 
        list_for_each_advance_continue(iter, &root->children, reverse) {
@@ -1388,7 +1408,7 @@ static bool check_conflicting_actions(u32 action1, u32 action2)
                return false;
 
        if (xored_actions & (MLX5_FLOW_CONTEXT_ACTION_DROP  |
-                            MLX5_FLOW_CONTEXT_ACTION_ENCAP |
+                            MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT |
                             MLX5_FLOW_CONTEXT_ACTION_DECAP |
                             MLX5_FLOW_CONTEXT_ACTION_MOD_HDR  |
                             MLX5_FLOW_CONTEXT_ACTION_VLAN_POP |
@@ -1455,29 +1475,8 @@ static struct mlx5_flow_handle *add_rule_fg(struct mlx5_flow_group *fg,
        return handle;
 }
 
-struct mlx5_fc *mlx5_flow_rule_counter(struct mlx5_flow_handle *handle)
+static bool counter_is_valid(u32 action)
 {
-       struct mlx5_flow_rule *dst;
-       struct fs_fte *fte;
-
-       fs_get_obj(fte, handle->rule[0]->node.parent);
-
-       fs_for_each_dst(dst, fte) {
-               if (dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_COUNTER)
-                       return dst->dest_attr.counter;
-       }
-
-       return NULL;
-}
-
-static bool counter_is_valid(struct mlx5_fc *counter, u32 action)
-{
-       if (!(action & MLX5_FLOW_CONTEXT_ACTION_COUNT))
-               return !counter;
-
-       if (!counter)
-               return false;
-
        return (action & (MLX5_FLOW_CONTEXT_ACTION_DROP |
                          MLX5_FLOW_CONTEXT_ACTION_FWD_DEST));
 }
@@ -1487,7 +1486,7 @@ static bool dest_is_valid(struct mlx5_flow_destination *dest,
                          struct mlx5_flow_table *ft)
 {
        if (dest && (dest->type == MLX5_FLOW_DESTINATION_TYPE_COUNTER))
-               return counter_is_valid(dest->counter, action);
+               return counter_is_valid(action);
 
        if (!(action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST))
                return true;
@@ -1975,12 +1974,24 @@ void mlx5_destroy_flow_group(struct mlx5_flow_group *fg)
                               fg->id);
 }
 
+struct mlx5_flow_namespace *mlx5_get_fdb_sub_ns(struct mlx5_core_dev *dev,
+                                               int n)
+{
+       struct mlx5_flow_steering *steering = dev->priv.steering;
+
+       if (!steering || !steering->fdb_sub_ns)
+               return NULL;
+
+       return steering->fdb_sub_ns[n];
+}
+EXPORT_SYMBOL(mlx5_get_fdb_sub_ns);
+
 struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev,
                                                    enum mlx5_flow_namespace_type type)
 {
        struct mlx5_flow_steering *steering = dev->priv.steering;
        struct mlx5_flow_root_namespace *root_ns;
-       int prio;
+       int prio = 0;
        struct fs_prio *fs_prio;
        struct mlx5_flow_namespace *ns;
 
@@ -1988,40 +1999,29 @@ struct mlx5_flow_namespace *mlx5_get_flow_namespace(struct mlx5_core_dev *dev,
                return NULL;
 
        switch (type) {
-       case MLX5_FLOW_NAMESPACE_BYPASS:
-       case MLX5_FLOW_NAMESPACE_LAG:
-       case MLX5_FLOW_NAMESPACE_OFFLOADS:
-       case MLX5_FLOW_NAMESPACE_ETHTOOL:
-       case MLX5_FLOW_NAMESPACE_KERNEL:
-       case MLX5_FLOW_NAMESPACE_LEFTOVERS:
-       case MLX5_FLOW_NAMESPACE_ANCHOR:
-               prio = type;
-               break;
        case MLX5_FLOW_NAMESPACE_FDB:
                if (steering->fdb_root_ns)
                        return &steering->fdb_root_ns->ns;
-               else
-                       return NULL;
+               return NULL;
        case MLX5_FLOW_NAMESPACE_SNIFFER_RX:
                if (steering->sniffer_rx_root_ns)
                        return &steering->sniffer_rx_root_ns->ns;
-               else
-                       return NULL;
+               return NULL;
        case MLX5_FLOW_NAMESPACE_SNIFFER_TX:
                if (steering->sniffer_tx_root_ns)
                        return &steering->sniffer_tx_root_ns->ns;
-               else
-                       return NULL;
-       case MLX5_FLOW_NAMESPACE_EGRESS:
-               if (steering->egress_root_ns)
-                       return &steering->egress_root_ns->ns;
-               else
-                       return NULL;
-       default:
                return NULL;
+       default:
+               break;
+       }
+
+       if (type == MLX5_FLOW_NAMESPACE_EGRESS) {
+               root_ns = steering->egress_root_ns;
+       } else { /* Must be NIC RX */
+               root_ns = steering->root_ns;
+               prio = type;
        }
 
-       root_ns = steering->root_ns;
        if (!root_ns)
                return NULL;
 
@@ -2064,8 +2064,10 @@ struct mlx5_flow_namespace *mlx5_get_flow_vport_acl_namespace(struct mlx5_core_d
        }
 }
 
-static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
-                                     unsigned int prio, int num_levels)
+static struct fs_prio *_fs_create_prio(struct mlx5_flow_namespace *ns,
+                                      unsigned int prio,
+                                      int num_levels,
+                                      enum fs_node_type type)
 {
        struct fs_prio *fs_prio;
 
@@ -2073,7 +2075,7 @@ static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
        if (!fs_prio)
                return ERR_PTR(-ENOMEM);
 
-       fs_prio->node.type = FS_TYPE_PRIO;
+       fs_prio->node.type = type;
        tree_init_node(&fs_prio->node, NULL, del_sw_prio);
        tree_add_node(&fs_prio->node, &ns->node);
        fs_prio->num_levels = num_levels;
@@ -2083,6 +2085,19 @@ static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
        return fs_prio;
 }
 
+static struct fs_prio *fs_create_prio_chained(struct mlx5_flow_namespace *ns,
+                                             unsigned int prio,
+                                             int num_levels)
+{
+       return _fs_create_prio(ns, prio, num_levels, FS_TYPE_PRIO_CHAINS);
+}
+
+static struct fs_prio *fs_create_prio(struct mlx5_flow_namespace *ns,
+                                     unsigned int prio, int num_levels)
+{
+       return _fs_create_prio(ns, prio, num_levels, FS_TYPE_PRIO);
+}
+
 static struct mlx5_flow_namespace *fs_init_namespace(struct mlx5_flow_namespace
                                                     *ns)
 {
@@ -2387,6 +2402,9 @@ void mlx5_cleanup_fs(struct mlx5_core_dev *dev)
        cleanup_egress_acls_root_ns(dev);
        cleanup_ingress_acls_root_ns(dev);
        cleanup_root_ns(steering->fdb_root_ns);
+       steering->fdb_root_ns = NULL;
+       kfree(steering->fdb_sub_ns);
+       steering->fdb_sub_ns = NULL;
        cleanup_root_ns(steering->sniffer_rx_root_ns);
        cleanup_root_ns(steering->sniffer_tx_root_ns);
        cleanup_root_ns(steering->egress_root_ns);
@@ -2432,27 +2450,64 @@ static int init_sniffer_rx_root_ns(struct mlx5_flow_steering *steering)
 
 static int init_fdb_root_ns(struct mlx5_flow_steering *steering)
 {
-       struct fs_prio *prio;
+       struct mlx5_flow_namespace *ns;
+       struct fs_prio *maj_prio;
+       struct fs_prio *min_prio;
+       int levels;
+       int chain;
+       int prio;
+       int err;
 
        steering->fdb_root_ns = create_root_ns(steering, FS_FT_FDB);
        if (!steering->fdb_root_ns)
                return -ENOMEM;
 
-       prio = fs_create_prio(&steering->fdb_root_ns->ns, 0, 2);
-       if (IS_ERR(prio))
+       steering->fdb_sub_ns = kzalloc(sizeof(steering->fdb_sub_ns) *
+                                      FDB_MAX_CHAIN + 1, GFP_KERNEL);
+       if (!steering->fdb_sub_ns)
+               return -ENOMEM;
+
+       levels = 2 * FDB_MAX_PRIO * (FDB_MAX_CHAIN + 1);
+       maj_prio = fs_create_prio_chained(&steering->fdb_root_ns->ns, 0,
+                                         levels);
+       if (IS_ERR(maj_prio)) {
+               err = PTR_ERR(maj_prio);
                goto out_err;
+       }
+
+       for (chain = 0; chain <= FDB_MAX_CHAIN; chain++) {
+               ns = fs_create_namespace(maj_prio);
+               if (IS_ERR(ns)) {
+                       err = PTR_ERR(ns);
+                       goto out_err;
+               }
+
+               for (prio = 0; prio < FDB_MAX_PRIO * (chain + 1); prio++) {
+                       min_prio = fs_create_prio(ns, prio, 2);
+                       if (IS_ERR(min_prio)) {
+                               err = PTR_ERR(min_prio);
+                               goto out_err;
+                       }
+               }
+
+               steering->fdb_sub_ns[chain] = ns;
+       }
 
-       prio = fs_create_prio(&steering->fdb_root_ns->ns, 1, 1);
-       if (IS_ERR(prio))
+       maj_prio = fs_create_prio(&steering->fdb_root_ns->ns, 1, 1);
+       if (IS_ERR(maj_prio)) {
+               err = PTR_ERR(maj_prio);
                goto out_err;
+       }
 
        set_prio_attrs(steering->fdb_root_ns);
        return 0;
 
 out_err:
        cleanup_root_ns(steering->fdb_root_ns);
+       kfree(steering->fdb_sub_ns);
+       steering->fdb_sub_ns = NULL;
        steering->fdb_root_ns = NULL;
-       return PTR_ERR(prio);
+       return err;
 }
 
 static int init_egress_acl_root_ns(struct mlx5_flow_steering *steering, int vport)
@@ -2537,16 +2592,23 @@ cleanup_root_ns:
 
 static int init_egress_root_ns(struct mlx5_flow_steering *steering)
 {
-       struct fs_prio *prio;
+       int err;
 
        steering->egress_root_ns = create_root_ns(steering,
                                                  FS_FT_NIC_TX);
        if (!steering->egress_root_ns)
                return -ENOMEM;
 
-       /* create 1 prio*/
-       prio = fs_create_prio(&steering->egress_root_ns->ns, 0, 1);
-       return PTR_ERR_OR_ZERO(prio);
+       err = init_root_tree(steering, &egress_root_fs,
+                            &steering->egress_root_ns->ns.node);
+       if (err)
+               goto cleanup;
+       set_prio_attrs(steering->egress_root_ns);
+       return 0;
+cleanup:
+       cleanup_root_ns(steering->egress_root_ns);
+       steering->egress_root_ns = NULL;
+       return err;
 }
 
 int mlx5_init_fs(struct mlx5_core_dev *dev)
@@ -2614,7 +2676,7 @@ int mlx5_init_fs(struct mlx5_core_dev *dev)
                        goto err;
        }
 
-       if (MLX5_IPSEC_DEV(dev)) {
+       if (MLX5_IPSEC_DEV(dev) || MLX5_CAP_FLOWTABLE_NIC_TX(dev, ft_support)) {
                err = init_egress_root_ns(steering);
                if (err)
                        goto err;