net/mlx5e: Support updating coalescing configuration without resetting channels
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlx5 / core / en_main.c
index 8b4ecae0fd9fff597c64bbddad85f3cda972a821..3bd0695845c7d0d597aca104f19773f506027a06 100644 (file)
@@ -962,20 +962,8 @@ static int mlx5e_alloc_rq(struct mlx5e_params *params,
                }
        }
 
-       rq->dim = kvzalloc_node(sizeof(*rq->dim), GFP_KERNEL, node);
-       if (!rq->dim) {
-               err = -ENOMEM;
-               goto err_unreg_xdp_rxq_info;
-       }
-
-       rq->dim->priv = rq;
-       INIT_WORK(&rq->dim->work, mlx5e_rx_dim_work);
-       rq->dim->mode = params->rx_cq_moderation.cq_period_mode;
-
        return 0;
 
-err_unreg_xdp_rxq_info:
-       xdp_rxq_info_unreg(&rq->xdp_rxq);
 err_destroy_page_pool:
        page_pool_destroy(rq->page_pool);
 err_free_by_rq_type:
@@ -1304,8 +1292,21 @@ int mlx5e_open_rq(struct mlx5e_params *params, struct mlx5e_rq_param *param,
        if (MLX5_CAP_ETH(mdev, cqe_checksum_full))
                __set_bit(MLX5E_RQ_STATE_CSUM_FULL, &rq->state);
 
-       if (params->rx_dim_enabled)
-               __set_bit(MLX5E_RQ_STATE_DIM, &rq->state);
+       if (rq->channel && !params->rx_dim_enabled) {
+               rq->channel->rx_cq_moder = params->rx_cq_moderation;
+       } else if (rq->channel) {
+               u8 cq_period_mode;
+
+               cq_period_mode = params->rx_moder_use_cqe_mode ?
+                                        DIM_CQ_PERIOD_MODE_START_FROM_CQE :
+                                        DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+               mlx5e_reset_rx_moderation(&rq->channel->rx_cq_moder, cq_period_mode,
+                                         params->rx_dim_enabled);
+
+               err = mlx5e_dim_rx_change(rq, params->rx_dim_enabled);
+               if (err)
+                       goto err_destroy_rq;
+       }
 
        /* We disable csum_complete when XDP is enabled since
         * XDP programs might manipulate packets which will render
@@ -1351,7 +1352,8 @@ void mlx5e_deactivate_rq(struct mlx5e_rq *rq)
 
 void mlx5e_close_rq(struct mlx5e_rq *rq)
 {
-       cancel_work_sync(&rq->dim->work);
+       if (rq->dim)
+               cancel_work_sync(&rq->dim->work);
        cancel_work_sync(&rq->recover_work);
        mlx5e_destroy_rq(rq);
        mlx5e_free_rx_descs(rq);
@@ -1626,20 +1628,9 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
        err = mlx5e_alloc_txqsq_db(sq, cpu_to_node(c->cpu));
        if (err)
                goto err_sq_wq_destroy;
-       sq->dim = kvzalloc_node(sizeof(*sq->dim), GFP_KERNEL, cpu_to_node(c->cpu));
-       if (!sq->dim) {
-               err = -ENOMEM;
-               goto err_free_txqsq_db;
-       }
-
-       sq->dim->priv = sq;
-       INIT_WORK(&sq->dim->work, mlx5e_tx_dim_work);
-       sq->dim->mode = params->tx_cq_moderation.cq_period_mode;
 
        return 0;
 
-err_free_txqsq_db:
-       mlx5e_free_txqsq_db(sq);
 err_sq_wq_destroy:
        mlx5_wq_destroy(&sq->wq_ctrl);
 
@@ -1804,11 +1795,27 @@ int mlx5e_open_txqsq(struct mlx5e_channel *c, u32 tisn, int txq_ix,
        if (tx_rate)
                mlx5e_set_sq_maxrate(c->netdev, sq, tx_rate);
 
-       if (params->tx_dim_enabled)
-               sq->state |= BIT(MLX5E_SQ_STATE_DIM);
+       if (sq->channel && !params->tx_dim_enabled) {
+               sq->channel->tx_cq_moder = params->tx_cq_moderation;
+       } else if (sq->channel) {
+               u8 cq_period_mode;
+
+               cq_period_mode = params->tx_moder_use_cqe_mode ?
+                                        DIM_CQ_PERIOD_MODE_START_FROM_CQE :
+                                        DIM_CQ_PERIOD_MODE_START_FROM_EQE;
+               mlx5e_reset_tx_moderation(&sq->channel->tx_cq_moder,
+                                         cq_period_mode,
+                                         params->tx_dim_enabled);
+
+               err = mlx5e_dim_tx_change(sq, params->tx_dim_enabled);
+               if (err)
+                       goto err_destroy_sq;
+       }
 
        return 0;
 
+err_destroy_sq:
+       mlx5e_destroy_sq(c->mdev, sq->sqn);
 err_free_txqsq:
        mlx5e_free_txqsq(sq);
 
@@ -1860,7 +1867,8 @@ void mlx5e_close_txqsq(struct mlx5e_txqsq *sq)
        struct mlx5_core_dev *mdev = sq->mdev;
        struct mlx5_rate_limit rl = {0};
 
-       cancel_work_sync(&sq->dim->work);
+       if (sq->dim)
+               cancel_work_sync(&sq->dim->work);
        cancel_work_sync(&sq->recover_work);
        mlx5e_destroy_sq(mdev, sq->sqn);
        if (sq->rate_limit) {
@@ -1879,6 +1887,49 @@ void mlx5e_tx_err_cqe_work(struct work_struct *recover_work)
        mlx5e_reporter_tx_err_cqe(sq);
 }
 
+static struct dim_cq_moder mlx5e_get_def_tx_moderation(u8 cq_period_mode)
+{
+       return (struct dim_cq_moder) {
+               .cq_period_mode = cq_period_mode,
+               .pkts = MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS,
+               .usec = cq_period_mode == DIM_CQ_PERIOD_MODE_START_FROM_CQE ?
+                               MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC_FROM_CQE :
+                               MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC,
+       };
+}
+
+bool mlx5e_reset_tx_moderation(struct dim_cq_moder *cq_moder, u8 cq_period_mode,
+                              bool dim_enabled)
+{
+       bool reset_needed = cq_moder->cq_period_mode != cq_period_mode;
+
+       if (dim_enabled)
+               *cq_moder = net_dim_get_def_tx_moderation(cq_period_mode);
+       else
+               *cq_moder = mlx5e_get_def_tx_moderation(cq_period_mode);
+
+       return reset_needed;
+}
+
+bool mlx5e_reset_tx_channels_moderation(struct mlx5e_channels *chs, u8 cq_period_mode,
+                                       bool dim_enabled, bool keep_dim_state)
+{
+       bool reset = false;
+       int i, tc;
+
+       for (i = 0; i < chs->num; i++) {
+               for (tc = 0; tc < mlx5e_get_dcb_num_tc(&chs->params); tc++) {
+                       if (keep_dim_state)
+                               dim_enabled = !!chs->c[i]->sq[tc].dim;
+
+                       reset |= mlx5e_reset_tx_moderation(&chs->c[i]->tx_cq_moder,
+                                                          cq_period_mode, dim_enabled);
+               }
+       }
+
+       return reset;
+}
+
 static int mlx5e_open_icosq(struct mlx5e_channel *c, struct mlx5e_params *params,
                            struct mlx5e_sq_param *param, struct mlx5e_icosq *sq,
                            work_func_t recover_work_func)
@@ -2102,7 +2153,8 @@ static int mlx5e_create_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
        mlx5_fill_page_frag_array(&cq->wq_ctrl.buf,
                                  (__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas));
 
-       MLX5_SET(cqc,   cqc, cq_period_mode, mlx5e_cq_period_mode(param->cq_period_mode));
+       MLX5_SET(cqc, cqc, cq_period_mode, mlx5e_cq_period_mode(param->cq_period_mode));
+
        MLX5_SET(cqc,   cqc, c_eqn_or_apu_element, eqn);
        MLX5_SET(cqc,   cqc, uar_page,      mdev->priv.uar->index);
        MLX5_SET(cqc,   cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
@@ -2140,8 +2192,10 @@ int mlx5e_open_cq(struct mlx5_core_dev *mdev, struct dim_cq_moder moder,
        if (err)
                goto err_free_cq;
 
-       if (MLX5_CAP_GEN(mdev, cq_moderation))
-               mlx5_core_modify_cq_moderation(mdev, &cq->mcq, moder.usec, moder.pkts);
+       if (MLX5_CAP_GEN(mdev, cq_moderation) &&
+           MLX5_CAP_GEN(mdev, cq_period_mode_modify))
+               mlx5e_modify_cq_moderation(mdev, &cq->mcq, moder.usec, moder.pkts,
+                                          mlx5e_cq_period_mode(moder.cq_period_mode));
        return 0;
 
 err_free_cq:
@@ -2156,6 +2210,40 @@ void mlx5e_close_cq(struct mlx5e_cq *cq)
        mlx5e_free_cq(cq);
 }
 
+int mlx5e_modify_cq_period_mode(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
+                               u8 cq_period_mode)
+{
+       u32 in[MLX5_ST_SZ_DW(modify_cq_in)] = {};
+       void *cqc;
+
+       MLX5_SET(modify_cq_in, in, cqn, cq->cqn);
+       cqc = MLX5_ADDR_OF(modify_cq_in, in, cq_context);
+       MLX5_SET(cqc, cqc, cq_period_mode, mlx5e_cq_period_mode(cq_period_mode));
+       MLX5_SET(modify_cq_in, in,
+                modify_field_select_resize_field_select.modify_field_select.modify_field_select,
+                MLX5_CQ_MODIFY_PERIOD_MODE);
+
+       return mlx5_core_modify_cq(dev, cq, in, sizeof(in));
+}
+
+int mlx5e_modify_cq_moderation(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
+                              u16 cq_period, u16 cq_max_count, u8 cq_period_mode)
+{
+       u32 in[MLX5_ST_SZ_DW(modify_cq_in)] = {};
+       void *cqc;
+
+       MLX5_SET(modify_cq_in, in, cqn, cq->cqn);
+       cqc = MLX5_ADDR_OF(modify_cq_in, in, cq_context);
+       MLX5_SET(cqc, cqc, cq_period, cq_period);
+       MLX5_SET(cqc, cqc, cq_max_count, cq_max_count);
+       MLX5_SET(cqc, cqc, cq_period_mode, cq_period_mode);
+       MLX5_SET(modify_cq_in, in,
+                modify_field_select_resize_field_select.modify_field_select.modify_field_select,
+                MLX5_CQ_MODIFY_PERIOD | MLX5_CQ_MODIFY_COUNT | MLX5_CQ_MODIFY_PERIOD_MODE);
+
+       return mlx5_core_modify_cq(dev, cq, in, sizeof(in));
+}
+
 static int mlx5e_open_tx_cqs(struct mlx5e_channel *c,
                             struct mlx5e_params *params,
                             struct mlx5e_create_cq_param *ccp,
@@ -3973,6 +4061,47 @@ static int set_feature_rx_all(struct net_device *netdev, bool enable)
        return mlx5_set_port_fcs(mdev, !enable);
 }
 
+static struct dim_cq_moder mlx5e_get_def_rx_moderation(u8 cq_period_mode)
+{
+       return (struct dim_cq_moder) {
+               .cq_period_mode = cq_period_mode,
+               .pkts = MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS,
+               .usec = cq_period_mode == DIM_CQ_PERIOD_MODE_START_FROM_CQE ?
+                               MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC_FROM_CQE :
+                               MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC,
+       };
+}
+
+bool mlx5e_reset_rx_moderation(struct dim_cq_moder *cq_moder, u8 cq_period_mode,
+                              bool dim_enabled)
+{
+       bool reset_needed = cq_moder->cq_period_mode != cq_period_mode;
+
+       if (dim_enabled)
+               *cq_moder = net_dim_get_def_rx_moderation(cq_period_mode);
+       else
+               *cq_moder = mlx5e_get_def_rx_moderation(cq_period_mode);
+
+       return reset_needed;
+}
+
+bool mlx5e_reset_rx_channels_moderation(struct mlx5e_channels *chs, u8 cq_period_mode,
+                                       bool dim_enabled, bool keep_dim_state)
+{
+       bool reset = false;
+       int i;
+
+       for (i = 0; i < chs->num; i++) {
+               if (keep_dim_state)
+                       dim_enabled = !!chs->c[i]->rq.dim;
+
+               reset |= mlx5e_reset_rx_moderation(&chs->c[i]->rx_cq_moder,
+                                                  cq_period_mode, dim_enabled);
+       }
+
+       return reset;
+}
+
 static int mlx5e_set_rx_port_ts(struct mlx5_core_dev *mdev, bool enable)
 {
        u32 in[MLX5_ST_SZ_DW(pcmr_reg)] = {};
@@ -5037,7 +5166,6 @@ void mlx5e_build_nic_params(struct mlx5e_priv *priv, struct mlx5e_xsk *xsk, u16
 {
        struct mlx5e_params *params = &priv->channels.params;
        struct mlx5_core_dev *mdev = priv->mdev;
-       u8 rx_cq_period_mode;
 
        params->sw_mtu = mtu;
        params->hard_mtu = MLX5E_ETH_HARD_MTU;
@@ -5071,12 +5199,16 @@ void mlx5e_build_nic_params(struct mlx5e_priv *priv, struct mlx5e_xsk *xsk, u16
        params->packet_merge.timeout = mlx5e_choose_lro_timeout(mdev, MLX5E_DEFAULT_LRO_TIMEOUT);
 
        /* CQ moderation params */
-       rx_cq_period_mode =
-               mlx5e_dim_cq_period_mode(MLX5_CAP_GEN(mdev, cq_period_start_from_cqe));
-       params->rx_dim_enabled = MLX5_CAP_GEN(mdev, cq_moderation);
-       params->tx_dim_enabled = MLX5_CAP_GEN(mdev, cq_moderation);
-       mlx5e_set_rx_cq_mode_params(params, rx_cq_period_mode);
-       mlx5e_set_tx_cq_mode_params(params, DIM_CQ_PERIOD_MODE_START_FROM_EQE);
+       params->rx_dim_enabled = MLX5_CAP_GEN(mdev, cq_moderation) &&
+                                MLX5_CAP_GEN(mdev, cq_period_mode_modify);
+       params->tx_dim_enabled = MLX5_CAP_GEN(mdev, cq_moderation) &&
+                                MLX5_CAP_GEN(mdev, cq_period_mode_modify);
+       params->rx_moder_use_cqe_mode = !!MLX5_CAP_GEN(mdev, cq_period_start_from_cqe);
+       params->tx_moder_use_cqe_mode = false;
+       mlx5e_reset_rx_moderation(&params->rx_cq_moderation, params->rx_moder_use_cqe_mode,
+                                 params->rx_dim_enabled);
+       mlx5e_reset_tx_moderation(&params->tx_cq_moderation, params->tx_moder_use_cqe_mode,
+                                 params->tx_dim_enabled);
 
        /* TX inline */
        mlx5_query_min_inline(mdev, &params->tx_min_inline_mode);