net/mlx5e: Optimization for MTU change
[cascardo/linux.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_main.c
index 5a4d88c..65258b2 100644 (file)
@@ -47,14 +47,16 @@ enum {
 };
 
 struct mlx5e_rq_param {
-       u32                        rqc[MLX5_ST_SZ_DW(rqc)];
-       struct mlx5_wq_param       wq;
+       u32                     rqc[MLX5_ST_SZ_DW(rqc)];
+       struct mlx5_wq_param    wq;
+       bool                    am_enabled;
 };
 
 struct mlx5e_sq_param {
        u32                        sqc[MLX5_ST_SZ_DW(sqc)];
        struct mlx5_wq_param       wq;
        u16                        max_inline;
+       u8                         min_inline_mode;
        bool                       icosq;
 };
 
@@ -62,6 +64,7 @@ struct mlx5e_cq_param {
        u32                        cqc[MLX5_ST_SZ_DW(cqc)];
        struct mlx5_wq_param       wq;
        u16                        eq_ix;
+       u8                         cq_period_mode;
 };
 
 struct mlx5e_channel_param {
@@ -254,14 +257,14 @@ void mlx5e_update_stats(struct mlx5e_priv *priv)
        mlx5e_update_sw_counters(priv);
 }
 
-static void mlx5e_update_stats_work(struct work_struct *work)
+void mlx5e_update_stats_work(struct work_struct *work)
 {
        struct delayed_work *dwork = to_delayed_work(work);
        struct mlx5e_priv *priv = container_of(dwork, struct mlx5e_priv,
                                               update_stats_work);
        mutex_lock(&priv->state_lock);
        if (test_bit(MLX5E_STATE_OPENED, &priv->state)) {
-               mlx5e_update_stats(priv);
+               priv->profile->update_stats(priv);
                queue_delayed_work(priv->wq, dwork,
                                   msecs_to_jiffies(MLX5E_UPDATE_STATS_INTERVAL));
        }
@@ -367,6 +370,9 @@ static int mlx5e_create_rq(struct mlx5e_channel *c,
                wqe->data.byte_count = cpu_to_be32(byte_count);
        }
 
+       INIT_WORK(&rq->am.work, mlx5e_rx_am_work);
+       rq->am.mode = priv->params.rx_cq_period_mode;
+
        rq->wq_type = priv->params.rq_wq_type;
        rq->pdev    = c->pdev;
        rq->netdev  = c->netdev;
@@ -539,6 +545,9 @@ static int mlx5e_open_rq(struct mlx5e_channel *c,
        if (err)
                goto err_disable_rq;
 
+       if (param->am_enabled)
+               set_bit(MLX5E_RQ_STATE_AM, &c->rq.state);
+
        set_bit(MLX5E_RQ_STATE_POST_WQES_ENABLE, &rq->state);
 
        sq->ico_wqe_info[pi].opcode     = MLX5_OPCODE_NOP;
@@ -574,6 +583,8 @@ static void mlx5e_close_rq(struct mlx5e_rq *rq)
        /* avoid destroying rq before mlx5e_poll_rx_cq() is done with it */
        napi_synchronize(&rq->channel->napi);
 
+       cancel_work_sync(&rq->am.work);
+
        mlx5e_disable_rq(rq);
        mlx5e_free_rx_descs(rq);
        mlx5e_destroy_rq(rq);
@@ -639,6 +650,9 @@ static int mlx5e_create_sq(struct mlx5e_channel *c,
        }
        sq->bf_buf_size = (1 << MLX5_CAP_GEN(mdev, log_bf_reg_size)) / 2;
        sq->max_inline  = param->max_inline;
+       sq->min_inline_mode =
+               MLX5_CAP_ETH(mdev, wqe_inline_mode) == MLX5E_INLINE_MODE_VPORT_CONTEXT ?
+               param->min_inline_mode : 0;
 
        err = mlx5e_alloc_sq_db(sq, cpu_to_node(c->cpu));
        if (err)
@@ -721,6 +735,7 @@ static int mlx5e_enable_sq(struct mlx5e_sq *sq, struct mlx5e_sq_param *param)
 
        MLX5_SET(sqc,  sqc, tis_num_0, param->icosq ? 0 : priv->tisn[sq->tc]);
        MLX5_SET(sqc,  sqc, cqn,                sq->cq.mcq.cqn);
+       MLX5_SET(sqc,  sqc, min_wqe_inline_mode, sq->min_inline_mode);
        MLX5_SET(sqc,  sqc, state,              MLX5_SQC_STATE_RST);
        MLX5_SET(sqc,  sqc, tis_lst_sz,         param->icosq ? 0 : 1);
        MLX5_SET(sqc,  sqc, flush_in_error_en,  1);
@@ -741,7 +756,8 @@ static int mlx5e_enable_sq(struct mlx5e_sq *sq, struct mlx5e_sq_param *param)
        return err;
 }
 
-static int mlx5e_modify_sq(struct mlx5e_sq *sq, int curr_state, int next_state)
+static int mlx5e_modify_sq(struct mlx5e_sq *sq, int curr_state,
+                          int next_state, bool update_rl, int rl_index)
 {
        struct mlx5e_channel *c = sq->channel;
        struct mlx5e_priv *priv = c->priv;
@@ -761,6 +777,10 @@ static int mlx5e_modify_sq(struct mlx5e_sq *sq, int curr_state, int next_state)
 
        MLX5_SET(modify_sq_in, in, sq_state, curr_state);
        MLX5_SET(sqc, sqc, state, next_state);
+       if (update_rl && next_state == MLX5_SQC_STATE_RDY) {
+               MLX5_SET64(modify_sq_in, in, modify_bitmask, 1);
+               MLX5_SET(sqc,  sqc, packet_pacing_rate_limit_index, rl_index);
+       }
 
        err = mlx5_core_modify_sq(mdev, sq->sqn, in, inlen);
 
@@ -776,6 +796,8 @@ static void mlx5e_disable_sq(struct mlx5e_sq *sq)
        struct mlx5_core_dev *mdev = priv->mdev;
 
        mlx5_core_destroy_sq(mdev, sq->sqn);
+       if (sq->rate_limit)
+               mlx5_rl_remove_rate(mdev, sq->rate_limit);
 }
 
 static int mlx5e_open_sq(struct mlx5e_channel *c,
@@ -793,7 +815,8 @@ static int mlx5e_open_sq(struct mlx5e_channel *c,
        if (err)
                goto err_destroy_sq;
 
-       err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY);
+       err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY,
+                             false, 0);
        if (err)
                goto err_disable_sq;
 
@@ -836,7 +859,7 @@ static void mlx5e_close_sq(struct mlx5e_sq *sq)
                        mlx5e_send_nop(sq, true);
 
                err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RDY,
-                                     MLX5_SQC_STATE_ERR);
+                                     MLX5_SQC_STATE_ERR, false, 0);
                if (err)
                        set_bit(MLX5E_SQ_STATE_TX_TIMEOUT, &sq->state);
        }
