Commit f62a5e71 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'mlx5e-per-queue-coalescing'

Tariq Toukan says:

====================
mlx5e per-queue coalescing

This patchset adds ethtool per-queue coalescing support for the mlx5e
driver.

The series introduce some changes needed as preparations for the final
patch which adds the support and implements the callbacks.  Main
changes:
- DIM code movements into its own header file.
- Switch to dynamic allocation of the DIM struct in the RQs/SQs.
- Allow coalescing config change without channels reset when possible.
====================

Link: https://lore.kernel.org/r/20240419080445.417574-1-tariqt@nvidia.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents b240fc56 651ebaad
......@@ -320,6 +320,8 @@ struct mlx5e_params {
bool scatter_fcs_en;
bool rx_dim_enabled;
bool tx_dim_enabled;
bool rx_moder_use_cqe_mode;
bool tx_moder_use_cqe_mode;
u32 pflags;
struct bpf_prog *xdp_prog;
struct mlx5e_xsk *xsk;
......@@ -430,7 +432,7 @@ struct mlx5e_txqsq {
u16 cc;
u16 skb_fifo_cc;
u32 dma_fifo_cc;
struct dim dim; /* Adaptive Moderation */
struct dim *dim; /* Adaptive Moderation */
/* dirtied @xmit */
u16 pc ____cacheline_aligned_in_smp;
......@@ -722,7 +724,7 @@ struct mlx5e_rq {
int ix;
unsigned int hw_mtu;
struct dim dim; /* Dynamic Interrupt Moderation */
struct dim *dim; /* Dynamic Interrupt Moderation */
/* XDP */
struct bpf_prog __rcu *xdp_prog;
......@@ -797,6 +799,10 @@ struct mlx5e_channel {
int cpu;
/* Sync between icosq recovery and XSK enable/disable. */
struct mutex icosq_recovery_lock;
/* coalescing configuration */
struct dim_cq_moder rx_cq_moder;
struct dim_cq_moder tx_cq_moder;
};
struct mlx5e_ptp;
......@@ -1040,6 +1046,11 @@ void mlx5e_close_rq(struct mlx5e_rq *rq);
int mlx5e_create_rq(struct mlx5e_rq *rq, struct mlx5e_rq_param *param, u16 q_counter);
void mlx5e_destroy_rq(struct mlx5e_rq *rq);
bool mlx5e_reset_rx_moderation(struct dim_cq_moder *cq_moder, u8 cq_period_mode,
bool dim_enabled);
bool mlx5e_reset_rx_channels_moderation(struct mlx5e_channels *chs, u8 cq_period_mode,
bool dim_enabled, bool keep_dim_state);
struct mlx5e_sq_param;
int mlx5e_open_xdpsq(struct mlx5e_channel *c, struct mlx5e_params *params,
struct mlx5e_sq_param *param, struct xsk_buff_pool *xsk_pool,
......@@ -1060,6 +1071,10 @@ int mlx5e_open_cq(struct mlx5_core_dev *mdev, struct dim_cq_moder moder,
struct mlx5e_cq_param *param, struct mlx5e_create_cq_param *ccp,
struct mlx5e_cq *cq);
void mlx5e_close_cq(struct mlx5e_cq *cq);
int mlx5e_modify_cq_period_mode(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
u8 cq_period_mode);
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);
int mlx5e_open_locked(struct net_device *netdev);
int mlx5e_close_locked(struct net_device *netdev);
......@@ -1118,6 +1133,11 @@ int mlx5e_create_sq_rdy(struct mlx5_core_dev *mdev,
void mlx5e_tx_err_cqe_work(struct work_struct *recover_work);
void mlx5e_close_txqsq(struct mlx5e_txqsq *sq);
bool mlx5e_reset_tx_moderation(struct dim_cq_moder *cq_moder, u8 cq_period_mode,
bool dim_enabled);
bool mlx5e_reset_tx_channels_moderation(struct mlx5e_channels *chs, u8 cq_period_mode,
bool dim_enabled, bool keep_dim_state);
static inline bool mlx5_tx_swp_supported(struct mlx5_core_dev *mdev)
{
return MLX5_CAP_ETH(mdev, swp) &&
......@@ -1179,6 +1199,10 @@ int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
struct ethtool_coalesce *coal,
struct kernel_ethtool_coalesce *kernel_coal,
struct netlink_ext_ack *extack);
int mlx5e_get_per_queue_coalesce(struct net_device *dev, u32 queue,
struct ethtool_coalesce *coal);
int mlx5e_set_per_queue_coalesce(struct net_device *dev, u32 queue,
struct ethtool_coalesce *coal);
u32 mlx5e_ethtool_get_rxfh_key_size(struct mlx5e_priv *priv);
u32 mlx5e_ethtool_get_rxfh_indir_size(struct mlx5e_priv *priv);
int mlx5e_ethtool_get_ts_info(struct mlx5e_priv *priv,
......@@ -1210,8 +1234,6 @@ int mlx5e_netdev_change_profile(struct mlx5e_priv *priv,
void mlx5e_netdev_attach_nic_profile(struct mlx5e_priv *priv);
void mlx5e_set_netdev_mtu_boundaries(struct mlx5e_priv *priv);
void mlx5e_build_nic_params(struct mlx5e_priv *priv, struct mlx5e_xsk *xsk, u16 mtu);
void mlx5e_rx_dim_work(struct work_struct *work);
void mlx5e_tx_dim_work(struct work_struct *work);
void mlx5e_set_xdp_feature(struct net_device *netdev);
netdev_features_t mlx5e_features_check(struct sk_buff *skb,
......
......@@ -3,6 +3,7 @@
#include "channels.h"
#include "en.h"
#include "en/dim.h"
#include "en/ptp.h"
unsigned int mlx5e_channels_get_num(struct mlx5e_channels *chs)
......@@ -55,3 +56,85 @@ bool mlx5e_channels_get_ptp_rqn(struct mlx5e_channels *chs, u32 *rqn)
*rqn = c->rq.rqn;
return true;
}
int mlx5e_channels_rx_change_dim(struct mlx5e_channels *chs, bool enable)
{
int i;
for (i = 0; i < chs->num; i++) {
int err = mlx5e_dim_rx_change(&chs->c[i]->rq, enable);
if (err)
return err;
}
return 0;
}
int mlx5e_channels_tx_change_dim(struct mlx5e_channels *chs, bool enable)
{
int i, tc;
for (i = 0; i < chs->num; i++) {
for (tc = 0; tc < mlx5e_get_dcb_num_tc(&chs->params); tc++) {
int err = mlx5e_dim_tx_change(&chs->c[i]->sq[tc], enable);
if (err)
return err;
}
}
return 0;
}
int mlx5e_channels_rx_toggle_dim(struct mlx5e_channels *chs)
{
int i;
for (i = 0; i < chs->num; i++) {
/* If dim is enabled for the channel, reset the dim state so the
* collected statistics will be reset. This is useful for
* supporting legacy interfaces that allow things like changing
* the CQ period mode for all channels without disturbing
* individual channel configurations.
*/
if (chs->c[i]->rq.dim) {
int err;
mlx5e_dim_rx_change(&chs->c[i]->rq, false);
err = mlx5e_dim_rx_change(&chs->c[i]->rq, true);
if (err)
return err;
}
}
return 0;
}
int mlx5e_channels_tx_toggle_dim(struct mlx5e_channels *chs)
{
int i, tc;
for (i = 0; i < chs->num; i++) {
for (tc = 0; tc < mlx5e_get_dcb_num_tc(&chs->params); tc++) {
int err;
/* If dim is enabled for the channel, reset the dim
* state so the collected statistics will be reset. This
* is useful for supporting legacy interfaces that allow
* things like changing the CQ period mode for all
* channels without disturbing individual channel
* configurations.
*/
if (!chs->c[i]->sq[tc].dim)
continue;
mlx5e_dim_tx_change(&chs->c[i]->sq[tc], false);
err = mlx5e_dim_tx_change(&chs->c[i]->sq[tc], true);
if (err)
return err;
}
}
return 0;
}
......@@ -15,5 +15,9 @@ void mlx5e_channels_get_regular_rqn(struct mlx5e_channels *chs, unsigned int ix,
void mlx5e_channels_get_xsk_rqn(struct mlx5e_channels *chs, unsigned int ix, u32 *rqn,
u32 *vhca_id);
bool mlx5e_channels_get_ptp_rqn(struct mlx5e_channels *chs, u32 *rqn);
int mlx5e_channels_rx_change_dim(struct mlx5e_channels *chs, bool enabled);
int mlx5e_channels_tx_change_dim(struct mlx5e_channels *chs, bool enabled);
int mlx5e_channels_rx_toggle_dim(struct mlx5e_channels *chs);
int mlx5e_channels_tx_toggle_dim(struct mlx5e_channels *chs);
#endif /* __MLX5_EN_CHANNELS_H__ */
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved */
#ifndef __MLX5_EN_DIM_H__
#define __MLX5_EN_DIM_H__
#include <linux/dim.h>
#include <linux/types.h>
#include <linux/mlx5/mlx5_ifc.h>
/* Forward declarations */
struct mlx5e_rq;
struct mlx5e_txqsq;
struct work_struct;
/* convert a boolean value for cqe mode to appropriate dim constant
* true : DIM_CQ_PERIOD_MODE_START_FROM_CQE
* false : DIM_CQ_PERIOD_MODE_START_FROM_EQE
*/
static inline int mlx5e_dim_cq_period_mode(bool start_from_cqe)
{
return start_from_cqe ? DIM_CQ_PERIOD_MODE_START_FROM_CQE :
DIM_CQ_PERIOD_MODE_START_FROM_EQE;
}
static inline enum mlx5_cq_period_mode
mlx5e_cq_period_mode(enum dim_cq_period_mode cq_period_mode)
{
switch (cq_period_mode) {
case DIM_CQ_PERIOD_MODE_START_FROM_EQE:
return MLX5_CQ_PERIOD_MODE_START_FROM_EQE;
case DIM_CQ_PERIOD_MODE_START_FROM_CQE:
return MLX5_CQ_PERIOD_MODE_START_FROM_CQE;
default:
WARN_ON_ONCE(true);
return MLX5_CQ_PERIOD_MODE_START_FROM_EQE;
}
}
void mlx5e_rx_dim_work(struct work_struct *work);
void mlx5e_tx_dim_work(struct work_struct *work);
int mlx5e_dim_rx_change(struct mlx5e_rq *rq, bool enabled);
int mlx5e_dim_tx_change(struct mlx5e_txqsq *sq, bool enabled);
#endif /* __MLX5_EN_DIM_H__ */
......@@ -6,6 +6,7 @@
#include "en/port.h"
#include "en_accel/en_accel.h"
#include "en_accel/ipsec.h"
#include <linux/dim.h>
#include <net/page_pool/types.h>
#include <net/xdp_sock_drv.h>
......@@ -513,77 +514,6 @@ int mlx5e_validate_params(struct mlx5_core_dev *mdev, struct mlx5e_params *param
return 0;
}
static struct dim_cq_moder mlx5e_get_def_tx_moderation(u8 cq_period_mode)
{
struct dim_cq_moder moder = {};
moder.cq_period_mode = cq_period_mode;
moder.pkts = MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS;
moder.usec = MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC;
if (cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE)
moder.usec = MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC_FROM_CQE;
return moder;
}
static struct dim_cq_moder mlx5e_get_def_rx_moderation(u8 cq_period_mode)
{
struct dim_cq_moder moder = {};
moder.cq_period_mode = cq_period_mode;
moder.pkts = MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_PKTS;
moder.usec = MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC;
if (cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE)
moder.usec = MLX5E_PARAMS_DEFAULT_RX_CQ_MODERATION_USEC_FROM_CQE;
return moder;
}
static u8 mlx5_to_net_dim_cq_period_mode(u8 cq_period_mode)
{
return cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE ?
DIM_CQ_PERIOD_MODE_START_FROM_CQE :
DIM_CQ_PERIOD_MODE_START_FROM_EQE;
}
void mlx5e_reset_tx_moderation(struct mlx5e_params *params, u8 cq_period_mode)
{
if (params->tx_dim_enabled) {
u8 dim_period_mode = mlx5_to_net_dim_cq_period_mode(cq_period_mode);
params->tx_cq_moderation = net_dim_get_def_tx_moderation(dim_period_mode);
} else {
params->tx_cq_moderation = mlx5e_get_def_tx_moderation(cq_period_mode);
}
}
void mlx5e_reset_rx_moderation(struct mlx5e_params *params, u8 cq_period_mode)
{
if (params->rx_dim_enabled) {
u8 dim_period_mode = mlx5_to_net_dim_cq_period_mode(cq_period_mode);
params->rx_cq_moderation = net_dim_get_def_rx_moderation(dim_period_mode);
} else {
params->rx_cq_moderation = mlx5e_get_def_rx_moderation(cq_period_mode);
}
}
void mlx5e_set_tx_cq_mode_params(struct mlx5e_params *params, u8 cq_period_mode)
{
mlx5e_reset_tx_moderation(params, cq_period_mode);
MLX5E_SET_PFLAG(params, MLX5E_PFLAG_TX_CQE_BASED_MODER,
params->tx_cq_moderation.cq_period_mode ==
MLX5_CQ_PERIOD_MODE_START_FROM_CQE);
}
void mlx5e_set_rx_cq_mode_params(struct mlx5e_params *params, u8 cq_period_mode)
{
mlx5e_reset_rx_moderation(params, cq_period_mode);
MLX5E_SET_PFLAG(params, MLX5E_PFLAG_RX_CQE_BASED_MODER,
params->rx_cq_moderation.cq_period_mode ==
MLX5_CQ_PERIOD_MODE_START_FROM_CQE);
}
bool slow_pci_heuristic(struct mlx5_core_dev *mdev)
{
u32 link_speed = 0;
......
......@@ -77,11 +77,6 @@ u8 mlx5e_mpwrq_max_log_rq_pkts(struct mlx5_core_dev *mdev, u8 page_shift,
/* Parameter calculations */
void mlx5e_reset_tx_moderation(struct mlx5e_params *params, u8 cq_period_mode);
void mlx5e_reset_rx_moderation(struct mlx5e_params *params, u8 cq_period_mode);
void mlx5e_set_tx_cq_mode_params(struct mlx5e_params *params, u8 cq_period_mode);
void mlx5e_set_rx_cq_mode_params(struct mlx5e_params *params, u8 cq_period_mode);
bool slow_pci_heuristic(struct mlx5_core_dev *mdev);
int mlx5e_mpwrq_validate_regular(struct mlx5_core_dev *mdev, struct mlx5e_params *params);
int mlx5e_mpwrq_validate_xsk(struct mlx5_core_dev *mdev, struct mlx5e_params *params,
......
......@@ -30,21 +30,22 @@
* SOFTWARE.
*/
#include <linux/dim.h>
#include "en.h"
#include "en/dim.h"
static void
mlx5e_complete_dim_work(struct dim *dim, struct dim_cq_moder moder,
struct mlx5_core_dev *mdev, struct mlx5_core_cq *mcq)
{
mlx5_core_modify_cq_moderation(mdev, mcq, moder.usec, moder.pkts);
mlx5e_modify_cq_moderation(mdev, mcq, moder.usec, moder.pkts,
mlx5e_cq_period_mode(moder.cq_period_mode));
dim->state = DIM_START_MEASURE;
}
void mlx5e_rx_dim_work(struct work_struct *work)
{
struct dim *dim = container_of(work, struct dim, work);
struct mlx5e_rq *rq = container_of(dim, struct mlx5e_rq, dim);
struct mlx5e_rq *rq = dim->priv;
struct dim_cq_moder cur_moder =
net_dim_get_rx_moderation(dim->mode, dim->profile_ix);
......@@ -54,9 +55,95 @@ void mlx5e_rx_dim_work(struct work_struct *work)
void mlx5e_tx_dim_work(struct work_struct *work)
{
struct dim *dim = container_of(work, struct dim, work);
struct mlx5e_txqsq *sq = container_of(dim, struct mlx5e_txqsq, dim);
struct mlx5e_txqsq *sq = dim->priv;
struct dim_cq_moder cur_moder =
net_dim_get_tx_moderation(dim->mode, dim->profile_ix);
mlx5e_complete_dim_work(dim, cur_moder, sq->cq.mdev, &sq->cq.mcq);
}
static struct dim *mlx5e_dim_enable(struct mlx5_core_dev *mdev,
void (*work_fun)(struct work_struct *), int cpu,
u8 cq_period_mode, struct mlx5_core_cq *mcq,
void *queue)
{
struct dim *dim;
int err;
dim = kvzalloc_node(sizeof(*dim), GFP_KERNEL, cpu_to_node(cpu));
if (!dim)
return ERR_PTR(-ENOMEM);
INIT_WORK(&dim->work, work_fun);
dim->mode = cq_period_mode;
dim->priv = queue;
err = mlx5e_modify_cq_period_mode(mdev, mcq, dim->mode);
if (err) {
kvfree(dim);
return ERR_PTR(err);
}
return dim;
}
static void mlx5e_dim_disable(struct dim *dim)
{
cancel_work_sync(&dim->work);
kvfree(dim);
}
int mlx5e_dim_rx_change(struct mlx5e_rq *rq, bool enable)
{
if (enable == !!rq->dim)
return 0;
if (enable) {
struct mlx5e_channel *c = rq->channel;
struct dim *dim;
dim = mlx5e_dim_enable(rq->mdev, mlx5e_rx_dim_work, c->cpu,
c->rx_cq_moder.cq_period_mode, &rq->cq.mcq, rq);
if (IS_ERR(dim))
return PTR_ERR(dim);
rq->dim = dim;
__set_bit(MLX5E_RQ_STATE_DIM, &rq->state);
} else {
__clear_bit(MLX5E_RQ_STATE_DIM, &rq->state);
mlx5e_dim_disable(rq->dim);
rq->dim = NULL;
}
return 0;
}
int mlx5e_dim_tx_change(struct mlx5e_txqsq *sq, bool enable)
{
if (enable == !!sq->dim)
return 0;
if (enable) {
struct mlx5e_channel *c = sq->channel;
struct dim *dim;
dim = mlx5e_dim_enable(sq->mdev, mlx5e_tx_dim_work, c->cpu,
c->tx_cq_moder.cq_period_mode, &sq->cq.mcq, sq);
if (IS_ERR(dim))
return PTR_ERR(dim);
sq->dim = dim;
__set_bit(MLX5E_SQ_STATE_DIM, &sq->state);
} else {
__clear_bit(MLX5E_SQ_STATE_DIM, &sq->state);
mlx5e_dim_disable(sq->dim);
sq->dim = NULL;
}
return 0;
}
......@@ -30,6 +30,7 @@
* SOFTWARE.
*/
#include <linux/dim.h>
#include <linux/debugfs.h>
#include <linux/mlx5/fs.h>
#include <net/switchdev.h>
......@@ -40,6 +41,7 @@
#include "eswitch.h"
#include "en.h"
#include "en/dim.h"
#include "en_rep.h"
#include "en/params.h"
#include "en/txrx.h"
......@@ -426,6 +428,8 @@ static const struct ethtool_ops mlx5e_rep_ethtool_ops = {
.set_channels = mlx5e_rep_set_channels,
.get_coalesce = mlx5e_rep_get_coalesce,
.set_coalesce = mlx5e_rep_set_coalesce,
.get_per_queue_coalesce = mlx5e_get_per_queue_coalesce,
.set_per_queue_coalesce = mlx5e_set_per_queue_coalesce,
.get_rxfh_key_size = mlx5e_rep_get_rxfh_key_size,
.get_rxfh_indir_size = mlx5e_rep_get_rxfh_indir_size,
};
......@@ -836,10 +840,6 @@ static void mlx5e_build_rep_params(struct net_device *netdev)
struct mlx5_core_dev *mdev = priv->mdev;
struct mlx5e_params *params;
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;
params = &priv->channels.params;
params->num_channels = MLX5E_REP_PARAMS_DEF_NUM_CHANNELS;
......@@ -867,7 +867,7 @@ static void mlx5e_build_rep_params(struct net_device *netdev)
/* CQ moderation params */
params->rx_dim_enabled = MLX5_CAP_GEN(mdev, cq_moderation);
mlx5e_set_rx_cq_mode_params(params, cq_period_mode);
params->rx_moder_use_cqe_mode = !!MLX5_CAP_GEN(mdev, cq_period_start_from_cqe);
params->mqprio.num_tc = 1;
if (rep->vport != MLX5_VPORT_UPLINK)
......
......@@ -55,7 +55,7 @@ static void mlx5e_handle_tx_dim(struct mlx5e_txqsq *sq)
return;
dim_update_sample(sq->cq.event_ctr, stats->packets, stats->bytes, &dim_sample);
net_dim(&sq->dim, dim_sample);
net_dim(sq->dim, dim_sample);
}
static void mlx5e_handle_rx_dim(struct mlx5e_rq *rq)
......@@ -67,7 +67,7 @@ static void mlx5e_handle_rx_dim(struct mlx5e_rq *rq)
return;
dim_update_sample(rq->cq.event_ctr, stats->packets, stats->bytes, &dim_sample);
net_dim(&rq->dim, dim_sample);
net_dim(rq->dim, dim_sample);
}
void mlx5e_trigger_irq(struct mlx5e_icosq *sq)
......
......@@ -95,9 +95,10 @@ enum {
};
enum {
MLX5_CQ_MODIFY_PERIOD = 1 << 0,
MLX5_CQ_MODIFY_COUNT = 1 << 1,
MLX5_CQ_MODIFY_OVERRUN = 1 << 2,
MLX5_CQ_MODIFY_PERIOD = BIT(0),
MLX5_CQ_MODIFY_COUNT = BIT(1),
MLX5_CQ_MODIFY_OVERRUN = BIT(2),
MLX5_CQ_MODIFY_PERIOD_MODE = BIT(4),
};
enum {
......
......@@ -1686,7 +1686,8 @@ struct mlx5_ifc_cmd_hca_cap_bits {
u8 cq_oi[0x1];
u8 cq_resize[0x1];
u8 cq_moderation[0x1];
u8 reserved_at_223[0x3];
u8 cq_period_mode_modify[0x1];
u8 reserved_at_224[0x2];
u8 cq_eq_remap[0x1];
u8 pg[0x1];
u8 block_lb_mc[0x1];
......@@ -4385,10 +4386,10 @@ enum {
MLX5_CQC_ST_FIRED = 0xa,
};
enum {
enum mlx5_cq_period_mode {
MLX5_CQ_PERIOD_MODE_START_FROM_EQE = 0x0,
MLX5_CQ_PERIOD_MODE_START_FROM_CQE = 0x1,
MLX5_CQ_PERIOD_NUM_MODES
MLX5_CQ_PERIOD_NUM_MODES,
};
struct mlx5_ifc_cqc_bits {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment