net/mlx5: Unify and improve command interface
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx5 / core / eswitch.c
index aebbd6c..0a364bf 100644 (file)
 
 #define UPLINK_VPORT 0xFFFF
 
-#define MLX5_DEBUG_ESWITCH_MASK BIT(3)
-
-#define esw_info(dev, format, ...)                             \
-       pr_info("(%s): E-Switch: " format, (dev)->priv.name, ##__VA_ARGS__)
-
-#define esw_warn(dev, format, ...)                             \
-       pr_warn("(%s): E-Switch: " format, (dev)->priv.name, ##__VA_ARGS__)
-
-#define esw_debug(dev, format, ...)                            \
-       mlx5_core_dbg_mask(dev, MLX5_DEBUG_ESWITCH_MASK, format, ##__VA_ARGS__)
-
 enum {
        MLX5_ACTION_NONE = 0,
        MLX5_ACTION_ADD  = 1,
@@ -92,16 +81,15 @@ enum {
                            MC_ADDR_CHANGE | \
                            PROMISC_CHANGE)
 
+int esw_offloads_init(struct mlx5_eswitch *esw, int nvports);
+void esw_offloads_cleanup(struct mlx5_eswitch *esw, int nvports);
+
 static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport,
                                        u32 events_mask)
 {
-       int in[MLX5_ST_SZ_DW(modify_nic_vport_context_in)];
-       int out[MLX5_ST_SZ_DW(modify_nic_vport_context_out)];
+       int in[MLX5_ST_SZ_DW(modify_nic_vport_context_in)]   = {0};
+       int out[MLX5_ST_SZ_DW(modify_nic_vport_context_out)] = {0};
        void *nic_vport_ctx;
-       int err;
-
-       memset(out, 0, sizeof(out));
-       memset(in, 0, sizeof(in));
 
        MLX5_SET(modify_nic_vport_context_in, in,
                 opcode, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT);
@@ -124,45 +112,31 @@ static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport,
                MLX5_SET(nic_vport_context, nic_vport_ctx,
                         event_on_promisc_change, 1);
 
-       err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
-       if (err)
-               goto ex;
-       err = mlx5_cmd_status_to_err_v2(out);
-       if (err)
-               goto ex;
-       return 0;
-ex:
-       return err;
+       return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
 }
 
 /* E-Switch vport context HW commands */
 static int query_esw_vport_context_cmd(struct mlx5_core_dev *mdev, u32 vport,
                                       u32 *out, int outlen)
 {
-       u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)];
-
-       memset(in, 0, sizeof(in));
+       u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {0};
 
        MLX5_SET(query_nic_vport_context_in, in, opcode,
                 MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT);
-
        MLX5_SET(query_esw_vport_context_in, in, vport_number, vport);
        if (vport)
                MLX5_SET(query_esw_vport_context_in, in, other_vport, 1);
-
-       return mlx5_cmd_exec_check_status(mdev, in, sizeof(in), out, outlen);
+       return mlx5_cmd_exec(mdev, in, sizeof(in), out, outlen);
 }
 
 static int query_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
                                 u16 *vlan, u8 *qos)
 {
-       u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)];
+       u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {0};
        int err;
        bool cvlan_strip;
        bool cvlan_insert;
 
-       memset(out, 0, sizeof(out));
-
        *vlan = 0;
        *qos = 0;
 
@@ -196,27 +170,20 @@ out:
 static int modify_esw_vport_context_cmd(struct mlx5_core_dev *dev, u16 vport,
                                        void *in, int inlen)
 {
-       u32 out[MLX5_ST_SZ_DW(modify_esw_vport_context_out)];
-
-       memset(out, 0, sizeof(out));
+       u32 out[MLX5_ST_SZ_DW(modify_esw_vport_context_out)] = {0};
 
+       MLX5_SET(modify_esw_vport_context_in, in, opcode,
+                MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT);
        MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport);
        if (vport)
                MLX5_SET(modify_esw_vport_context_in, in, other_vport, 1);
-
-       MLX5_SET(modify_esw_vport_context_in, in, opcode,
-                MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT);
-
-       return mlx5_cmd_exec_check_status(dev, in, inlen,
-                                         out, sizeof(out));
+       return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
 }
 
 static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
                                  u16 vlan, u8 qos, bool set)
 {
-       u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)];
-
-       memset(in, 0, sizeof(in));
+       u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {0};
 
        if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||
            !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))