@@ -891,7 +914,7 @@ static int mlx5e_create_cq(struct mlx5e_channel *c,
        mcq->comp       = mlx5e_completion_event;
        mcq->event      = mlx5e_cq_error_event;
        mcq->irqn       = irqn;
-       mcq->uar        = &priv->cq_uar;
+       mcq->uar        = &mdev->mlx5e_res.cq_uar;
 
        for (i = 0; i < mlx5_cqwq_get_size(&cq->wq); i++) {
                struct mlx5_cqe64 *cqe = mlx5_cqwq_get_wqe(&cq->wq, i);
@@ -938,6 +961,7 @@ static int mlx5e_enable_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
 
        mlx5_vector2eqn(mdev, param->eq_ix, &eqn, &irqn_not_used);
 
+       MLX5_SET(cqc,   cqc, cq_period_mode, param->cq_period_mode);
        MLX5_SET(cqc,   cqc, c_eqn,         eqn);
        MLX5_SET(cqc,   cqc, uar_page,      mcq->uar->index);
        MLX5_SET(cqc,   cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
@@ -967,8 +991,7 @@ static void mlx5e_disable_cq(struct mlx5e_cq *cq)
 static int mlx5e_open_cq(struct mlx5e_channel *c,
                         struct mlx5e_cq_param *param,
                         struct mlx5e_cq *cq,
-                        u16 moderation_usecs,
-                        u16 moderation_frames)
+                        struct mlx5e_cq_moder moderation)
 {
        int err;
        struct mlx5e_priv *priv = c->priv;
@@ -984,8 +1007,8 @@ static int mlx5e_open_cq(struct mlx5e_channel *c,
 
        if (MLX5_CAP_GEN(mdev, cq_moderation))
                mlx5_core_modify_cq_moderation(mdev, &cq->mcq,
-                                              moderation_usecs,
-                                              moderation_frames);
+                                              moderation.usec,
+                                              moderation.pkts);
        return 0;
 
 err_destroy_cq:
@@ -1014,8 +1037,7 @@ static int mlx5e_open_tx_cqs(struct mlx5e_channel *c,
 
        for (tc = 0; tc < c->num_tc; tc++) {
                err = mlx5e_open_cq(c, &cparam->tx_cq, &c->sq[tc].cq,
-                                   priv->params.tx_cq_moderation_usec,
-                                   priv->params.tx_cq_moderation_pkts);
+                                   priv->params.tx_cq_moderation);
                if (err)
                        goto err_close_tx_cqs;
        }
@@ -1070,19 +1092,96 @@ static void mlx5e_build_channeltc_to_txq_map(struct mlx5e_priv *priv, int ix)
 {
        int i;
 
-       for (i = 0; i < MLX5E_MAX_NUM_TC; i++)
+       for (i = 0; i < priv->profile->max_tc; i++)
                priv->channeltc_to_txq_map[ix][i] =
                        ix + i * priv->params.num_channels;
 }
 
+static int mlx5e_set_sq_maxrate(struct net_device *dev,
+                               struct mlx5e_sq *sq, u32 rate)
+{
+       struct mlx5e_priv *priv = netdev_priv(dev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+       u16 rl_index = 0;
+       int err;
+
+       if (rate == sq->rate_limit)
+               /* nothing to do */
+               return 0;
+
+       if (sq->rate_limit)
+               /* remove current rl index to free space to next ones */
+               mlx5_rl_remove_rate(mdev, sq->rate_limit);
+
+       sq->rate_limit = 0;
+
+       if (rate) {
+               err = mlx5_rl_add_rate(mdev, rate, &rl_index);
+               if (err) {
+                       netdev_err(dev, "Failed configuring rate %u: %d\n",
+                                  rate, err);
+                       return err;
+               }
+       }
+
+       err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RDY,
+                             MLX5_SQC_STATE_RDY, true, rl_index);
+       if (err) {
+               netdev_err(dev, "Failed configuring rate %u: %d\n",
+                          rate, err);
+               /* remove the rate from the table */
+               if (rate)
+                       mlx5_rl_remove_rate(mdev, rate);
+               return err;
+       }
+
+       sq->rate_limit = rate;
+       return 0;
+}
+
+static int mlx5e_set_tx_maxrate(struct net_device *dev, int index, u32 rate)
+{
+       struct mlx5e_priv *priv = netdev_priv(dev);
+       struct mlx5_core_dev *mdev = priv->mdev;
+       struct mlx5e_sq *sq = priv->txq_to_sq_map[index];
+       int err = 0;
+
+       if (!mlx5_rl_is_supported(mdev)) {
+               netdev_err(dev, "Rate limiting is not supported on this device\n");
+               return -EINVAL;
+       }
+
+       /* rate is given in Mb/sec, HW config is in Kb/sec */
+       rate = rate << 10;
+
+       /* Check whether rate in valid range, 0 is always valid */
+       if (rate && !mlx5_rl_is_in_range(mdev, rate)) {
+               netdev_err(dev, "TX rate %u, is not in range\n", rate);
+               return -ERANGE;
+       }
+
+       mutex_lock(&priv->state_lock);
+       if (test_bit(MLX5E_STATE_OPENED, &priv->state))
+               err = mlx5e_set_sq_maxrate(dev, sq, rate);
+       if (!err)
+               priv->tx_rates[index] = rate;
+       mutex_unlock(&priv->state_lock);
+
+       return err;
+}
+
 static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
                              struct mlx5e_channel_param *cparam,
                              struct mlx5e_channel **cp)
 {
+       struct mlx5e_cq_moder icosq_cq_moder = {0, 0};
        struct net_device *netdev = priv->netdev;
+       struct mlx5e_cq_moder rx_cq_profile;
        int cpu = mlx5e_get_cpu(priv, ix);
        struct mlx5e_channel *c;
+       struct mlx5e_sq *sq;
        int err;
+       int i;
 
        c = kzalloc_node(sizeof(*c), GFP_KERNEL, cpu_to_node(cpu));
        if (!c)
@@ -1093,14 +1192,19 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
        c->cpu      = cpu;
        c->pdev     = &priv->mdev->pdev->dev;
        c->netdev   = priv->netdev;
-       c->mkey_be  = cpu_to_be32(priv->mkey.key);
+       c->mkey_be  = cpu_to_be32(priv->mdev->mlx5e_res.mkey.key);
        c->num_tc   = priv->params.num_tc;
 
+       if (priv->params.rx_am_enabled)
+               rx_cq_profile = mlx5e_am_get_def_profile(priv->params.rx_cq_period_mode);
+       else
+               rx_cq_profile = priv->params.rx_cq_moderation;
+
        mlx5e_build_channeltc_to_txq_map(priv, ix);
 
        netif_napi_add(netdev, &c->napi, mlx5e_napi_poll, 64);
 
-       err = mlx5e_open_cq(c, &cparam->icosq_cq, &c->icosq.cq, 0, 0);
+       err = mlx5e_open_cq(c, &cparam->icosq_cq, &c->icosq.cq, icosq_cq_moder);
        if (err)
                goto err_napi_del;
 
@@ -1109,8 +1213,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
                goto err_close_icosq_cq;
 
        err = mlx5e_open_cq(c, &cparam->rx_cq, &c->rq.cq,
-                           priv->params.rx_cq_moderation_usec,
-                           priv->params.rx_cq_moderation_pkts);
+                           rx_cq_profile);
        if (err)
                goto err_close_tx_cqs;
 
@@ -1124,6 +1227,16 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
        if (err)
                goto err_close_icosq;
 
+       for (i = 0; i < priv->params.num_tc; i++) {
+               u32 txq_ix = priv->channeltc_to_txq_map[ix][i];
+
+               if (priv->tx_rates[txq_ix]) {
+                       sq = priv->txq_to_sq_map[txq_ix];
+                       mlx5e_set_sq_maxrate(priv->netdev, sq,
+                                            priv->tx_rates[txq_ix]);
+               }
+       }
+
        err = mlx5e_open_rq(c, &cparam->rq, &c->rq);
        if (err)
                goto err_close_sqs;
@@ -1195,11 +1308,13 @@ static void mlx5e_build_rq_param(struct mlx5e_priv *priv,
        MLX5_SET(wq, wq, end_padding_mode, MLX5_WQ_END_PAD_MODE_ALIGN);
        MLX5_SET(wq, wq, log_wq_stride,    ilog2(sizeof(struct mlx5e_rx_wqe)));
        MLX5_SET(wq, wq, log_wq_sz,        priv->params.log_rq_size);
-       MLX5_SET(wq, wq, pd,               priv->pdn);
+       MLX5_SET(wq, wq, pd,               priv->mdev->mlx5e_res.pdn);
        MLX5_SET(rqc, rqc, counter_set_id, priv->q_counter);
 
        param->wq.buf_numa_node = dev_to_node(&priv->mdev->pdev->dev);
        param->wq.linear = 1;
+
+       param->am_enabled = priv->params.rx_am_enabled;
 }
 
 static void mlx5e_build_drop_rq_param(struct mlx5e_rq_param *param)
@@ -1218,7 +1333,7 @@ static void mlx5e_build_sq_param_common(struct mlx5e_priv *priv,
        void *wq = MLX5_ADDR_OF(sqc, sqc, wq);
 
        MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB));
-       MLX5_SET(wq, wq, pd,            priv->pdn);
+       MLX5_SET(wq, wq, pd,            priv->mdev->mlx5e_res.pdn);
 
        param->wq.buf_numa_node = dev_to_node(&priv->mdev->pdev->dev);
 }
