int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv,
                               struct ethtool_channels *ch);
 int mlx5e_ethtool_get_coalesce(struct mlx5e_priv *priv,
-                              struct ethtool_coalesce *coal);
+                              struct ethtool_coalesce *coal,
+                              struct kernel_ethtool_coalesce *kernel_coal);
 int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
-                              struct ethtool_coalesce *coal);
+                              struct ethtool_coalesce *coal,
+                              struct kernel_ethtool_coalesce *kernel_coal,
+                              struct netlink_ext_ack *extack);
 int mlx5e_ethtool_get_link_ksettings(struct mlx5e_priv *priv,
                                     struct ethtool_link_ksettings *link_ksettings);
 int mlx5e_ethtool_set_link_ksettings(struct mlx5e_priv *priv,
 
 }
 
 int mlx5e_ethtool_get_coalesce(struct mlx5e_priv *priv,
-                              struct ethtool_coalesce *coal)
+                              struct ethtool_coalesce *coal,
+                              struct kernel_ethtool_coalesce *kernel_coal)
 {
        struct dim_cq_moder *rx_moder, *tx_moder;
 
        coal->tx_max_coalesced_frames   = tx_moder->pkts;
        coal->use_adaptive_tx_coalesce  = priv->channels.params.tx_dim_enabled;
 
+       kernel_coal->use_cqe_mode_rx =
+               MLX5E_GET_PFLAG(&priv->channels.params, MLX5E_PFLAG_RX_CQE_BASED_MODER);
+       kernel_coal->use_cqe_mode_tx =
+               MLX5E_GET_PFLAG(&priv->channels.params, MLX5E_PFLAG_TX_CQE_BASED_MODER);
+
        return 0;
 }
 
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
 
-       return mlx5e_ethtool_get_coalesce(priv, coal);
+       return mlx5e_ethtool_get_coalesce(priv, coal, kernel_coal);
 }
 
 #define MLX5E_MAX_COAL_TIME            MLX5_MAX_CQ_PERIOD
        }
 }
 
+/* convert a boolean value of cq_mode to mlx5 period mode
+ * true  : MLX5_CQ_PERIOD_MODE_START_FROM_CQE
+ * false : MLX5_CQ_PERIOD_MODE_START_FROM_EQE
+ */
+static int cqe_mode_to_period_mode(bool val)
+{
+       return val ? MLX5_CQ_PERIOD_MODE_START_FROM_CQE : MLX5_CQ_PERIOD_MODE_START_FROM_EQE;
+}
+
 int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
-                              struct ethtool_coalesce *coal)
+                              struct ethtool_coalesce *coal,
+                              struct kernel_ethtool_coalesce *kernel_coal,
+                              struct netlink_ext_ack *extack)
 {
        struct dim_cq_moder *rx_moder, *tx_moder;
        struct mlx5_core_dev *mdev = priv->mdev;
        struct mlx5e_params new_params;
        bool reset_rx, reset_tx;
        bool reset = true;
+       u8 cq_period_mode;
        int err = 0;
 
        if (!MLX5_CAP_GEN(mdev, cq_moderation))
                return -ERANGE;
        }
 
+       if ((kernel_coal->use_cqe_mode_rx || kernel_coal->use_cqe_mode_tx) &&
+           !MLX5_CAP_GEN(priv->mdev, cq_period_start_from_cqe)) {
+               NL_SET_ERR_MSG_MOD(extack, "cqe_mode_rx/tx is not supported on this device");
+               return -EOPNOTSUPP;
+       }
+
        mutex_lock(&priv->state_lock);
        new_params = priv->channels.params;
 
        reset_rx = !!coal->use_adaptive_rx_coalesce != priv->channels.params.rx_dim_enabled;
        reset_tx = !!coal->use_adaptive_tx_coalesce != priv->channels.params.tx_dim_enabled;
 
+       cq_period_mode = cqe_mode_to_period_mode(kernel_coal->use_cqe_mode_rx);
+       if (cq_period_mode != rx_moder->cq_period_mode) {
+               mlx5e_set_rx_cq_mode_params(&new_params, cq_period_mode);
+               reset_rx = true;
+       }
+
+       cq_period_mode = cqe_mode_to_period_mode(kernel_coal->use_cqe_mode_tx);
+       if (cq_period_mode != tx_moder->cq_period_mode) {
+               mlx5e_set_tx_cq_mode_params(&new_params, cq_period_mode);
+               reset_tx = true;
+       }
+
        if (reset_rx) {
                u8 mode = MLX5E_GET_PFLAG(&new_params,
                                          MLX5E_PFLAG_RX_CQE_BASED_MODER);
                              struct kernel_ethtool_coalesce *kernel_coal,
                              struct netlink_ext_ack *extack)
 {
-       struct mlx5e_priv *priv    = netdev_priv(netdev);
+       struct mlx5e_priv *priv = netdev_priv(netdev);
 
-       return mlx5e_ethtool_set_coalesce(priv, coal);
+       return mlx5e_ethtool_set_coalesce(priv, coal, kernel_coal, extack);
 }
 
 static void ptys2ethtool_supported_link(struct mlx5_core_dev *mdev,
 const struct ethtool_ops mlx5e_ethtool_ops = {
        .supported_coalesce_params = ETHTOOL_COALESCE_USECS |
                                     ETHTOOL_COALESCE_MAX_FRAMES |
-                                    ETHTOOL_COALESCE_USE_ADAPTIVE,
+                                    ETHTOOL_COALESCE_USE_ADAPTIVE |
+                                    ETHTOOL_COALESCE_USE_CQE,
        .get_drvinfo       = mlx5e_get_drvinfo,
        .get_link          = ethtool_op_get_link,
        .get_link_ext_state  = mlx5e_get_link_ext_state,