@@ -224,7 +191,6 @@ static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
 
        esw_debug(dev, "Set Vport[%d] VLAN %d qos %d set=%d\n",
                  vport, vlan, qos, set);
-
        if (set) {
                MLX5_SET(modify_esw_vport_context_in, in,
                         esw_vport_context.vport_cvlan_strip, 1);
@@ -249,13 +215,10 @@ static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport,
 static int set_l2_table_entry_cmd(struct mlx5_core_dev *dev, u32 index,
                                  u8 *mac, u8 vlan_valid, u16 vlan)
 {
-       u32 in[MLX5_ST_SZ_DW(set_l2_table_entry_in)];
-       u32 out[MLX5_ST_SZ_DW(set_l2_table_entry_out)];
+       u32 in[MLX5_ST_SZ_DW(set_l2_table_entry_in)]   = {0};
+       u32 out[MLX5_ST_SZ_DW(set_l2_table_entry_out)] = {0};
        u8 *in_mac_addr;
 
-       memset(in, 0, sizeof(in));
-       memset(out, 0, sizeof(out));
-
        MLX5_SET(set_l2_table_entry_in, in, opcode,
                 MLX5_CMD_OP_SET_L2_TABLE_ENTRY);
        MLX5_SET(set_l2_table_entry_in, in, table_index, index);
@@ -265,23 +228,18 @@ static int set_l2_table_entry_cmd(struct mlx5_core_dev *dev, u32 index,
        in_mac_addr = MLX5_ADDR_OF(set_l2_table_entry_in, in, mac_address);
        ether_addr_copy(&in_mac_addr[2], mac);
 
-       return mlx5_cmd_exec_check_status(dev, in, sizeof(in),
-                                         out, sizeof(out));
+       return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
 }
 
 static int del_l2_table_entry_cmd(struct mlx5_core_dev *dev, u32 index)
 {
-       u32 in[MLX5_ST_SZ_DW(delete_l2_table_entry_in)];
-       u32 out[MLX5_ST_SZ_DW(delete_l2_table_entry_out)];
-
-       memset(in, 0, sizeof(in));
-       memset(out, 0, sizeof(out));
+       u32 in[MLX5_ST_SZ_DW(delete_l2_table_entry_in)]   = {0};
+       u32 out[MLX5_ST_SZ_DW(delete_l2_table_entry_out)] = {0};
 
        MLX5_SET(delete_l2_table_entry_in, in, opcode,
                 MLX5_CMD_OP_DELETE_L2_TABLE_ENTRY);
        MLX5_SET(delete_l2_table_entry_in, in, table_index, index);
-       return mlx5_cmd_exec_check_status(dev, in, sizeof(in),
-                                         out, sizeof(out));
+       return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
 }
 
 static int alloc_l2_table_index(struct mlx5_l2_table *l2_table, u32 *ix)
@@ -337,25 +295,23 @@ __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u32 vport, bool rx_rule,
                            MLX5_MATCH_OUTER_HEADERS);
        struct mlx5_flow_rule *flow_rule = NULL;
        struct mlx5_flow_destination dest;
+       struct mlx5_flow_spec *spec;
        void *mv_misc = NULL;
        void *mc_misc = NULL;
        u8 *dmac_v = NULL;
        u8 *dmac_c = NULL;
-       u32 *match_v;
-       u32 *match_c;
 
        if (rx_rule)
                match_header |= MLX5_MATCH_MISC_PARAMETERS;
-       match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
-       match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
-       if (!match_v || !match_c) {
+
+       spec = mlx5_vzalloc(sizeof(*spec));
+       if (!spec) {
                pr_warn("FDB: Failed to alloc match parameters\n");
-               goto out;
+               return NULL;
        }
-
-       dmac_v = MLX5_ADDR_OF(fte_match_param, match_v,
+       dmac_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
                              outer_headers.dmac_47_16);
-       dmac_c = MLX5_ADDR_OF(fte_match_param, match_c,
+       dmac_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
                              outer_headers.dmac_47_16);
 
        if (match_header & MLX5_MATCH_OUTER_HEADERS) {
@@ -364,8 +320,10 @@ __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u32 vport, bool rx_rule,
        }
 
        if (match_header & MLX5_MATCH_MISC_PARAMETERS) {
-               mv_misc  = MLX5_ADDR_OF(fte_match_param, match_v, misc_parameters);
-               mc_misc  = MLX5_ADDR_OF(fte_match_param, match_c, misc_parameters);
+               mv_misc  = MLX5_ADDR_OF(fte_match_param, spec->match_value,
+                                       misc_parameters);
+               mc_misc  = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
+                                       misc_parameters);
                MLX5_SET(fte_match_set_misc, mv_misc, source_port, UPLINK_VPORT);
                MLX5_SET_TO_ONES(fte_match_set_misc, mc_misc, source_port);
        }
@@ -376,11 +334,9 @@ __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u32 vport, bool rx_rule,
        esw_debug(esw->dev,
                  "\tFDB add rule dmac_v(%pM) dmac_c(%pM) -> vport(%d)\n",
                  dmac_v, dmac_c, vport);
+       spec->match_criteria_enable = match_header;
        flow_rule =
-               mlx5_add_flow_rule(esw->fdb_table.fdb,
-                                  match_header,
-                                  match_c,
-                                  match_v,
+               mlx5_add_flow_rule(esw->fdb_table.fdb, spec,
                                   MLX5_FLOW_CONTEXT_ACTION_FWD_DEST,
                                   0, &dest);
        if (IS_ERR(flow_rule)) {
@@ -389,9 +345,8 @@ __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u32 vport, bool rx_rule,
                         dmac_v, dmac_c, vport, PTR_ERR(flow_rule));
                flow_rule = NULL;
        }
-out:
-       kfree(match_v);
-       kfree(match_c);
+
+       kvfree(spec);
        return flow_rule;
 }
 