@@ -1233,6 +1348,7 @@ static void mlx5e_build_sq_param(struct mlx5e_priv *priv,
        MLX5_SET(wq, wq, log_wq_sz,     priv->params.log_sq_size);
 
        param->max_inline = priv->params.tx_max_inline;
+       param->min_inline_mode = priv->params.tx_min_inline_mode;
 }
 
 static void mlx5e_build_common_cq_param(struct mlx5e_priv *priv,
@@ -1240,7 +1356,7 @@ static void mlx5e_build_common_cq_param(struct mlx5e_priv *priv,
 {
        void *cqc = param->cqc;
 
-       MLX5_SET(cqc, cqc, uar_page, priv->cq_uar.index);
+       MLX5_SET(cqc, cqc, uar_page, priv->mdev->mlx5e_res.cq_uar.index);
 }
 
 static void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
@@ -1265,6 +1381,8 @@ static void mlx5e_build_rx_cq_param(struct mlx5e_priv *priv,
        }
 
        mlx5e_build_common_cq_param(priv, param);
+
+       param->cq_period_mode = priv->params.rx_cq_period_mode;
 }
 
 static void mlx5e_build_tx_cq_param(struct mlx5e_priv *priv,
@@ -1275,6 +1393,8 @@ static void mlx5e_build_tx_cq_param(struct mlx5e_priv *priv,
        MLX5_SET(cqc, cqc, log_cq_size, priv->params.log_sq_size);
 
        mlx5e_build_common_cq_param(priv, param);
+
+       param->cq_period_mode = MLX5_CQ_PERIOD_MODE_START_FROM_EQE;
 }
 
 static void mlx5e_build_ico_cq_param(struct mlx5e_priv *priv,
@@ -1286,6 +1406,8 @@ static void mlx5e_build_ico_cq_param(struct mlx5e_priv *priv,
        MLX5_SET(cqc, cqc, log_cq_size, log_wq_size);
 
        mlx5e_build_common_cq_param(priv, param);
+
+       param->cq_period_mode = MLX5_CQ_PERIOD_MODE_START_FROM_EQE;
 }
 
 static void mlx5e_build_icosq_param(struct mlx5e_priv *priv,
@@ -1432,7 +1554,8 @@ static void mlx5e_fill_direct_rqt_rqn(struct mlx5e_priv *priv, void *rqtc,
        MLX5_SET(rqtc, rqtc, rq_num[0], rqn);
 }
 
-static int mlx5e_create_rqt(struct mlx5e_priv *priv, int sz, int ix, u32 *rqtn)
+static int mlx5e_create_rqt(struct mlx5e_priv *priv, int sz,
+                           int ix, struct mlx5e_rqt *rqt)
 {
        struct mlx5_core_dev *mdev = priv->mdev;
        void *rqtc;
@@ -1455,34 +1578,36 @@ static int mlx5e_create_rqt(struct mlx5e_priv *priv, int sz, int ix, u32 *rqtn)
        else
                mlx5e_fill_direct_rqt_rqn(priv, rqtc, ix);
 
-       err = mlx5_core_create_rqt(mdev, in, inlen, rqtn);
+       err = mlx5_core_create_rqt(mdev, in, inlen, &rqt->rqtn);
+       if (!err)
+               rqt->enabled = true;
 
        kvfree(in);
        return err;
 }
 
-static void mlx5e_destroy_rqt(struct mlx5e_priv *priv, u32 rqtn)
+void mlx5e_destroy_rqt(struct mlx5e_priv *priv, struct mlx5e_rqt *rqt)
+{
+       rqt->enabled = false;
+       mlx5_core_destroy_rqt(priv->mdev, rqt->rqtn);
+}
+
+static int mlx5e_create_indirect_rqts(struct mlx5e_priv *priv)
 {
-       mlx5_core_destroy_rqt(priv->mdev, rqtn);
+       struct mlx5e_rqt *rqt = &priv->indir_rqt;
+
+       return mlx5e_create_rqt(priv, MLX5E_INDIR_RQT_SIZE, 0, rqt);
 }
 
-static int mlx5e_create_rqts(struct mlx5e_priv *priv)
+int mlx5e_create_direct_rqts(struct mlx5e_priv *priv)
 {
-       int nch = mlx5e_get_max_num_channels(priv->mdev);
-       u32 *rqtn;
+       struct mlx5e_rqt *rqt;
        int err;
        int ix;
 
-       /* Indirect RQT */
-       rqtn = &priv->indir_rqtn;
-       err = mlx5e_create_rqt(priv, MLX5E_INDIR_RQT_SIZE, 0, rqtn);
-       if (err)
-               return err;
-
-       /* Direct RQTs */
-       for (ix = 0; ix < nch; ix++) {
-               rqtn = &priv->direct_tir[ix].rqtn;
-               err = mlx5e_create_rqt(priv, 1 /*size */, ix, rqtn);
+       for (ix = 0; ix < priv->profile->max_nch(priv->mdev); ix++) {
+               rqt = &priv->direct_tir[ix].rqt;
+               err = mlx5e_create_rqt(priv, 1 /*size */, ix, rqt);
                if (err)
                        goto err_destroy_rqts;
        }
@@ -1491,24 +1616,11 @@ static int mlx5e_create_rqts(struct mlx5e_priv *priv)
 
 err_destroy_rqts:
        for (ix--; ix >= 0; ix--)
-               mlx5e_destroy_rqt(priv, priv->direct_tir[ix].rqtn);
-
-       mlx5e_destroy_rqt(priv, priv->indir_rqtn);
+               mlx5e_destroy_rqt(priv, &priv->direct_tir[ix].rqt);
 
        return err;
 }
 
-static void mlx5e_destroy_rqts(struct mlx5e_priv *priv)
-{
-       int nch = mlx5e_get_max_num_channels(priv->mdev);
-       int i;
-
-       for (i = 0; i < nch; i++)
-               mlx5e_destroy_rqt(priv, priv->direct_tir[i].rqtn);
-
-       mlx5e_destroy_rqt(priv, priv->indir_rqtn);
-}
-
 int mlx5e_redirect_rqt(struct mlx5e_priv *priv, u32 rqtn, int sz, int ix)
 {
        struct mlx5_core_dev *mdev = priv->mdev;
@@ -1544,10 +1656,15 @@ static void mlx5e_redirect_rqts(struct mlx5e_priv *priv)
        u32 rqtn;
        int ix;
 
-       rqtn = priv->indir_rqtn;
-       mlx5e_redirect_rqt(priv, rqtn, MLX5E_INDIR_RQT_SIZE, 0);
+       if (priv->indir_rqt.enabled) {
+               rqtn = priv->indir_rqt.rqtn;
+               mlx5e_redirect_rqt(priv, rqtn, MLX5E_INDIR_RQT_SIZE, 0);
+       }
+
        for (ix = 0; ix < priv->params.num_channels; ix++) {
-               rqtn = priv->direct_tir[ix].rqtn;
+               if (!priv->direct_tir[ix].rqt.enabled)
+                       continue;
+               rqtn = priv->direct_tir[ix].rqt.rqtn;
                mlx5e_redirect_rqt(priv, rqtn, 1, ix);
        }
 }
@@ -1607,13 +1724,13 @@ static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv)
        mlx5e_build_tir_ctx_lro(tirc, priv);
 
        for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
-               err = mlx5_core_modify_tir(mdev, priv->indir_tirn[tt], in,
+               err = mlx5_core_modify_tir(mdev, priv->indir_tir[tt].tirn, in,
                                           inlen);
                if (err)
                        goto free_in;
        }
 
-       for (ix = 0; ix < mlx5e_get_max_num_channels(mdev); ix++) {
+       for (ix = 0; ix < priv->profile->max_nch(priv->mdev); ix++) {
                err = mlx5_core_modify_tir(mdev, priv->direct_tir[ix].tirn,
                                           in, inlen);
                if (err)
@@ -1626,40 +1743,6 @@ free_in:
        return err;
 }
 
-static int mlx5e_refresh_tirs_self_loopback_enable(struct mlx5e_priv *priv)
-{
-       void *in;
-       int inlen;
-       int err;
-       int i;
-
-       inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
-       in = mlx5_vzalloc(inlen);
-       if (!in)
-               return -ENOMEM;
-
-       MLX5_SET(modify_tir_in, in, bitmask.self_lb_en, 1);
-
-       for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++) {
-               err = mlx5_core_modify_tir(priv->mdev, priv->indir_tirn[i], in,
-                                          inlen);
-               if (err)
-                       return err;
-       }
-
-       for (i = 0; i < priv->params.num_channels; i++) {
-               err = mlx5_core_modify_tir(priv->mdev,
-                                          priv->direct_tir[i].tirn, in,
-                                          inlen);
-               if (err)
-                       return err;
-       }
-
-       kvfree(in);
-
-       return 0;
-}
-
 static int mlx5e_set_mtu(struct mlx5e_priv *priv, u16 mtu)
 {
        struct mlx5_core_dev *mdev = priv->mdev;
@@ -1731,6 +1814,7 @@ static void mlx5e_netdev_set_tcs(struct net_device *netdev)
 int mlx5e_open_locked(struct net_device *netdev)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
+       struct mlx5_core_dev *mdev = priv->mdev;
        int num_txqs;
        int err;
 
@@ -1742,10 +1826,6 @@ int mlx5e_open_locked(struct net_device *netdev)
        netif_set_real_num_tx_queues(netdev, num_txqs);
        netif_set_real_num_rx_queues(netdev, priv->params.num_channels);
 
-       err = mlx5e_set_dev_port_mtu(netdev);
-       if (err)
-               goto err_clear_state_opened_flag;
-
        err = mlx5e_open_channels(priv);
        if (err) {
                netdev_err(netdev, "%s: mlx5e_open_channels failed, %d\n",
@@ -1753,7 +1833,7 @@ int mlx5e_open_locked(struct net_device *netdev)
                goto err_clear_state_opened_flag;
        }
 
-       err = mlx5e_refresh_tirs_self_loopback_enable(priv);
+       err = mlx5e_refresh_tirs_self_loopback_enable(priv->mdev);
        if (err) {
                netdev_err(netdev, "%s: mlx5e_refresh_tirs_self_loopback_enable failed, %d\n",
                           __func__, err);
@@ -1766,9 +1846,14 @@ int mlx5e_open_locked(struct net_device *netdev)
 #ifdef CONFIG_RFS_ACCEL
        priv->netdev->rx_cpu_rmap = priv->mdev->rmap;
 #endif
+       if (priv->profile->update_stats)
+               queue_delayed_work(priv->wq, &priv->update_stats_work, 0);
 
-       queue_delayed_work(priv->wq, &priv->update_stats_work, 0);
-
+       if (MLX5_CAP_GEN(mdev, vport_group_manager)) {
+               err = mlx5e_add_sqs_fwd_rules(priv);
+               if (err)
+                       goto err_close_channels;
+       }
        return 0;
 
 err_close_channels:
@@ -1778,7 +1863,7 @@ err_clear_state_opened_flag:
        return err;
 }
 
-static int mlx5e_open(struct net_device *netdev)
+int mlx5e_open(struct net_device *netdev)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        int err;
@@ -1793,6 +1878,7 @@ static int mlx5e_open(struct net_device *netdev)
 int mlx5e_close_locked(struct net_device *netdev)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
+       struct mlx5_core_dev *mdev = priv->mdev;
 
        /* May already be CLOSED in case a previous configuration operation
         * (e.g RX/TX queue size change) that involves close&open failed.
@@ -1802,6 +1888,9 @@ int mlx5e_close_locked(struct net_device *netdev)
 
        clear_bit(MLX5E_STATE_OPENED, &priv->state);
 
+       if (MLX5_CAP_GEN(mdev, vport_group_manager))
+               mlx5e_remove_sqs_fwd_rules(priv);
+
        mlx5e_timestamp_cleanup(priv);
        netif_carrier_off(priv->netdev);
        mlx5e_redirect_rqts(priv);
@@ -1810,7 +1899,7 @@ int mlx5e_close_locked(struct net_device *netdev)
        return 0;
 }
 
-static int mlx5e_close(struct net_device *netdev)
+int mlx5e_close(struct net_device *netdev)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        int err;
@@ -1869,7 +1958,7 @@ static int mlx5e_create_drop_cq(struct mlx5e_priv *priv,
        mcq->comp       = mlx5e_completion_event;
        mcq->event      = mlx5e_cq_error_event;
        mcq->irqn       = irqn;
-       mcq->uar        = &priv->cq_uar;
+       mcq->uar        = &mdev->mlx5e_res.cq_uar;
 
        cq->priv = priv;
 
@@ -1935,7 +2024,7 @@ static int mlx5e_create_tis(struct mlx5e_priv *priv, int tc)
        memset(in, 0, sizeof(in));
 
        MLX5_SET(tisc, tisc, prio, tc << 1);
-       MLX5_SET(tisc, tisc, transport_domain, priv->tdn);
+       MLX5_SET(tisc, tisc, transport_domain, mdev->mlx5e_res.td.tdn);
 
        return mlx5_core_create_tis(mdev, in, sizeof(in), &priv->tisn[tc]);
 }
@@ -1945,12 +2034,12 @@ static void mlx5e_destroy_tis(struct mlx5e_priv *priv, int tc)
        mlx5_core_destroy_tis(priv->mdev, priv->tisn[tc]);
 }
 
-static int mlx5e_create_tises(struct mlx5e_priv *priv)
+int mlx5e_create_tises(struct mlx5e_priv *priv)
 {
        int err;
        int tc;
 
-       for (tc = 0; tc < MLX5E_MAX_NUM_TC; tc++) {
+       for (tc = 0; tc < priv->profile->max_tc; tc++) {
                err = mlx5e_create_tis(priv, tc);
                if (err)
                        goto err_close_tises;
@@ -1965,11 +2054,11 @@ err_close_tises:
        return err;
 }
 
-static void mlx5e_destroy_tises(struct mlx5e_priv *priv)
+void mlx5e_cleanup_nic_tx(struct mlx5e_priv *priv)
 {
        int tc;
 
-       for (tc = 0; tc < MLX5E_MAX_NUM_TC; tc++)
+       for (tc = 0; tc < priv->profile->max_tc; tc++)
                mlx5e_destroy_tis(priv, tc);
 }
 
@@ -1978,7 +2067,7 @@ static void mlx5e_build_indir_tir_ctx(struct mlx5e_priv *priv, u32 *tirc,
 {
        void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer);
 
-       MLX5_SET(tirc, tirc, transport_domain, priv->tdn);
+       MLX5_SET(tirc, tirc, transport_domain, priv->mdev->mlx5e_res.td.tdn);
 
 #define MLX5_HASH_IP            (MLX5_HASH_FIELD_SEL_SRC_IP   |\
                                 MLX5_HASH_FIELD_SEL_DST_IP)
@@ -1995,7 +2084,7 @@ static void mlx5e_build_indir_tir_ctx(struct mlx5e_priv *priv, u32 *tirc,
        mlx5e_build_tir_ctx_lro(tirc, priv);
 
        MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT);
-       MLX5_SET(tirc, tirc, indirect_table, priv->indir_rqtn);
+       MLX5_SET(tirc, tirc, indirect_table, priv->indir_rqt.rqtn);
        mlx5e_build_tir_ctx_hash(tirc, priv);
 
        switch (tt) {
@@ -2085,7 +2174,7 @@ static void mlx5e_build_indir_tir_ctx(struct mlx5e_priv *priv, u32 *tirc,
 static void mlx5e_build_direct_tir_ctx(struct mlx5e_priv *priv, u32 *tirc,
                                       u32 rqtn)
 {
-       MLX5_SET(tirc, tirc, transport_domain, priv->tdn);
+       MLX5_SET(tirc, tirc, transport_domain, priv->mdev->mlx5e_res.td.tdn);
 
        mlx5e_build_tir_ctx_lro(tirc, priv);
 
@@ -2094,15 +2183,13 @@ static void mlx5e_build_direct_tir_ctx(struct mlx5e_priv *priv, u32 *tirc,
        MLX5_SET(tirc, tirc, rx_hash_fn, MLX5_RX_HASH_FN_INVERTED_XOR8);
 }
 
-static int mlx5e_create_tirs(struct mlx5e_priv *priv)
+static int mlx5e_create_indirect_tirs(struct mlx5e_priv *priv)
 {
-       int nch = mlx5e_get_max_num_channels(priv->mdev);
+       struct mlx5e_tir *tir;
        void *tirc;
        int inlen;
-       u32 *tirn;
        int err;
        u32 *in;
-       int ix;
        int tt;
 
        inlen = MLX5_ST_SZ_BYTES(create_tir_in);
@@ -2110,25 +2197,51 @@ static int mlx5e_create_tirs(struct mlx5e_priv *priv)
        if (!in)
                return -ENOMEM;
 
-       /* indirect tirs */
        for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) {
                memset(in, 0, inlen);
-               tirn = &priv->indir_tirn[tt];
+               tir = &priv->indir_tir[tt];
                tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
                mlx5e_build_indir_tir_ctx(priv, tirc, tt);
-               err = mlx5_core_create_tir(priv->mdev, in, inlen, tirn);
+               err = mlx5e_create_tir(priv->mdev, tir, in, inlen);
                if (err)
                        goto err_destroy_tirs;
        }
 
-       /* direct tirs */
+       kvfree(in);
+
+       return 0;
+
+err_destroy_tirs:
+       for (tt--; tt >= 0; tt--)
+               mlx5e_destroy_tir(priv->mdev, &priv->indir_tir[tt]);
+
+       kvfree(in);
+
+       return err;
+}
+
+int mlx5e_create_direct_tirs(struct mlx5e_priv *priv)
+{
+       int nch = priv->profile->max_nch(priv->mdev);
+       struct mlx5e_tir *tir;
+       void *tirc;
+       int inlen;
+       int err;
+       u32 *in;
+       int ix;
+
+       inlen = MLX5_ST_SZ_BYTES(create_tir_in);
+       in = mlx5_vzalloc(inlen);
+       if (!in)
+               return -ENOMEM;
+
        for (ix = 0; ix < nch; ix++) {
                memset(in, 0, inlen);
-               tirn = &priv->direct_tir[ix].tirn;
+               tir = &priv->direct_tir[ix];
                tirc = MLX5_ADDR_OF(create_tir_in, in, ctx);
                mlx5e_build_direct_tir_ctx(priv, tirc,
-                                          priv->direct_tir[ix].rqtn);
-               err = mlx5_core_create_tir(priv->mdev, in, inlen, tirn);
+                                          priv->direct_tir[ix].rqt.rqtn);
+               err = mlx5e_create_tir(priv->mdev, tir, in, inlen);
                if (err)
                        goto err_destroy_ch_tirs;
        }
@@ -2139,27 +2252,28 @@ static int mlx5e_create_tirs(struct mlx5e_priv *priv)
 
 err_destroy_ch_tirs:
        for (ix--; ix >= 0; ix--)
-               mlx5_core_destroy_tir(priv->mdev, priv->direct_tir[ix].tirn);
-
-err_destroy_tirs:
-       for (tt--; tt >= 0; tt--)
-               mlx5_core_destroy_tir(priv->mdev, priv->indir_tirn[tt]);
+               mlx5e_destroy_tir(priv->mdev, &priv->direct_tir[ix]);
 
        kvfree(in);
 
        return err;
 }
 
-static void mlx5e_destroy_tirs(struct mlx5e_priv *priv)
+static void mlx5e_destroy_indirect_tirs(struct mlx5e_priv *priv)
 {
-       int nch = mlx5e_get_max_num_channels(priv->mdev);
        int i;
 
-       for (i = 0; i < nch; i++)
-               mlx5_core_destroy_tir(priv->mdev, priv->direct_tir[i].tirn);
-
        for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++)
-               mlx5_core_destroy_tir(priv->mdev, priv->indir_tirn[i]);
+               mlx5e_destroy_tir(priv->mdev, &priv->indir_tir[i]);
+}
+
+void mlx5e_destroy_direct_tirs(struct mlx5e_priv *priv)
+{
+       int nch = priv->profile->max_nch(priv->mdev);
+       int i;
+
+       for (i = 0; i < nch; i++)
+               mlx5e_destroy_tir(priv->mdev, &priv->direct_tir[i]);
 }
 
 int mlx5e_modify_rqs_vsd(struct mlx5e_priv *priv, bool vsd)
@@ -2233,7 +2347,7 @@ mqprio:
        return mlx5e_setup_tc(dev, tc->tc);
 }
 
-static struct rtnl_link_stats64 *
+struct rtnl_link_stats64 *
 mlx5e_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
 {
        struct mlx5e_priv *priv = netdev_priv(dev);
@@ -2455,6 +2569,7 @@ static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu)
        u16 max_mtu;
        u16 min_mtu;
        int err = 0;
+       bool reset;
 
        mlx5_query_port_max_mtu(mdev, &max_mtu, 1);
 
@@ -2470,13 +2585,18 @@ static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu)
 
        mutex_lock(&priv->state_lock);
 
