Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux-2.6-block.git] / drivers / net / ethernet / mellanox / mlx5 / core / eswitch_offloads.c
index d111cebca9f1ea57d57a70b108a436af1adcc6aa..d297354e8ea986c144727322a36d3107291549cb 100644 (file)
@@ -68,8 +68,10 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
        }
        if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
                counter = mlx5_fc_create(esw->dev, true);
-               if (IS_ERR(counter))
-                       return ERR_CAST(counter);
+               if (IS_ERR(counter)) {
+                       rule = ERR_CAST(counter);
+                       goto err_counter_alloc;
+               }
                dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
                dest[i].counter = counter;
                i++;
@@ -86,17 +88,25 @@ mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
        if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DECAP)
                spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
 
-       if (attr->encap)
+       if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
+               flow_act.modify_id = attr->mod_hdr_id;
+
+       if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)
                flow_act.encap_id = attr->encap->encap_id;
 
        rule = mlx5_add_flow_rules((struct mlx5_flow_table *)esw->fdb_table.fdb,
                                   spec, &flow_act, dest, i);
        if (IS_ERR(rule))
-               mlx5_fc_destroy(esw->dev, counter);
+               goto err_add_rule;
        else
                esw->offloads.num_flows++;
 
        return rule;
+
+err_add_rule:
+       mlx5_fc_destroy(esw->dev, counter);
+err_counter_alloc:
+       return rule;
 }
 
 void
@@ -106,12 +116,10 @@ mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw,
 {
        struct mlx5_fc *counter = NULL;
 
-       if (!IS_ERR(rule)) {
-               counter = mlx5_flow_rule_counter(rule);
-               mlx5_del_flow_rules(rule);
-               mlx5_fc_destroy(esw->dev, counter);
-               esw->offloads.num_flows--;
-       }
+       counter = mlx5_flow_rule_counter(rule);
+       mlx5_del_flow_rules(rule);
+       mlx5_fc_destroy(esw->dev, counter);
+       esw->offloads.num_flows--;
 }
 
 static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val)
@@ -418,30 +426,21 @@ out:
        return err;
 }
 
-#define MAX_PF_SQ 256
 #define ESW_OFFLOADS_NUM_GROUPS  4
 
-static int esw_create_offloads_fdb_table(struct mlx5_eswitch *esw, int nvports)
+static int esw_create_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
 {
-       int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
-       int table_size, ix, esw_size, err = 0;
        struct mlx5_core_dev *dev = esw->dev;
        struct mlx5_flow_namespace *root_ns;
        struct mlx5_flow_table *fdb = NULL;
-       struct mlx5_flow_group *g;
-       u32 *flow_group_in;
-       void *match_criteria;
+       int esw_size, err = 0;
        u32 flags = 0;
 
-       flow_group_in = mlx5_vzalloc(inlen);
-       if (!flow_group_in)
-               return -ENOMEM;
-
        root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
        if (!root_ns) {
                esw_warn(dev, "Failed to get FDB flow namespace\n");
                err = -EOPNOTSUPP;
-               goto ns_err;
+               goto out;
        }
 
        esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d)*groups(%d))\n",
@@ -451,8 +450,7 @@ static int esw_create_offloads_fdb_table(struct mlx5_eswitch *esw, int nvports)
        esw_size = min_t(int, MLX5_CAP_GEN(dev, max_flow_counter) * ESW_OFFLOADS_NUM_GROUPS,
                         1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
 
-       if (MLX5_CAP_ESW_FLOWTABLE_FDB(dev, encap) &&
-           MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap))
+       if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
                flags |= MLX5_FLOW_TABLE_TUNNEL_EN;
 
        fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH,
@@ -462,12 +460,55 @@ static int esw_create_offloads_fdb_table(struct mlx5_eswitch *esw, int nvports)
        if (IS_ERR(fdb)) {
                err = PTR_ERR(fdb);
                esw_warn(dev, "Failed to create Fast path FDB Table err %d\n", err);
-               goto fast_fdb_err;
+               goto out;
        }
        esw->fdb_table.fdb = fdb;
 