@@ -428,7 +383,7 @@ esw_fdb_set_vport_promisc_rule(struct mlx5_eswitch *esw, u32 vport)
        return __esw_fdb_set_vport_rule(esw, vport, true, mac_c, mac_v);
 }
 
-static int esw_create_fdb_table(struct mlx5_eswitch *esw, int nvports)
+static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw, int nvports)
 {
        int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
        struct mlx5_core_dev *dev = esw->dev;
@@ -479,7 +434,7 @@ static int esw_create_fdb_table(struct mlx5_eswitch *esw, int nvports)
                esw_warn(dev, "Failed to create flow group err(%d)\n", err);
                goto out;
        }
-       esw->fdb_table.addr_grp = g;
+       esw->fdb_table.legacy.addr_grp = g;
 
        /* Allmulti group : One rule that forwards any mcast traffic */
        MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
@@ -494,7 +449,7 @@ static int esw_create_fdb_table(struct mlx5_eswitch *esw, int nvports)
                esw_warn(dev, "Failed to create allmulti flow group err(%d)\n", err);
                goto out;
        }
-       esw->fdb_table.allmulti_grp = g;
+       esw->fdb_table.legacy.allmulti_grp = g;
 
        /* Promiscuous group :
         * One rule that forward all unmatched traffic from previous groups
@@ -511,17 +466,17 @@ static int esw_create_fdb_table(struct mlx5_eswitch *esw, int nvports)
                esw_warn(dev, "Failed to create promisc flow group err(%d)\n", err);
                goto out;
        }
-       esw->fdb_table.promisc_grp = g;
+       esw->fdb_table.legacy.promisc_grp = g;
 
 out:
        if (err) {
-               if (!IS_ERR_OR_NULL(esw->fdb_table.allmulti_grp)) {
-                       mlx5_destroy_flow_group(esw->fdb_table.allmulti_grp);
-                       esw->fdb_table.allmulti_grp = NULL;
+               if (!IS_ERR_OR_NULL(esw->fdb_table.legacy.allmulti_grp)) {
+                       mlx5_destroy_flow_group(esw->fdb_table.legacy.allmulti_grp);
+                       esw->fdb_table.legacy.allmulti_grp = NULL;
                }
-               if (!IS_ERR_OR_NULL(esw->fdb_table.addr_grp)) {
-                       mlx5_destroy_flow_group(esw->fdb_table.addr_grp);
-                       esw->fdb_table.addr_grp = NULL;
+               if (!IS_ERR_OR_NULL(esw->fdb_table.legacy.addr_grp)) {
+                       mlx5_destroy_flow_group(esw->fdb_table.legacy.addr_grp);
+                       esw->fdb_table.legacy.addr_grp = NULL;
                }
                if (!IS_ERR_OR_NULL(esw->fdb_table.fdb)) {
                        mlx5_destroy_flow_table(esw->fdb_table.fdb);
@@ -533,20 +488,20 @@ out:
        return err;
 }
 
-static void esw_destroy_fdb_table(struct mlx5_eswitch *esw)
+static void esw_destroy_legacy_fdb_table(struct mlx5_eswitch *esw)
 {
        if (!esw->fdb_table.fdb)
                return;
 
        esw_debug(esw->dev, "Destroy FDB Table\n");
-       mlx5_destroy_flow_group(esw->fdb_table.promisc_grp);
-       mlx5_destroy_flow_group(esw->fdb_table.allmulti_grp);
-       mlx5_destroy_flow_group(esw->fdb_table.addr_grp);
+       mlx5_destroy_flow_group(esw->fdb_table.legacy.promisc_grp);
+       mlx5_destroy_flow_group(esw->fdb_table.legacy.allmulti_grp);
+       mlx5_destroy_flow_group(esw->fdb_table.legacy.addr_grp);
        mlx5_destroy_flow_table(esw->fdb_table.fdb);
        esw->fdb_table.fdb = NULL;
-       esw->fdb_table.addr_grp = NULL;
-       esw->fdb_table.allmulti_grp = NULL;
-       esw->fdb_table.promisc_grp = NULL;
+       esw->fdb_table.legacy.addr_grp = NULL;
+       esw->fdb_table.legacy.allmulti_grp = NULL;
+       esw->fdb_table.legacy.promisc_grp = NULL;
 }
 
 /* E-Switch vport UC/MC lists management */