+       reset = !priv->params.lro_en &&
+               (priv->params.rq_wq_type !=
+                MLX5_WQ_TYPE_LINKED_LIST_STRIDING_RQ);
+
        was_opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
-       if (was_opened)
+       if (was_opened && reset)
                mlx5e_close_locked(netdev);
 
        netdev->mtu = new_mtu;
+       mlx5e_set_dev_port_mtu(netdev);
 
-       if (was_opened)
+       if (was_opened && reset)
                err = mlx5e_open_locked(netdev);
 
        mutex_unlock(&priv->state_lock);
@@ -2585,25 +2705,31 @@ static int mlx5e_get_vf_stats(struct net_device *dev,
 }
 
 static void mlx5e_add_vxlan_port(struct net_device *netdev,
-                                sa_family_t sa_family, __be16 port)
+                                struct udp_tunnel_info *ti)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
 
+       if (ti->type != UDP_TUNNEL_TYPE_VXLAN)
+               return;
+
        if (!mlx5e_vxlan_allowed(priv->mdev))
                return;
 
-       mlx5e_vxlan_queue_work(priv, sa_family, be16_to_cpu(port), 1);
+       mlx5e_vxlan_queue_work(priv, ti->sa_family, be16_to_cpu(ti->port), 1);
 }
 
 static void mlx5e_del_vxlan_port(struct net_device *netdev,
-                                sa_family_t sa_family, __be16 port)
+                                struct udp_tunnel_info *ti)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
 