+out:
+       return err;
+}
+
+static void esw_destroy_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
+{
+       mlx5_destroy_flow_table(esw->fdb_table.fdb);
+}
+
+#define MAX_PF_SQ 256
+
+static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
+{
+       int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+       struct mlx5_flow_table_attr ft_attr = {};
+       struct mlx5_core_dev *dev = esw->dev;
+       struct mlx5_flow_namespace *root_ns;
+       struct mlx5_flow_table *fdb = NULL;
+       int table_size, ix, err = 0;
+       struct mlx5_flow_group *g;
+       void *match_criteria;
+       u32 *flow_group_in;
+
+       esw_debug(esw->dev, "Create offloads FDB Tables\n");
+       flow_group_in = mlx5_vzalloc(inlen);
+       if (!flow_group_in)
+               return -ENOMEM;
+
+       root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
+       if (!root_ns) {
+               esw_warn(dev, "Failed to get FDB flow namespace\n");
+               err = -EOPNOTSUPP;
+               goto ns_err;
+       }
+
+       err = esw_create_offloads_fast_fdb_table(esw);
+       if (err)
+               goto fast_fdb_err;
+
        table_size = nvports + MAX_PF_SQ + 1;
-       fdb = mlx5_create_flow_table(root_ns, FDB_SLOW_PATH, table_size, 0, 0);
+
+       ft_attr.max_fte = table_size;
+       ft_attr.prio = FDB_SLOW_PATH;
+
+       fdb = mlx5_create_flow_table(root_ns, &ft_attr);
        if (IS_ERR(fdb)) {
                err = PTR_ERR(fdb);
                esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
@@ -532,25 +573,26 @@ ns_err:
        return err;
 }
 
-static void esw_destroy_offloads_fdb_table(struct mlx5_eswitch *esw)
+static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
 {
        if (!esw->fdb_table.fdb)
                return;
 
-       esw_debug(esw->dev, "Destroy offloads FDB Table\n");
+       esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
        mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule);
        mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
        mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
 
        mlx5_destroy_flow_table(esw->fdb_table.offloads.fdb);
-       mlx5_destroy_flow_table(esw->fdb_table.fdb);
+       esw_destroy_offloads_fast_fdb_table(esw);
 }
 
 static int esw_create_offloads_table(struct mlx5_eswitch *esw)
 {
-       struct mlx5_flow_namespace *ns;
-       struct mlx5_flow_table *ft_offloads;
+       struct mlx5_flow_table_attr ft_attr = {};
        struct mlx5_core_dev *dev = esw->dev;
+       struct mlx5_flow_table *ft_offloads;
+       struct mlx5_flow_namespace *ns;
        int err = 0;
 
        ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
@@ -559,7 +601,9 @@ static int esw_create_offloads_table(struct mlx5_eswitch *esw)
                return -EOPNOTSUPP;
        }
 
-       ft_offloads = mlx5_create_flow_table(ns, 0, dev->priv.sriov.num_vfs + 2, 0, 0);
+       ft_attr.max_fte = dev->priv.sriov.num_vfs + 2;
+
+       ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
        if (IS_ERR(ft_offloads)) {
                err = PTR_ERR(ft_offloads);
                esw_warn(esw->dev, "Failed to create offloads table, err %d\n", err);
@@ -700,7 +744,7 @@ int esw_offloads_init(struct mlx5_eswitch *esw, int nvports)
        mlx5_remove_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
        mlx5_dev_list_unlock();
 
-       err = esw_create_offloads_fdb_table(esw, nvports);
+       err = esw_create_offloads_fdb_tables(esw, nvports);
        if (err)
                goto create_fdb_err;
 
@@ -737,7 +781,7 @@ create_fg_err:
        esw_destroy_offloads_table(esw);
 
 create_ft_err:
-       esw_destroy_offloads_fdb_table(esw);
+       esw_destroy_offloads_fdb_tables(esw);
 
 create_fdb_err:
        /* enable back PF RoCE */
@@ -783,7 +827,7 @@ void esw_offloads_cleanup(struct mlx5_eswitch *esw, int nvports)
 
        esw_destroy_vport_rx_group(esw);
        esw_destroy_offloads_table(esw);
-       esw_destroy_offloads_fdb_table(esw);
+       esw_destroy_offloads_fdb_tables(esw);
 }
 
 static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
@@ -1012,6 +1056,66 @@ out:
        return 0;
 }
 
+int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap)
+{
+       struct mlx5_core_dev *dev = devlink_priv(devlink);
+       struct mlx5_eswitch *esw = dev->priv.eswitch;
+       int err;
+
+       if (!MLX5_CAP_GEN(dev, vport_group_manager))
+               return -EOPNOTSUPP;
+
+       if (esw->mode == SRIOV_NONE)
+               return -EOPNOTSUPP;
+
+       if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
+           (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, encap) ||
+            !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)))
+               return -EOPNOTSUPP;
+
+       if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
+               return -EOPNOTSUPP;
+
+       if (esw->mode == SRIOV_LEGACY) {
+               esw->offloads.encap = encap;
+               return 0;
+       }
+
+       if (esw->offloads.encap == encap)
+               return 0;
+
+       if (esw->offloads.num_flows > 0) {
+               esw_warn(dev, "Can't set encapsulation when flows are configured\n");
+               return -EOPNOTSUPP;
+       }
+
+       esw_destroy_offloads_fast_fdb_table(esw);
+
+       esw->offloads.encap = encap;
+       err = esw_create_offloads_fast_fdb_table(esw);
+       if (err) {
+               esw_warn(esw->dev, "Failed re-creating fast FDB table, err %d\n", err);
+               esw->offloads.encap = !encap;
+               (void) esw_create_offloads_fast_fdb_table(esw);
+       }
+       return err;
+}
+
+int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap)
+{
+       struct mlx5_core_dev *dev = devlink_priv(devlink);
+       struct mlx5_eswitch *esw = dev->priv.eswitch;
+
+       if (!MLX5_CAP_GEN(dev, vport_group_manager))
+               return -EOPNOTSUPP;
+
+       if (esw->mode == SRIOV_NONE)
+               return -EOPNOTSUPP;
+
+       *encap = esw->offloads.encap;
+       return 0;
+}
+
 void mlx5_eswitch_register_vport_rep(struct mlx5_eswitch *esw,
                                     int vport_index,
                                     struct mlx5_eswitch_rep *__rep)