@@ -578,7 +533,8 @@ static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
        if (err)
                goto abort;
 
-       if (esw->fdb_table.fdb) /* SRIOV is enabled: Forward UC MAC to vport */
+       /* SRIOV is enabled: Forward UC MAC to vport */
+       if (esw->fdb_table.fdb && esw->mode == SRIOV_LEGACY)
                vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
 
        esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM index:%d fr(%p)\n",
@@ -1300,9 +1256,8 @@ static void esw_vport_disable_ingress_acl(struct mlx5_eswitch *esw,
 static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
                                    struct mlx5_vport *vport)
 {
+       struct mlx5_flow_spec *spec;
        u8 smac[ETH_ALEN];
-       u32 *match_v;
-       u32 *match_c;
        int err = 0;
        u8 *smac_v;
 
@@ -1336,9 +1291,8 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
                  "vport[%d] configure ingress rules, vlan(%d) qos(%d)\n",
                  vport->vport, vport->vlan, vport->qos);
 
-       match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
-       match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
-       if (!match_v || !match_c) {
+       spec = mlx5_vzalloc(sizeof(*spec));
+       if (!spec) {
                err = -ENOMEM;
                esw_warn(esw->dev, "vport[%d] configure ingress rules failed, err(%d)\n",
                         vport->vport, err);
@@ -1346,22 +1300,20 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
        }
 
        if (vport->vlan || vport->qos)
-               MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.vlan_tag);
+               MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.vlan_tag);
 
        if (vport->spoofchk) {
-               MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.smac_47_16);
-               MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.smac_15_0);
+               MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_47_16);
+               MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_15_0);
                smac_v = MLX5_ADDR_OF(fte_match_param,
-                                     match_v,
+                                     spec->match_value,
                                      outer_headers.smac_47_16);
                ether_addr_copy(smac_v, smac);
        }
 
+       spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
        vport->ingress.allow_rule =