+       if (ti->type != UDP_TUNNEL_TYPE_VXLAN)
+               return;
+
        if (!mlx5e_vxlan_allowed(priv->mdev))
                return;
 
-       mlx5e_vxlan_queue_work(priv, sa_family, be16_to_cpu(port), 0);
+       mlx5e_vxlan_queue_work(priv, ti->sa_family, be16_to_cpu(ti->port), 0);
 }
 
 static netdev_features_t mlx5e_vxlan_features_check(struct mlx5e_priv *priv,
@@ -2693,6 +2819,7 @@ static const struct net_device_ops mlx5e_netdev_ops_basic = {
        .ndo_set_features        = mlx5e_set_features,
        .ndo_change_mtu          = mlx5e_change_mtu,
        .ndo_do_ioctl            = mlx5e_ioctl,
+       .ndo_set_tx_maxrate      = mlx5e_set_tx_maxrate,
 #ifdef CONFIG_RFS_ACCEL
        .ndo_rx_flow_steer       = mlx5e_rx_flow_steer,
 #endif
@@ -2713,8 +2840,9 @@ static const struct net_device_ops mlx5e_netdev_ops_sriov = {
        .ndo_set_features        = mlx5e_set_features,
        .ndo_change_mtu          = mlx5e_change_mtu,
        .ndo_do_ioctl            = mlx5e_ioctl,
-       .ndo_add_vxlan_port      = mlx5e_add_vxlan_port,
-       .ndo_del_vxlan_port      = mlx5e_del_vxlan_port,
+       .ndo_udp_tunnel_add      = mlx5e_add_vxlan_port,
+       .ndo_udp_tunnel_del      = mlx5e_del_vxlan_port,
+       .ndo_set_tx_maxrate      = mlx5e_set_tx_maxrate,
        .ndo_features_check      = mlx5e_features_check,
 #ifdef CONFIG_RFS_ACCEL
        .ndo_rx_flow_steer       = mlx5e_rx_flow_steer,
@@ -2844,13 +2972,48 @@ static bool cqe_compress_heuristic(u32 link_speed, u32 pci_bw)
                (pci_bw < 40000) && (pci_bw < link_speed));
 }
 
-static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
-                                   struct net_device *netdev,
-                                   int num_channels)
+void mlx5e_set_rx_cq_mode_params(struct mlx5e_params *params, u8 cq_period_mode)
+{
+       params->rx_cq_period_mode = cq_period_mode;
+
+       params->rx_cq_moderation.pkts =
+               MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS;
+       params->rx_cq_moderation.usec =
+                       MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC;
+
+       if (cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE)
+               params->rx_cq_moderation.usec =
+                       MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC_FROM_CQE;
+}
+
+static void mlx5e_query_min_inline(struct mlx5_core_dev *mdev,
+                                  u8 *min_inline_mode)
+{
+       switch (MLX5_CAP_ETH(mdev, wqe_inline_mode)) {
+       case MLX5E_INLINE_MODE_L2:
+               *min_inline_mode = MLX5_INLINE_MODE_L2;
+               break;
+       case MLX5E_INLINE_MODE_VPORT_CONTEXT:
+               mlx5_query_nic_vport_min_inline(mdev,
+                                               min_inline_mode);
+               break;
+       case MLX5_INLINE_MODE_NOT_REQUIRED:
+               *min_inline_mode = MLX5_INLINE_MODE_NONE;
+               break;
+       }
+}
+
+static void mlx5e_build_nic_netdev_priv(struct mlx5_core_dev *mdev,
+                                       struct net_device *netdev,
+                                       const struct mlx5e_profile *profile,
+                                       void *ppriv)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        u32 link_speed = 0;
        u32 pci_bw = 0;
+       u8 cq_period_mode = MLX5_CAP_GEN(mdev, cq_period_start_from_cqe) ?
+                                        MLX5_CQ_PERIOD_MODE_START_FROM_CQE :
+                                        MLX5_CQ_PERIOD_MODE_START_FROM_EQE;
 
        priv->params.log_sq_size           =
                MLX5E_PARAMS_DEFAULT_LOG_SQ_SIZE;
@@ -2896,15 +3059,16 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
 
        priv->params.min_rx_wqes = mlx5_min_rx_wqes(priv->params.rq_wq_type,
                                            BIT(priv->params.log_rq_size));
-       priv->params.rx_cq_moderation_usec =
-               MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC;
-       priv->params.rx_cq_moderation_pkts =
-               MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS;
-       priv->params.tx_cq_moderation_usec =
+
+       priv->params.rx_am_enabled = MLX5_CAP_GEN(mdev, cq_moderation);
+       mlx5e_set_rx_cq_mode_params(&priv->params, cq_period_mode);
+
+       priv->params.tx_cq_moderation.usec =
                MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC;
-       priv->params.tx_cq_moderation_pkts =
+       priv->params.tx_cq_moderation.pkts =
                MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS;
        priv->params.tx_max_inline         = mlx5e_get_max_inline_cap(mdev);
+       mlx5e_query_min_inline(mdev, &priv->params.tx_min_inline_mode);
        priv->params.num_tc                = 1;
        priv->params.rss_hfunc             = ETH_RSS_HASH_XOR;
 
@@ -2912,14 +3076,20 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev,
                            sizeof(priv->params.toeplitz_hash_key));
 
        mlx5e_build_default_indir_rqt(mdev, priv->params.indirection_rqt,
-                                     MLX5E_INDIR_RQT_SIZE, num_channels);
+                                     MLX5E_INDIR_RQT_SIZE, profile->max_nch(mdev));
 
        priv->params.lro_wqe_sz            =
                MLX5E_PARAMS_DEFAULT_LRO_WQE_SZ;
 
+       /* Initialize pflags */
+       MLX5E_SET_PRIV_FLAG(priv, MLX5E_PFLAG_RX_CQE_BASED_MODER,
+                           priv->params.rx_cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE);
+
        priv->mdev                         = mdev;
        priv->netdev                       = netdev;
-       priv->params.num_channels          = num_channels;
+       priv->params.num_channels          = profile->max_nch(mdev);
+       priv->profile                      = profile;
+       priv->ppriv                        = ppriv;
 
 #ifdef CONFIG_MLX5_CORE_EN_DCB
        mlx5e_ets_init(priv);
@@ -2945,7 +3115,11 @@ static void mlx5e_set_netdev_dev_addr(struct net_device *netdev)
        }
 }
 
-static void mlx5e_build_netdev(struct net_device *netdev)
+static const struct switchdev_ops mlx5e_switchdev_ops = {
+       .switchdev_port_attr_get        = mlx5e_attr_get,
+};
+
+static void mlx5e_build_nic_netdev(struct net_device *netdev)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        struct mlx5_core_dev *mdev = priv->mdev;
@@ -3026,31 +3200,11 @@ static void mlx5e_build_netdev(struct net_device *netdev)
        netdev->priv_flags       |= IFF_UNICAST_FLT;
 
        mlx5e_set_netdev_dev_addr(netdev);
-}
-
-static int mlx5e_create_mkey(struct mlx5e_priv *priv, u32 pdn,
-                            struct mlx5_core_mkey *mkey)
-{
-       struct mlx5_core_dev *mdev = priv->mdev;
-       struct mlx5_create_mkey_mbox_in *in;
-       int err;
-
-       in = mlx5_vzalloc(sizeof(*in));
-       if (!in)
-               return -ENOMEM;
-
-       in->seg.flags = MLX5_PERM_LOCAL_WRITE |
-                       MLX5_PERM_LOCAL_READ  |
-                       MLX5_ACCESS_MODE_PA;
-       in->seg.flags_pd = cpu_to_be32(pdn | MLX5_MKEY_LEN64);
-       in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
-
-       err = mlx5_core_create_mkey(mdev, mkey, in, sizeof(*in), NULL, NULL,
-                                   NULL);
-
-       kvfree(in);
 
-       return err;
+#ifdef CONFIG_NET_SWITCHDEV
+       if (MLX5_CAP_GEN(mdev, vport_group_manager))
+               netdev->switchdev_ops = &mlx5e_switchdev_ops;
+#endif
 }
 
 static void mlx5e_create_q_counter(struct mlx5e_priv *priv)
@@ -3080,7 +3234,7 @@ static int mlx5e_create_umr_mkey(struct mlx5e_priv *priv)
        struct mlx5_mkey_seg *mkc;
        int inlen = sizeof(*in);
        u64 npages =
-               mlx5e_get_max_num_channels(mdev) * MLX5_CHANNEL_MAX_NUM_MTTS;
+               priv->profile->max_nch(mdev) * MLX5_CHANNEL_MAX_NUM_MTTS;
        int err;
 
        in = mlx5_vzalloc(inlen);
@@ -3095,7 +3249,7 @@ static int mlx5e_create_umr_mkey(struct mlx5e_priv *priv)
                     MLX5_ACCESS_MODE_MTT;
 
        mkc->qpn_mkey7_0 = cpu_to_be32(0xffffff << 8);
-       mkc->flags_pd = cpu_to_be32(priv->pdn);
+       mkc->flags_pd = cpu_to_be32(mdev->mlx5e_res.pdn);
        mkc->len = cpu_to_be64(npages << PAGE_SHIFT);
        mkc->xlt_oct_size = cpu_to_be32(mlx5e_get_mtt_octw(npages));
        mkc->log2_page_size = PAGE_SHIFT;
@@ -3108,160 +3262,235 @@ static int mlx5e_create_umr_mkey(struct mlx5e_priv *priv)
        return err;
 }
 
-static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
+static void mlx5e_nic_init(struct mlx5_core_dev *mdev,
+                          struct net_device *netdev,
+                          const struct mlx5e_profile *profile,
+                          void *ppriv)
 {
-       struct net_device *netdev;
-       struct mlx5e_priv *priv;
-       int nch = mlx5e_get_max_num_channels(mdev);
-       int err;
-
-       if (mlx5e_check_required_hca_cap(mdev))
-               return NULL;
+       struct mlx5e_priv *priv = netdev_priv(netdev);
 
-       netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv),
-                                   nch * MLX5E_MAX_NUM_TC,
-                                   nch);
-       if (!netdev) {
-               mlx5_core_err(mdev, "alloc_etherdev_mqs() failed\n");
-               return NULL;
-       }
+       mlx5e_build_nic_netdev_priv(mdev, netdev, profile, ppriv);
+       mlx5e_build_nic_netdev(netdev);
+       mlx5e_vxlan_init(priv);
+}
 