-               mlx5_add_flow_rule(vport->ingress.acl,
-                                  MLX5_MATCH_OUTER_HEADERS,
-                                  match_c,
-                                  match_v,
+               mlx5_add_flow_rule(vport->ingress.acl, spec,
                                   MLX5_FLOW_CONTEXT_ACTION_ALLOW,
                                   0, NULL);
        if (IS_ERR(vport->ingress.allow_rule)) {
@@ -1372,13 +1324,9 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
                goto out;
        }
 
-       memset(match_c, 0, MLX5_ST_SZ_BYTES(fte_match_param));
-       memset(match_v, 0, MLX5_ST_SZ_BYTES(fte_match_param));
+       memset(spec, 0, sizeof(*spec));
        vport->ingress.drop_rule =
-               mlx5_add_flow_rule(vport->ingress.acl,
-                                  0,
-                                  match_c,
-                                  match_v,
+               mlx5_add_flow_rule(vport->ingress.acl, spec,
                                   MLX5_FLOW_CONTEXT_ACTION_DROP,
                                   0, NULL);
        if (IS_ERR(vport->ingress.drop_rule)) {
@@ -1392,17 +1340,14 @@ static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
 out:
        if (err)
                esw_vport_cleanup_ingress_rules(esw, vport);
-
-       kfree(match_v);
-       kfree(match_c);
+       kvfree(spec);
        return err;
 }
 
 static int esw_vport_egress_config(struct mlx5_eswitch *esw,
                                   struct mlx5_vport *vport)
 {
-       u32 *match_v;
-       u32 *match_c;
+       struct mlx5_flow_spec *spec;
        int err = 0;
 
        esw_vport_cleanup_egress_rules(esw, vport);
@@ -1418,9 +1363,8 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw,
                  "vport[%d] configure egress rules, vlan(%d) qos(%d)\n",
                  vport->vport, vport->vlan, vport->qos);
 
-       match_v = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
-       match_c = kzalloc(MLX5_ST_SZ_BYTES(fte_match_param), GFP_KERNEL);
-       if (!match_v || !match_c) {
+       spec = mlx5_vzalloc(sizeof(*spec));
+       if (!spec) {
                err = -ENOMEM;
                esw_warn(esw->dev, "vport[%d] configure egress rules failed, err(%d)\n",
                         vport->vport, err);
@@ -1428,16 +1372,14 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw,
        }
 
        /* Allowed vlan rule */
-       MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.vlan_tag);
-       MLX5_SET_TO_ONES(fte_match_param, match_v, outer_headers.vlan_tag);
-       MLX5_SET_TO_ONES(fte_match_param, match_c, outer_headers.first_vid);
-       MLX5_SET(fte_match_param, match_v, outer_headers.first_vid, vport->vlan);
+       MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.vlan_tag);
+       MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.vlan_tag);
+       MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid);
+       MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vport->vlan);
 
+       spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
        vport->egress.allowed_vlan =
-               mlx5_add_flow_rule(vport->egress.acl,
-                                  MLX5_MATCH_OUTER_HEADERS,
-                                  match_c,
-                                  match_v,
+               mlx5_add_flow_rule(vport->egress.acl, spec,
                                   MLX5_FLOW_CONTEXT_ACTION_ALLOW,
                                   0, NULL);
        if (IS_ERR(vport->egress.allowed_vlan)) {
@@ -1449,13 +1391,9 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw,
        }
 
        /* Drop others rule (star rule) */
-       memset(match_c, 0, MLX5_ST_SZ_BYTES(fte_match_param));
-       memset(match_v, 0, MLX5_ST_SZ_BYTES(fte_match_param));
+       memset(spec, 0, sizeof(*spec));
        vport->egress.drop_rule =
-               mlx5_add_flow_rule(vport->egress.acl,
-                                  0,
-                                  match_c,
-                                  match_v,
+               mlx5_add_flow_rule(vport->egress.acl, spec,
                                   MLX5_FLOW_CONTEXT_ACTION_DROP,
                                   0, NULL);
        if (IS_ERR(vport->egress.drop_rule)) {
@@ -1465,8 +1403,7 @@ static int esw_vport_egress_config(struct mlx5_eswitch *esw,
                vport->egress.drop_rule = NULL;
        }
 out:
-       kfree(match_v);
-       kfree(match_c);
+       kvfree(spec);
        return err;
 }
 
@@ -1540,10 +1477,10 @@ static void esw_disable_vport(struct mlx5_eswitch *esw, int vport_num)
 }
 
 /* Public E-Switch API */
-int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs)
+int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode)
 {
        int err;
-       int i;
+       int i, enabled_events;
 
        if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
            MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
@@ -1561,16 +1498,20 @@ int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs)
        if (!MLX5_CAP_ESW_EGRESS_ACL(esw->dev, ft_support))
                esw_warn(esw->dev, "E-Switch engress ACL is not supported by FW\n");
 
-       esw_info(esw->dev, "E-Switch enable SRIOV: nvfs(%d)\n", nvfs);
-
+       esw_info(esw->dev, "E-Switch enable SRIOV: nvfs(%d) mode (%d)\n", nvfs, mode);
+       esw->mode = mode;
        esw_disable_vport(esw, 0);
 