-       mlx5e_build_netdev_priv(mdev, netdev, nch);
-       mlx5e_build_netdev(netdev);
+static void mlx5e_nic_cleanup(struct mlx5e_priv *priv)
+{
+       struct mlx5_core_dev *mdev = priv->mdev;
+       struct mlx5_eswitch *esw = mdev->priv.eswitch;
 
-       netif_carrier_off(netdev);
+       mlx5e_vxlan_cleanup(priv);
 
-       priv = netdev_priv(netdev);
+       if (MLX5_CAP_GEN(mdev, vport_group_manager))
+               mlx5_eswitch_unregister_vport_rep(esw, 0);
+}
 
-       priv->wq = create_singlethread_workqueue("mlx5e");
-       if (!priv->wq)
-               goto err_free_netdev;
+static int mlx5e_init_nic_rx(struct mlx5e_priv *priv)
+{
+       struct mlx5_core_dev *mdev = priv->mdev;
+       int err;
+       int i;
 
-       err = mlx5_alloc_map_uar(mdev, &priv->cq_uar, false);
+       err = mlx5e_create_indirect_rqts(priv);
        if (err) {
-               mlx5_core_err(mdev, "alloc_map uar failed, %d\n", err);
-               goto err_destroy_wq;
+               mlx5_core_warn(mdev, "create indirect rqts failed, %d\n", err);
+               return err;
        }
 
-       err = mlx5_core_alloc_pd(mdev, &priv->pdn);
+       err = mlx5e_create_direct_rqts(priv);
        if (err) {
-               mlx5_core_err(mdev, "alloc pd failed, %d\n", err);
-               goto err_unmap_free_uar;
+               mlx5_core_warn(mdev, "create direct rqts failed, %d\n", err);
+               goto err_destroy_indirect_rqts;
        }
 
-       err = mlx5_core_alloc_transport_domain(mdev, &priv->tdn);
+       err = mlx5e_create_indirect_tirs(priv);
        if (err) {
-               mlx5_core_err(mdev, "alloc td failed, %d\n", err);
-               goto err_dealloc_pd;
+               mlx5_core_warn(mdev, "create indirect tirs failed, %d\n", err);
+               goto err_destroy_direct_rqts;
        }
 
-       err = mlx5e_create_mkey(priv, priv->pdn, &priv->mkey);
+       err = mlx5e_create_direct_tirs(priv);
        if (err) {
-               mlx5_core_err(mdev, "create mkey failed, %d\n", err);
-               goto err_dealloc_transport_domain;
+               mlx5_core_warn(mdev, "create direct tirs failed, %d\n", err);
+               goto err_destroy_indirect_tirs;
        }
 
-       err = mlx5e_create_umr_mkey(priv);
+       err = mlx5e_create_flow_steering(priv);
        if (err) {
-               mlx5_core_err(mdev, "create umr mkey failed, %d\n", err);
-               goto err_destroy_mkey;
+               mlx5_core_warn(mdev, "create flow steering failed, %d\n", err);
+               goto err_destroy_direct_tirs;
        }
 
+       err = mlx5e_tc_init(priv);
+       if (err)
+               goto err_destroy_flow_steering;
+
+       return 0;
+
+err_destroy_flow_steering:
+       mlx5e_destroy_flow_steering(priv);
+err_destroy_direct_tirs:
+       mlx5e_destroy_direct_tirs(priv);
+err_destroy_indirect_tirs:
+       mlx5e_destroy_indirect_tirs(priv);
+err_destroy_direct_rqts:
+       for (i = 0; i < priv->profile->max_nch(mdev); i++)
+               mlx5e_destroy_rqt(priv, &priv->direct_tir[i].rqt);
+err_destroy_indirect_rqts:
+       mlx5e_destroy_rqt(priv, &priv->indir_rqt);
+       return err;
+}
+
+static void mlx5e_cleanup_nic_rx(struct mlx5e_priv *priv)
+{
+       int i;
+
+       mlx5e_tc_cleanup(priv);
+       mlx5e_destroy_flow_steering(priv);
+       mlx5e_destroy_direct_tirs(priv);
+       mlx5e_destroy_indirect_tirs(priv);
+       for (i = 0; i < priv->profile->max_nch(priv->mdev); i++)
+               mlx5e_destroy_rqt(priv, &priv->direct_tir[i].rqt);
+       mlx5e_destroy_rqt(priv, &priv->indir_rqt);
+}
+
+static int mlx5e_init_nic_tx(struct mlx5e_priv *priv)
+{
+       int err;
+
        err = mlx5e_create_tises(priv);
        if (err) {
-               mlx5_core_warn(mdev, "create tises failed, %d\n", err);
-               goto err_destroy_umr_mkey;
+               mlx5_core_warn(priv->mdev, "create tises failed, %d\n", err);
+               return err;
        }
 
-       err = mlx5e_open_drop_rq(priv);
-       if (err) {
-               mlx5_core_err(mdev, "open drop rq failed, %d\n", err);
-               goto err_destroy_tises;
+#ifdef CONFIG_MLX5_CORE_EN_DCB
+       mlx5e_dcbnl_ieee_setets_core(priv, &priv->params.ets);
+#endif
+       return 0;
+}
+
+static void mlx5e_nic_enable(struct mlx5e_priv *priv)
+{
+       struct net_device *netdev = priv->netdev;
+       struct mlx5_core_dev *mdev = priv->mdev;
+       struct mlx5_eswitch *esw = mdev->priv.eswitch;
+       struct mlx5_eswitch_rep rep;
+
+       if (mlx5e_vxlan_allowed(mdev)) {
+               rtnl_lock();
+               udp_tunnel_get_rx_info(netdev);
+               rtnl_unlock();
        }
 
-       err = mlx5e_create_rqts(priv);
-       if (err) {
-               mlx5_core_warn(mdev, "create rqts failed, %d\n", err);
-               goto err_close_drop_rq;
+       mlx5e_enable_async_events(priv);
+       queue_work(priv->wq, &priv->set_rx_mode_work);
+
+       if (MLX5_CAP_GEN(mdev, vport_group_manager)) {
+               rep.load = mlx5e_nic_rep_load;
+               rep.unload = mlx5e_nic_rep_unload;
+               rep.vport = 0;
+               rep.priv_data = priv;
+               mlx5_eswitch_register_vport_rep(esw, &rep);
+       }
+}
+
+static void mlx5e_nic_disable(struct mlx5e_priv *priv)
+{
+       queue_work(priv->wq, &priv->set_rx_mode_work);
+       mlx5e_disable_async_events(priv);
+}
+
+static const struct mlx5e_profile mlx5e_nic_profile = {
+       .init              = mlx5e_nic_init,
+       .cleanup           = mlx5e_nic_cleanup,
+       .init_rx           = mlx5e_init_nic_rx,
+       .cleanup_rx        = mlx5e_cleanup_nic_rx,
+       .init_tx           = mlx5e_init_nic_tx,
+       .cleanup_tx        = mlx5e_cleanup_nic_tx,
+       .enable            = mlx5e_nic_enable,
+       .disable           = mlx5e_nic_disable,
+       .update_stats      = mlx5e_update_stats,
+       .max_nch           = mlx5e_get_max_num_channels,
+       .max_tc            = MLX5E_MAX_NUM_TC,
+};
+
+void *mlx5e_create_netdev(struct mlx5_core_dev *mdev,
+                         const struct mlx5e_profile *profile, void *ppriv)
+{
+       struct net_device *netdev;
+       struct mlx5e_priv *priv;
+       int nch = profile->max_nch(mdev);
+       int err;
+
+       netdev = alloc_etherdev_mqs(sizeof(struct mlx5e_priv),
+                                   nch * profile->max_tc,
+                                   nch);
+       if (!netdev) {
+               mlx5_core_err(mdev, "alloc_etherdev_mqs() failed\n");
+               return NULL;
        }
 
-       err = mlx5e_create_tirs(priv);
+       profile->init(mdev, netdev, profile, ppriv);
+
+       netif_carrier_off(netdev);
+
+       priv = netdev_priv(netdev);
+
+       priv->wq = create_singlethread_workqueue("mlx5e");
+       if (!priv->wq)
+               goto err_free_netdev;
+
+       err = mlx5e_create_umr_mkey(priv);
        if (err) {
-               mlx5_core_warn(mdev, "create tirs failed, %d\n", err);
-               goto err_destroy_rqts;
+               mlx5_core_err(mdev, "create umr mkey failed, %d\n", err);
+               goto err_destroy_wq;
        }
 
-       err = mlx5e_create_flow_steering(priv);
+       err = profile->init_tx(priv);
+       if (err)
+               goto err_destroy_umr_mkey;
+
+       err = mlx5e_open_drop_rq(priv);
        if (err) {
-               mlx5_core_warn(mdev, "create flow steering failed, %d\n", err);
-               goto err_destroy_tirs;
+               mlx5_core_err(mdev, "open drop rq failed, %d\n", err);
+               goto err_cleanup_tx;
        }
 
+       err = profile->init_rx(priv);
+       if (err)
+               goto err_close_drop_rq;
+
        mlx5e_create_q_counter(priv);
 
        mlx5e_init_l2_addr(priv);
 
-       mlx5e_vxlan_init(priv);
-
-       err = mlx5e_tc_init(priv);
-       if (err)
-               goto err_dealloc_q_counters;
-
-#ifdef CONFIG_MLX5_CORE_EN_DCB
-       mlx5e_dcbnl_ieee_setets_core(priv, &priv->params.ets);
-#endif
+       mlx5e_set_dev_port_mtu(netdev);
 
        err = register_netdev(netdev);
        if (err) {
                mlx5_core_err(mdev, "register_netdev failed, %d\n", err);
-               goto err_tc_cleanup;
-       }
-
-       if (mlx5e_vxlan_allowed(mdev)) {
-               rtnl_lock();
-               vxlan_get_rx_port(netdev);
-               rtnl_unlock();
+               goto err_dealloc_q_counters;
        }
 
-       mlx5e_enable_async_events(priv);
-       queue_work(priv->wq, &priv->set_rx_mode_work);
+       if (profile->enable)
+               profile->enable(priv);
 
        return priv;
 
-err_tc_cleanup:
-       mlx5e_tc_cleanup(priv);
-
 err_dealloc_q_counters:
        mlx5e_destroy_q_counter(priv);
-       mlx5e_destroy_flow_steering(priv);
-
-err_destroy_tirs:
-       mlx5e_destroy_tirs(priv);
-
-err_destroy_rqts:
-       mlx5e_destroy_rqts(priv);
+       profile->cleanup_rx(priv);
 
 err_close_drop_rq:
        mlx5e_close_drop_rq(priv);
 
-err_destroy_tises:
-       mlx5e_destroy_tises(priv);
+err_cleanup_tx:
+       profile->cleanup_tx(priv);
 
 err_destroy_umr_mkey:
        mlx5_core_destroy_mkey(mdev, &priv->umr_mkey);
 
-err_destroy_mkey:
-       mlx5_core_destroy_mkey(mdev, &priv->mkey);
-
-err_dealloc_transport_domain:
-       mlx5_core_dealloc_transport_domain(mdev, priv->tdn);
-
-err_dealloc_pd:
-       mlx5_core_dealloc_pd(mdev, priv->pdn);
-
-err_unmap_free_uar:
-       mlx5_unmap_free_uar(mdev, &priv->cq_uar);
-
 err_destroy_wq:
        destroy_workqueue(priv->wq);
 
@@ -3271,15 +3500,59 @@ err_free_netdev:
        return NULL;
 }
 
-static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv)
+static void mlx5e_register_vport_rep(struct mlx5_core_dev *mdev)
 {
-       struct mlx5e_priv *priv = vpriv;
+       struct mlx5_eswitch *esw = mdev->priv.eswitch;
+       int total_vfs = MLX5_TOTAL_VPORTS(mdev);
+       int vport;
+
+       if (!MLX5_CAP_GEN(mdev, vport_group_manager))
+               return;
+
+       for (vport = 1; vport < total_vfs; vport++) {
+               struct mlx5_eswitch_rep rep;
+
+               rep.load = mlx5e_vport_rep_load;
+               rep.unload = mlx5e_vport_rep_unload;
+               rep.vport = vport;
+               mlx5_eswitch_register_vport_rep(esw, &rep);
+       }
+}
+
+static void *mlx5e_add(struct mlx5_core_dev *mdev)
+{
+       struct mlx5_eswitch *esw = mdev->priv.eswitch;
+       void *ppriv = NULL;
+       void *ret;
+
+       if (mlx5e_check_required_hca_cap(mdev))
+               return NULL;
+
+       if (mlx5e_create_mdev_resources(mdev))
+               return NULL;
+
+       mlx5e_register_vport_rep(mdev);
+
+       if (MLX5_CAP_GEN(mdev, vport_group_manager))
+               ppriv = &esw->offloads.vport_reps[0];
+
+       ret = mlx5e_create_netdev(mdev, &mlx5e_nic_profile, ppriv);
+       if (!ret) {
+               mlx5e_destroy_mdev_resources(mdev);
+               return NULL;
+       }
+       return ret;
+}
+
+void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, struct mlx5e_priv *priv)
+{
+       const struct mlx5e_profile *profile = priv->profile;
        struct net_device *netdev = priv->netdev;
 
        set_bit(MLX5E_STATE_DESTROYING, &priv->state);
+       if (profile->disable)
+               profile->disable(priv);
 
-       queue_work(priv->wq, &priv->set_rx_mode_work);
-       mlx5e_disable_async_events(priv);
        flush_workqueue(priv->wq);
        if (test_bit(MLX5_INTERFACE_STATE_SHUTDOWN, &mdev->intf_state)) {
                netif_device_detach(netdev);
@@ -3288,26 +3561,35 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv)
                unregister_netdev(netdev);
        }
 