-       err = esw_create_fdb_table(esw, nvfs + 1);
+       if (mode == SRIOV_LEGACY)
+               err = esw_create_legacy_fdb_table(esw, nvfs + 1);
+       else
+               err = esw_offloads_init(esw, nvfs + 1);
        if (err)
                goto abort;
 
+       enabled_events = (mode == SRIOV_LEGACY) ? SRIOV_VPORT_EVENTS : UC_ADDR_CHANGE;
        for (i = 0; i <= nvfs; i++)
-               esw_enable_vport(esw, i, SRIOV_VPORT_EVENTS);
+               esw_enable_vport(esw, i, enabled_events);
 
        esw_info(esw->dev, "SRIOV enabled: active vports(%d)\n",
                 esw->enabled_vports);
@@ -1584,16 +1525,18 @@ abort:
 void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
 {
        struct esw_mc_addr *mc_promisc;
+       int nvports;
        int i;
 
        if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager) ||
            MLX5_CAP_GEN(esw->dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
                return;
 
-       esw_info(esw->dev, "disable SRIOV: active vports(%d)\n",
-                esw->enabled_vports);
+       esw_info(esw->dev, "disable SRIOV: active vports(%d) mode(%d)\n",
+                esw->enabled_vports, esw->mode);
 
        mc_promisc = esw->mc_promisc;
+       nvports = esw->enabled_vports;
 
        for (i = 0; i < esw->total_vports; i++)
                esw_disable_vport(esw, i);
@@ -1601,8 +1544,12 @@ void mlx5_eswitch_disable_sriov(struct mlx5_eswitch *esw)
        if (mc_promisc && mc_promisc->uplink_rule)
                mlx5_del_flow_rule(mc_promisc->uplink_rule);
 
-       esw_destroy_fdb_table(esw);
+       if (esw->mode == SRIOV_LEGACY)
+               esw_destroy_legacy_fdb_table(esw);
+       else if (esw->mode == SRIOV_OFFLOADS)
+               esw_offloads_cleanup(esw, nvports);
 
+       esw->mode = SRIOV_NONE;
        /* VPORT 0 (PF) must be enabled back with non-sriov configuration */
        esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
 }
@@ -1660,6 +1607,14 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
                goto abort;
        }
 
+       esw->offloads.vport_reps =
+               kzalloc(total_vports * sizeof(struct mlx5_eswitch_rep),
+                       GFP_KERNEL);
+       if (!esw->offloads.vport_reps) {
+               err = -ENOMEM;
+               goto abort;
+       }
+
        mutex_init(&esw->state_lock);
 
        for (vport_num = 0; vport_num < total_vports; vport_num++) {
@@ -1673,6 +1628,7 @@ int mlx5_eswitch_init(struct mlx5_core_dev *dev)
 
        esw->total_vports = total_vports;
        esw->enabled_vports = 0;
+       esw->mode = SRIOV_NONE;
 
        dev->priv.eswitch = esw;
        esw_enable_vport(esw, 0, UC_ADDR_CHANGE);
@@ -1683,6 +1639,7 @@ abort:
                destroy_workqueue(esw->work_queue);
        kfree(esw->l2_table.bitmap);
        kfree(esw->vports);
+       kfree(esw->offloads.vport_reps);
        kfree(esw);
        return err;
 }
@@ -1700,6 +1657,7 @@ void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
        destroy_workqueue(esw->work_queue);
        kfree(esw->l2_table.bitmap);
        kfree(esw->mc_promisc);
+       kfree(esw->offloads.vport_reps);
        kfree(esw->vports);
        kfree(esw);
 }
@@ -1911,7 +1869,7 @@ int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
                                 struct ifla_vf_stats *vf_stats)
 {
        int outlen = MLX5_ST_SZ_BYTES(query_vport_counter_out);
-       u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)];
+       u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)] = {0};
        int err = 0;
        u32 *out;
 
@@ -1924,8 +1882,6 @@ int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
        if (!out)
                return -ENOMEM;
 
-       memset(in, 0, sizeof(in));
-
        MLX5_SET(query_vport_counter_in, in, opcode,
                 MLX5_CMD_OP_QUERY_VPORT_COUNTER);
        MLX5_SET(query_vport_counter_in, in, op_mod, 0);