-       mlx5e_tc_cleanup(priv);
-       mlx5e_vxlan_cleanup(priv);
        mlx5e_destroy_q_counter(priv);
-       mlx5e_destroy_flow_steering(priv);
-       mlx5e_destroy_tirs(priv);
-       mlx5e_destroy_rqts(priv);
+       profile->cleanup_rx(priv);
        mlx5e_close_drop_rq(priv);
-       mlx5e_destroy_tises(priv);
+       profile->cleanup_tx(priv);
        mlx5_core_destroy_mkey(priv->mdev, &priv->umr_mkey);
-       mlx5_core_destroy_mkey(priv->mdev, &priv->mkey);
-       mlx5_core_dealloc_transport_domain(priv->mdev, priv->tdn);
-       mlx5_core_dealloc_pd(priv->mdev, priv->pdn);
-       mlx5_unmap_free_uar(priv->mdev, &priv->cq_uar);
        cancel_delayed_work_sync(&priv->update_stats_work);
        destroy_workqueue(priv->wq);
+       if (profile->cleanup)
+               profile->cleanup(priv);
 
        if (!test_bit(MLX5_INTERFACE_STATE_SHUTDOWN, &mdev->intf_state))
                free_netdev(netdev);
 }
 
+static void mlx5e_remove(struct mlx5_core_dev *mdev, void *vpriv)
+{
+       struct mlx5_eswitch *esw = mdev->priv.eswitch;
+       int total_vfs = MLX5_TOTAL_VPORTS(mdev);
+       struct mlx5e_priv *priv = vpriv;
+       int vport;
+
+       mlx5e_destroy_netdev(mdev, priv);
+
+       for (vport = 1; vport < total_vfs; vport++)
+               mlx5_eswitch_unregister_vport_rep(esw, vport);
+
+       mlx5e_destroy_mdev_resources(mdev);
+}
+
 static void *mlx5e_get_netdev(void *vpriv)
 {
        struct mlx5e_priv *priv = vpriv;
@@ -3316,8 +3598,8 @@ static void *mlx5e_get_netdev(void *vpriv)
 }
 
 static struct mlx5_interface mlx5e_interface = {
-       .add       = mlx5e_create_netdev,
-       .remove    = mlx5e_destroy_netdev,
+       .add       = mlx5e_add,
+       .remove    = mlx5e_remove,
        .event     = mlx5e_async_event,
        .protocol  = MLX5_INTERFACE_PROTOCOL_ETH,
        .get_dev   = mlx5e_get_netdev,
@@ -3325,6 +3607,7 @@ static struct mlx5_interface mlx5e_interface = {
 
 void mlx5e_init(void)
 {
+       mlx5e_build_ptys2ethtool_map();
        mlx5_register_interface(&mlx5e_interface);
 }