mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-14 10:02:33 -04:00
Merge branch 'net-mlx5e-use-multiple-doorbells'
Tariq Toukan says: ==================== net/mlx5e: Use multiple doorbells mlx5e uses a single MMIO-mapped doorbell per netdevice for all send and receive operations. Writes to the doorbell go over the PCIe bus directly to the device, which then services the indicated queues. On certain architectures and with sufficiently high volume of doorbell ringing (many cores, many active channels, small MTU, no GSO, etc.), the MMIO-mapped doorbell address can become contended, leading to delays in servicing writes to that address and a global slowdown of all traffic for that netdevice. mlx5 NICs have supported using multiple doorbells for many years, the mlx5_ib driver for the same hardware has been using multiple doorbells traditionally. This patch series extends the mlx5 Ethernet driver to also use multiple doorbells to solve the MMIO contention issues. By allocating and using more doorbells for all channel queues (TX and RX), the MMIO contention on any particular doorbell address is reduced significantly. The first patches are cleanups: net/mlx5: Fix typo of MLX5_EQ_DOORBEL_OFFSET net/mlx5: Remove unused 'offset' field from struct mlx5_sq_bfreg' net/mlx5e: Remove unused 'xsk' param of mlx5e_build_xdpsq_param The next patch separates the global doorbell from Ethernet-specific resources: net/mlx5: Store the global doorbell in mlx5_priv Next, plumbing to allow a different doorbell to be used for channel TX and RX queues: net/mlx5e: Prepare for using multiple TX doorbells net/mlx5e: Prepare for using different CQ doorbells Then, enable using multiple doorbells for channel queues: net/mlx5e: Use multiple TX doorbells net/mlx5e: Use multiple CQ doorbells Finally, introduce a devlink parameter to control this: devlink: Add a 'num_doorbells' driverinit param net/mlx5e: Use the 'num_doorbells' devlink param Some performance results, done with the Linux pktgen script, running b2b over Connect-X 8 NICs: samples/pktgen/pktgen_sample02_multiqueue.sh -i $NIC -s 64 -d $DST_IP \ -m $MAC -t 64 Baseline (1 doorbell): 9 Mpps This series (8 doorbells): 56 Mpps Note that pktgen without 'burst' rings the doorbell after every packet, while real packet TX using NAPI usually batches multiple pending packets with the xmit_more mechanism. So this is in essence a micro-benchmark showcasing the improvement of using multiple doorbells on platforms affected by MMIO contention. Real life traffic usually sees little movement either way. ==================== Link: https://patch.msgid.link/1758031904-634231-1-git-send-email-tariqt@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
@@ -148,3 +148,6 @@ own name.
|
||||
- The max number of Virtual Functions (VFs) exposed by the PF.
|
||||
after reboot/pci reset, 'sriov_totalvfs' entry under the device's sysfs
|
||||
directory will report this value.
|
||||
* - ``num_doorbells``
|
||||
- u32
|
||||
- Controls the number of doorbells used by the device.
|
||||
|
||||
@@ -62,6 +62,15 @@ Note: permanent parameters such as ``enable_sriov`` and ``total_vfs`` require FW
|
||||
echo 1 >/sys/bus/pci/rescan
|
||||
grep ^ /sys/bus/pci/devices/0000:01:00.0/sriov_*
|
||||
|
||||
* - ``num_doorbells``
|
||||
- driverinit
|
||||
- This controls the number of channel doorbells used by the netdev. In all
|
||||
cases, an additional doorbell is allocated and used for non-channel
|
||||
communication (e.g. for PTP, HWS, etc.). Supported values are:
|
||||
|
||||
- 0: No channel-specific doorbells, use the global one for everything.
|
||||
- [1, max_num_channels]: Spread netdev channels equally across these
|
||||
doorbells.
|
||||
|
||||
The ``mlx5`` driver also implements the following driver-specific
|
||||
parameters.
|
||||
|
||||
@@ -648,7 +648,7 @@ int mlx5_ib_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
|
||||
{
|
||||
struct mlx5_core_dev *mdev = to_mdev(ibcq->device)->mdev;
|
||||
struct mlx5_ib_cq *cq = to_mcq(ibcq);
|
||||
void __iomem *uar_page = mdev->priv.uar->map;
|
||||
void __iomem *uar_page = mdev->priv.bfreg.up->map;
|
||||
unsigned long irq_flags;
|
||||
int ret = 0;
|
||||
|
||||
@@ -923,7 +923,7 @@ static int create_cq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
|
||||
cq->buf.frag_buf.page_shift -
|
||||
MLX5_ADAPTER_PAGE_SHIFT);
|
||||
|
||||
*index = dev->mdev->priv.uar->index;
|
||||
*index = dev->mdev->priv.bfreg.up->index;
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -145,7 +145,6 @@ int mlx5_create_cq(struct mlx5_core_dev *dev, struct mlx5_core_cq *cq,
|
||||
mlx5_core_dbg(dev, "failed adding CP 0x%x to debug file system\n",
|
||||
cq->cqn);
|
||||
|
||||
cq->uar = dev->priv.uar;
|
||||
cq->irqn = eq->core.irqn;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -530,6 +530,25 @@ mlx5_devlink_hairpin_queue_size_validate(struct devlink *devlink, u32 id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mlx5_devlink_num_doorbells_validate(struct devlink *devlink, u32 id,
|
||||
union devlink_param_value val,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct mlx5_core_dev *mdev = devlink_priv(devlink);
|
||||
u32 val32 = val.vu32;
|
||||
u32 max_num_channels;
|
||||
|
||||
max_num_channels = mlx5e_get_max_num_channels(mdev);
|
||||
if (val32 > max_num_channels) {
|
||||
NL_SET_ERR_MSG_FMT_MOD(extack,
|
||||
"Requested num_doorbells (%u) exceeds maximum number of channels (%u)",
|
||||
val32, max_num_channels);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mlx5_devlink_hairpin_params_init_values(struct devlink *devlink)
|
||||
{
|
||||
struct mlx5_core_dev *dev = devlink_priv(devlink);
|
||||
@@ -609,6 +628,9 @@ static const struct devlink_param mlx5_devlink_eth_params[] = {
|
||||
"hairpin_queue_size", DEVLINK_PARAM_TYPE_U32,
|
||||
BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), NULL, NULL,
|
||||
mlx5_devlink_hairpin_queue_size_validate),
|
||||
DEVLINK_PARAM_GENERIC(NUM_DOORBELLS,
|
||||
BIT(DEVLINK_PARAM_CMODE_DRIVERINIT), NULL, NULL,
|
||||
mlx5_devlink_num_doorbells_validate),
|
||||
};
|
||||
|
||||
static int mlx5_devlink_eth_params_register(struct devlink *devlink)
|
||||
@@ -632,6 +654,10 @@ static int mlx5_devlink_eth_params_register(struct devlink *devlink)
|
||||
|
||||
mlx5_devlink_hairpin_params_init_values(devlink);
|
||||
|
||||
value.vu32 = MLX5_DEFAULT_NUM_DOORBELLS;
|
||||
devl_param_driverinit_value_set(devlink,
|
||||
DEVLINK_PARAM_GENERIC_ID_NUM_DOORBELLS,
|
||||
value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -344,6 +344,7 @@ struct mlx5e_cq {
|
||||
/* data path - accessed per napi poll */
|
||||
u16 event_ctr;
|
||||
struct napi_struct *napi;
|
||||
struct mlx5_uars_page *uar;
|
||||
struct mlx5_core_cq mcq;
|
||||
struct mlx5e_ch_stats *ch_stats;
|
||||
|
||||
@@ -788,6 +789,7 @@ struct mlx5e_channel {
|
||||
int vec_ix;
|
||||
int sd_ix;
|
||||
int cpu;
|
||||
struct mlx5_sq_bfreg *bfreg;
|
||||
/* Sync between icosq recovery and XSK enable/disable. */
|
||||
struct mutex icosq_recovery_lock;
|
||||
|
||||
@@ -1060,6 +1062,7 @@ struct mlx5e_create_cq_param {
|
||||
struct mlx5e_ch_stats *ch_stats;
|
||||
int node;
|
||||
int ix;
|
||||
struct mlx5_uars_page *uar;
|
||||
};
|
||||
|
||||
struct mlx5e_cq_param;
|
||||
|
||||
@@ -611,6 +611,7 @@ void mlx5e_build_create_cq_param(struct mlx5e_create_cq_param *ccp, struct mlx5e
|
||||
.ch_stats = c->stats,
|
||||
.node = cpu_to_node(c->cpu),
|
||||
.ix = c->vec_ix,
|
||||
.uar = c->bfreg->up,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -810,7 +811,7 @@ static void mlx5e_build_common_cq_param(struct mlx5_core_dev *mdev,
|
||||
{
|
||||
void *cqc = param->cqc;
|
||||
|
||||
MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index);
|
||||
MLX5_SET(cqc, cqc, uar_page, mdev->priv.bfreg.up->index);
|
||||
if (MLX5_CAP_GEN(mdev, cqe_128_always) && cache_line_size() >= 128)
|
||||
MLX5_SET(cqc, cqc, cqe_sz, CQE_STRIDE_128_PAD);
|
||||
}
|
||||
@@ -1229,7 +1230,6 @@ static void mlx5e_build_async_icosq_param(struct mlx5_core_dev *mdev,
|
||||
|
||||
void mlx5e_build_xdpsq_param(struct mlx5_core_dev *mdev,
|
||||
struct mlx5e_params *params,
|
||||
struct mlx5e_xsk_param *xsk,
|
||||
struct mlx5e_sq_param *param)
|
||||
{
|
||||
void *sqc = param->sqc;
|
||||
@@ -1256,7 +1256,7 @@ int mlx5e_build_channel_param(struct mlx5_core_dev *mdev,
|
||||
async_icosq_log_wq_sz = mlx5e_build_async_icosq_log_wq_sz(mdev);
|
||||
|
||||
mlx5e_build_sq_param(mdev, params, &cparam->txq_sq);
|
||||
mlx5e_build_xdpsq_param(mdev, params, NULL, &cparam->xdp_sq);
|
||||
mlx5e_build_xdpsq_param(mdev, params, &cparam->xdp_sq);
|
||||
mlx5e_build_icosq_param(mdev, icosq_log_wq_sz, &cparam->icosq);
|
||||
mlx5e_build_async_icosq_param(mdev, async_icosq_log_wq_sz, &cparam->async_icosq);
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ struct mlx5e_create_sq_param {
|
||||
u32 tisn;
|
||||
u8 tis_lst_sz;
|
||||
u8 min_inline_mode;
|
||||
u32 uar_page;
|
||||
};
|
||||
|
||||
/* Striding RQ dynamic parameters */
|
||||
@@ -132,7 +133,6 @@ void mlx5e_build_tx_cq_param(struct mlx5_core_dev *mdev,
|
||||
struct mlx5e_cq_param *param);
|
||||
void mlx5e_build_xdpsq_param(struct mlx5_core_dev *mdev,
|
||||
struct mlx5e_params *params,
|
||||
struct mlx5e_xsk_param *xsk,
|
||||
struct mlx5e_sq_param *param);
|
||||
int mlx5e_build_channel_param(struct mlx5_core_dev *mdev,
|
||||
struct mlx5e_params *params,
|
||||
|
||||
@@ -334,7 +334,7 @@ static int mlx5e_ptp_alloc_txqsq(struct mlx5e_ptp *c, int txq_ix,
|
||||
sq->mdev = mdev;
|
||||
sq->ch_ix = MLX5E_PTP_CHANNEL_IX;
|
||||
sq->txq_ix = txq_ix;
|
||||
sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
|
||||
sq->uar_map = c->bfreg->map;
|
||||
sq->min_inline_mode = params->tx_min_inline_mode;
|
||||
sq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
|
||||
sq->stats = &c->priv->ptp_stats.sq[tc];
|
||||
@@ -486,6 +486,7 @@ static int mlx5e_ptp_open_txqsq(struct mlx5e_ptp *c, u32 tisn,
|
||||
csp.wq_ctrl = &txqsq->wq_ctrl;
|
||||
csp.min_inline_mode = txqsq->min_inline_mode;
|
||||
csp.ts_cqe_to_dest_cqn = ptpsq->ts_cq.mcq.cqn;
|
||||
csp.uar_page = c->bfreg->index;
|
||||
|
||||
err = mlx5e_create_sq_rdy(c->mdev, sqp, &csp, 0, &txqsq->sqn);
|
||||
if (err)
|
||||
@@ -577,6 +578,7 @@ static int mlx5e_ptp_open_tx_cqs(struct mlx5e_ptp *c,
|
||||
ccp.ch_stats = c->stats;
|
||||
ccp.napi = &c->napi;
|
||||
ccp.ix = MLX5E_PTP_CHANNEL_IX;
|
||||
ccp.uar = c->bfreg->up;
|
||||
|
||||
cq_param = &cparams->txq_sq_param.cqp;
|
||||
|
||||
@@ -626,6 +628,7 @@ static int mlx5e_ptp_open_rx_cq(struct mlx5e_ptp *c,
|
||||
ccp.ch_stats = c->stats;
|
||||
ccp.napi = &c->napi;
|
||||
ccp.ix = MLX5E_PTP_CHANNEL_IX;
|
||||
ccp.uar = c->bfreg->up;
|
||||
|
||||
cq_param = &cparams->rq_param.cqp;
|
||||
|
||||
@@ -900,6 +903,7 @@ int mlx5e_ptp_open(struct mlx5e_priv *priv, struct mlx5e_params *params,
|
||||
c->num_tc = mlx5e_get_dcb_num_tc(params);
|
||||
c->stats = &priv->ptp_stats.ch;
|
||||
c->lag_port = lag_port;
|
||||
c->bfreg = &mdev->priv.bfreg;
|
||||
|
||||
err = mlx5e_ptp_set_state(c, params);
|
||||
if (err)
|
||||
|
||||
@@ -66,6 +66,7 @@ struct mlx5e_ptp {
|
||||
struct mlx5_core_dev *mdev;
|
||||
struct hwtstamp_config *tstamp;
|
||||
DECLARE_BITMAP(state, MLX5E_PTP_STATE_NUM_STATES);
|
||||
struct mlx5_sq_bfreg *bfreg;
|
||||
};
|
||||
|
||||
static inline bool mlx5e_use_ptpsq(struct sk_buff *skb)
|
||||
|
||||
@@ -76,6 +76,7 @@ static int mlx5e_open_trap_rq(struct mlx5e_priv *priv, struct mlx5e_trap *t)
|
||||
ccp.ch_stats = t->stats;
|
||||
ccp.napi = &t->napi;
|
||||
ccp.ix = 0;
|
||||
ccp.uar = mdev->priv.bfreg.up;
|
||||
err = mlx5e_open_cq(priv->mdev, trap_moder, &rq_param->cqp, &ccp, &rq->cq);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -309,10 +309,7 @@ mlx5e_notify_hw(struct mlx5_wq_cyc *wq, u16 pc, void __iomem *uar_map,
|
||||
|
||||
static inline void mlx5e_cq_arm(struct mlx5e_cq *cq)
|
||||
{
|
||||
struct mlx5_core_cq *mcq;
|
||||
|
||||
mcq = &cq->mcq;
|
||||
mlx5_cq_arm(mcq, MLX5_CQ_DB_REQ_NOT, mcq->uar->map, cq->wq.cc);
|
||||
mlx5_cq_arm(&cq->mcq, MLX5_CQ_DB_REQ_NOT, cq->uar->map, cq->wq.cc);
|
||||
}
|
||||
|
||||
static inline struct mlx5e_sq_dma *
|
||||
|
||||
@@ -54,7 +54,7 @@ static void mlx5e_build_xsk_cparam(struct mlx5_core_dev *mdev,
|
||||
struct mlx5e_channel_param *cparam)
|
||||
{
|
||||
mlx5e_build_rq_param(mdev, params, xsk, &cparam->rq);
|
||||
mlx5e_build_xdpsq_param(mdev, params, xsk, &cparam->xdp_sq);
|
||||
mlx5e_build_xdpsq_param(mdev, params, &cparam->xdp_sq);
|
||||
}
|
||||
|
||||
static int mlx5e_init_xsk_rq(struct mlx5e_channel *c,
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "devlink.h"
|
||||
#include "en.h"
|
||||
#include "lib/crypto.h"
|
||||
|
||||
@@ -140,9 +141,22 @@ static int mlx5e_create_tises(struct mlx5_core_dev *mdev, u32 tisn[MLX5_MAX_PORT
|
||||
return err;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
mlx5e_get_devlink_param_num_doorbells(struct mlx5_core_dev *dev)
|
||||
{
|
||||
const u32 param_id = DEVLINK_PARAM_GENERIC_ID_NUM_DOORBELLS;
|
||||
struct devlink *devlink = priv_to_devlink(dev);
|
||||
union devlink_param_value val;
|
||||
int err;
|
||||
|
||||
err = devl_param_driverinit_value_get(devlink, param_id, &val);
|
||||
return err ? MLX5_DEFAULT_NUM_DOORBELLS : val.vu32;
|
||||
}
|
||||
|
||||
int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev, bool create_tises)
|
||||
{
|
||||
struct mlx5e_hw_objs *res = &mdev->mlx5e_res.hw_objs;
|
||||
unsigned int num_doorbells, i;
|
||||
int err;
|
||||
|
||||
err = mlx5_core_alloc_pd(mdev, &res->pdn);
|
||||
@@ -163,17 +177,30 @@ int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev, bool create_tises)
|
||||
goto err_dealloc_transport_domain;
|
||||
}
|
||||
|
||||
err = mlx5_alloc_bfreg(mdev, &res->bfreg, false, false);
|
||||
if (err) {
|
||||
mlx5_core_err(mdev, "alloc bfreg failed, %d\n", err);
|
||||
num_doorbells = min(mlx5e_get_devlink_param_num_doorbells(mdev),
|
||||
mlx5e_get_max_num_channels(mdev));
|
||||
res->bfregs = kcalloc(num_doorbells, sizeof(*res->bfregs), GFP_KERNEL);
|
||||
if (!res->bfregs) {
|
||||
err = -ENOMEM;
|
||||
goto err_destroy_mkey;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_doorbells; i++) {
|
||||
err = mlx5_alloc_bfreg(mdev, res->bfregs + i, false, false);
|
||||
if (err) {
|
||||
mlx5_core_warn(mdev,
|
||||
"could only allocate %d/%d doorbells, err %d.\n",
|
||||
i, num_doorbells, err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
res->num_bfregs = i;
|
||||
|
||||
if (create_tises) {
|
||||
err = mlx5e_create_tises(mdev, res->tisn);
|
||||
if (err) {
|
||||
mlx5_core_err(mdev, "alloc tises failed, %d\n", err);
|
||||
goto err_destroy_bfreg;
|
||||
goto err_destroy_bfregs;
|
||||
}
|
||||
res->tisn_valid = true;
|
||||
}
|
||||
@@ -190,8 +217,10 @@ int mlx5e_create_mdev_resources(struct mlx5_core_dev *mdev, bool create_tises)
|
||||
|
||||
return 0;
|
||||
|
||||
err_destroy_bfreg:
|
||||
mlx5_free_bfreg(mdev, &res->bfreg);
|
||||
err_destroy_bfregs:
|
||||
for (i = 0; i < res->num_bfregs; i++)
|
||||
mlx5_free_bfreg(mdev, res->bfregs + i);
|
||||
kfree(res->bfregs);
|
||||
err_destroy_mkey:
|
||||
mlx5_core_destroy_mkey(mdev, res->mkey);
|
||||
err_dealloc_transport_domain:
|
||||
@@ -209,7 +238,9 @@ void mlx5e_destroy_mdev_resources(struct mlx5_core_dev *mdev)
|
||||
mdev->mlx5e_res.dek_priv = NULL;
|
||||
if (res->tisn_valid)
|
||||
mlx5e_destroy_tises(mdev, res->tisn);
|
||||
mlx5_free_bfreg(mdev, &res->bfreg);
|
||||
for (unsigned int i = 0; i < res->num_bfregs; i++)
|
||||
mlx5_free_bfreg(mdev, res->bfregs + i);
|
||||
kfree(res->bfregs);
|
||||
mlx5_core_destroy_mkey(mdev, res->mkey);
|
||||
mlx5_core_dealloc_transport_domain(mdev, res->td.tdn);
|
||||
mlx5_core_dealloc_pd(mdev, res->pdn);
|
||||
|
||||
@@ -1536,7 +1536,7 @@ static int mlx5e_alloc_xdpsq(struct mlx5e_channel *c,
|
||||
sq->pdev = c->pdev;
|
||||
sq->mkey_be = c->mkey_be;
|
||||
sq->channel = c;
|
||||
sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
|
||||
sq->uar_map = c->bfreg->map;
|
||||
sq->min_inline_mode = params->tx_min_inline_mode;
|
||||
sq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu) - ETH_FCS_LEN;
|
||||
sq->xsk_pool = xsk_pool;
|
||||
@@ -1621,7 +1621,7 @@ static int mlx5e_alloc_icosq(struct mlx5e_channel *c,
|
||||
int err;
|
||||
|
||||
sq->channel = c;
|
||||
sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
|
||||
sq->uar_map = c->bfreg->map;
|
||||
sq->reserved_room = param->stop_room;
|
||||
|
||||
param->wq.db_numa_node = cpu_to_node(c->cpu);
|
||||
@@ -1706,7 +1706,7 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
|
||||
sq->priv = c->priv;
|
||||
sq->ch_ix = c->ix;
|
||||
sq->txq_ix = txq_ix;
|
||||
sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
|
||||
sq->uar_map = c->bfreg->map;
|
||||
sq->min_inline_mode = params->tx_min_inline_mode;
|
||||
sq->hw_mtu = MLX5E_SW2HW_MTU(params, params->sw_mtu);
|
||||
sq->max_sq_mpw_wqebbs = mlx5e_get_max_sq_aligned_wqebbs(mdev);
|
||||
@@ -1782,7 +1782,7 @@ static int mlx5e_create_sq(struct mlx5_core_dev *mdev,
|
||||
MLX5_SET(sqc, sqc, flush_in_error_en, 1);
|
||||
|
||||
MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
|
||||
MLX5_SET(wq, wq, uar_page, mdev->mlx5e_res.hw_objs.bfreg.index);
|
||||
MLX5_SET(wq, wq, uar_page, csp->uar_page);
|
||||
MLX5_SET(wq, wq, log_wq_pg_sz, csp->wq_ctrl->buf.page_shift -
|
||||
MLX5_ADAPTER_PAGE_SHIFT);
|
||||
MLX5_SET64(wq, wq, dbr_addr, csp->wq_ctrl->db.dma);
|
||||
@@ -1886,6 +1886,7 @@ int mlx5e_open_txqsq(struct mlx5e_channel *c, u32 tisn, int txq_ix,
|
||||
csp.cqn = sq->cq.mcq.cqn;
|
||||
csp.wq_ctrl = &sq->wq_ctrl;
|
||||
csp.min_inline_mode = sq->min_inline_mode;
|
||||
csp.uar_page = c->bfreg->index;
|
||||
err = mlx5e_create_sq_rdy(c->mdev, param, &csp, qos_queue_group_id, &sq->sqn);
|
||||
if (err)
|
||||
goto err_free_txqsq;
|
||||
@@ -2056,6 +2057,7 @@ static int mlx5e_open_icosq(struct mlx5e_channel *c, struct mlx5e_params *params
|
||||
csp.cqn = sq->cq.mcq.cqn;
|
||||
csp.wq_ctrl = &sq->wq_ctrl;
|
||||
csp.min_inline_mode = params->tx_min_inline_mode;
|
||||
csp.uar_page = c->bfreg->index;
|
||||
err = mlx5e_create_sq_rdy(c->mdev, param, &csp, 0, &sq->sqn);
|
||||
if (err)
|
||||
goto err_free_icosq;
|
||||
@@ -2116,6 +2118,7 @@ int mlx5e_open_xdpsq(struct mlx5e_channel *c, struct mlx5e_params *params,
|
||||
csp.cqn = sq->cq.mcq.cqn;
|
||||
csp.wq_ctrl = &sq->wq_ctrl;
|
||||
csp.min_inline_mode = sq->min_inline_mode;
|
||||
csp.uar_page = c->bfreg->index;
|
||||
set_bit(MLX5E_SQ_STATE_ENABLED, &sq->state);
|
||||
|
||||
err = mlx5e_create_sq_rdy(c->mdev, param, &csp, 0, &sq->sqn);
|
||||
@@ -2186,6 +2189,7 @@ static void mlx5e_close_xdpredirect_sq(struct mlx5e_xdpsq *xdpsq)
|
||||
static int mlx5e_alloc_cq_common(struct mlx5_core_dev *mdev,
|
||||
struct net_device *netdev,
|
||||
struct workqueue_struct *workqueue,
|
||||
struct mlx5_uars_page *uar,
|
||||
struct mlx5e_cq_param *param,
|
||||
struct mlx5e_cq *cq)
|
||||
{
|
||||
@@ -2217,6 +2221,7 @@ static int mlx5e_alloc_cq_common(struct mlx5_core_dev *mdev,
|
||||
cq->mdev = mdev;
|
||||
cq->netdev = netdev;
|
||||
cq->workqueue = workqueue;
|
||||
cq->uar = uar;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2232,7 +2237,8 @@ static int mlx5e_alloc_cq(struct mlx5_core_dev *mdev,
|
||||
param->wq.db_numa_node = ccp->node;
|
||||
param->eq_ix = ccp->ix;
|
||||
|
||||
err = mlx5e_alloc_cq_common(mdev, ccp->netdev, ccp->wq, param, cq);
|
||||
err = mlx5e_alloc_cq_common(mdev, ccp->netdev, ccp->wq,
|
||||
ccp->uar, param, cq);
|
||||
|
||||
cq->napi = ccp->napi;
|
||||
cq->ch_stats = ccp->ch_stats;
|
||||
@@ -2277,7 +2283,7 @@ static int mlx5e_create_cq(struct mlx5e_cq *cq, struct mlx5e_cq_param *param)
|
||||
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, uar_page, cq->uar->index);
|
||||
MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
|
||||
MLX5_ADAPTER_PAGE_SHIFT);
|
||||
MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma);
|
||||
@@ -2744,6 +2750,20 @@ void mlx5e_trigger_napi_sched(struct napi_struct *napi)
|
||||
local_bh_enable();
|
||||
}
|
||||
|
||||
static void mlx5e_channel_pick_doorbell(struct mlx5e_channel *c)
|
||||
{
|
||||
struct mlx5e_hw_objs *hw_objs = &c->mdev->mlx5e_res.hw_objs;
|
||||
|
||||
/* No dedicated Ethernet doorbells, use the global one. */
|
||||
if (hw_objs->num_bfregs == 0) {
|
||||
c->bfreg = &c->mdev->priv.bfreg;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Round-robin between doorbells. */
|
||||
c->bfreg = hw_objs->bfregs + c->vec_ix % hw_objs->num_bfregs;
|
||||
}
|
||||
|
||||
static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
|
||||
struct mlx5e_params *params,
|
||||
struct xsk_buff_pool *xsk_pool,
|
||||
@@ -2798,6 +2818,8 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix,
|
||||
c->aff_mask = irq_get_effective_affinity_mask(irq);
|
||||
c->lag_port = mlx5e_enumerate_lag_port(mdev, ix);
|
||||
|
||||
mlx5e_channel_pick_doorbell(c);
|
||||
|
||||
netif_napi_add_config_locked(netdev, &c->napi, mlx5e_napi_poll, ix);
|
||||
netif_napi_set_irq_locked(&c->napi, irq);
|
||||
|
||||
@@ -3583,7 +3605,8 @@ static int mlx5e_alloc_drop_cq(struct mlx5e_priv *priv,
|
||||
param->wq.buf_numa_node = dev_to_node(mlx5_core_dma_dev(mdev));
|
||||
param->wq.db_numa_node = dev_to_node(mlx5_core_dma_dev(mdev));
|
||||
|
||||
return mlx5e_alloc_cq_common(priv->mdev, priv->netdev, priv->wq, param, cq);
|
||||
return mlx5e_alloc_cq_common(priv->mdev, priv->netdev, priv->wq,
|
||||
mdev->priv.bfreg.up, param, cq);
|
||||
}
|
||||
|
||||
int mlx5e_open_drop_rq(struct mlx5e_priv *priv,
|
||||
|
||||
@@ -32,9 +32,7 @@ enum {
|
||||
MLX5_EQ_STATE_ALWAYS_ARMED = 0xb,
|
||||
};
|
||||
|
||||
enum {
|
||||
MLX5_EQ_DOORBEL_OFFSET = 0x40,
|
||||
};
|
||||
#define MLX5_EQ_DOORBELL_OFFSET 0x40
|
||||
|
||||
/* budget must be smaller than MLX5_NUM_SPARE_EQE to guarantee that we update
|
||||
* the ci before we polled all the entries in the EQ. MLX5_NUM_SPARE_EQE is
|
||||
@@ -309,7 +307,7 @@ create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
|
||||
|
||||
eqc = MLX5_ADDR_OF(create_eq_in, in, eq_context_entry);
|
||||
MLX5_SET(eqc, eqc, log_eq_size, eq->fbc.log_sz);
|
||||
MLX5_SET(eqc, eqc, uar_page, priv->uar->index);
|
||||
MLX5_SET(eqc, eqc, uar_page, priv->bfreg.up->index);
|
||||
MLX5_SET(eqc, eqc, intr, vecidx);
|
||||
MLX5_SET(eqc, eqc, log_page_size,
|
||||
eq->frag_buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT);
|
||||
@@ -322,7 +320,7 @@ create_map_eq(struct mlx5_core_dev *dev, struct mlx5_eq *eq,
|
||||
eq->eqn = MLX5_GET(create_eq_out, out, eq_number);
|
||||
eq->irqn = pci_irq_vector(dev->pdev, vecidx);
|
||||
eq->dev = dev;
|
||||
eq->doorbell = priv->uar->map + MLX5_EQ_DOORBEL_OFFSET;
|
||||
eq->doorbell = priv->bfreg.up->map + MLX5_EQ_DOORBELL_OFFSET;
|
||||
|
||||
err = mlx5_debug_eq_add(dev, eq);
|
||||
if (err)
|
||||
|
||||
@@ -475,7 +475,6 @@ static int mlx5_fpga_conn_create_cq(struct mlx5_fpga_conn *conn, int cq_size)
|
||||
*conn->cq.mcq.arm_db = 0;
|
||||
conn->cq.mcq.vector = 0;
|
||||
conn->cq.mcq.comp = mlx5_fpga_conn_cq_complete;
|
||||
conn->cq.mcq.uar = fdev->conn_res.uar;
|
||||
tasklet_setup(&conn->cq.tasklet, mlx5_fpga_conn_cq_tasklet);
|
||||
|
||||
mlx5_fpga_dbg(fdev, "Created CQ #0x%x\n", conn->cq.mcq.cqn);
|
||||
|
||||
@@ -100,7 +100,7 @@ static int create_aso_cq(struct mlx5_aso_cq *cq, void *cqc_data)
|
||||
|
||||
MLX5_SET(cqc, cqc, cq_period_mode, MLX5_CQ_PERIOD_MODE_START_FROM_EQE);
|
||||
MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn);
|
||||
MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index);
|
||||
MLX5_SET(cqc, cqc, uar_page, mdev->priv.bfreg.up->index);
|
||||
MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
|
||||
MLX5_ADAPTER_PAGE_SHIFT);
|
||||
MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma);
|
||||
@@ -129,7 +129,7 @@ static int mlx5_aso_create_cq(struct mlx5_core_dev *mdev, int numa_node,
|
||||
return -ENOMEM;
|
||||
|
||||
MLX5_SET(cqc, cqc_data, log_cq_size, 1);
|
||||
MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.uar->index);
|
||||
MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.bfreg.up->index);
|
||||
if (MLX5_CAP_GEN(mdev, cqe_128_always) && cache_line_size() >= 128)
|
||||
MLX5_SET(cqc, cqc_data, cqe_sz, CQE_STRIDE_128_PAD);
|
||||
|
||||
@@ -163,7 +163,7 @@ static int mlx5_aso_alloc_sq(struct mlx5_core_dev *mdev, int numa_node,
|
||||
struct mlx5_wq_param param;
|
||||
int err;
|
||||
|
||||
sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
|
||||
sq->uar_map = mdev->priv.bfreg.map;
|
||||
|
||||
param.db_numa_node = numa_node;
|
||||
param.buf_numa_node = numa_node;
|
||||
@@ -203,7 +203,7 @@ static int create_aso_sq(struct mlx5_core_dev *mdev, int pdn,
|
||||
MLX5_SET(sqc, sqc, ts_format, ts_format);
|
||||
|
||||
MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
|
||||
MLX5_SET(wq, wq, uar_page, mdev->mlx5e_res.hw_objs.bfreg.index);
|
||||
MLX5_SET(wq, wq, uar_page, mdev->priv.bfreg.index);
|
||||
MLX5_SET(wq, wq, log_wq_pg_sz, sq->wq_ctrl.buf.page_shift -
|
||||
MLX5_ADAPTER_PAGE_SHIFT);
|
||||
MLX5_SET64(wq, wq, dbr_addr, sq->wq_ctrl.db.dma);
|
||||
|
||||
@@ -1316,10 +1316,9 @@ static int mlx5_load(struct mlx5_core_dev *dev)
|
||||
{
|
||||
int err;
|
||||
|
||||
dev->priv.uar = mlx5_get_uars_page(dev);
|
||||
if (IS_ERR(dev->priv.uar)) {
|
||||
mlx5_core_err(dev, "Failed allocating uar, aborting\n");
|
||||
err = PTR_ERR(dev->priv.uar);
|
||||
err = mlx5_alloc_bfreg(dev, &dev->priv.bfreg, false, false);
|
||||
if (err) {
|
||||
mlx5_core_err(dev, "Failed allocating bfreg, %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1430,7 +1429,7 @@ static int mlx5_load(struct mlx5_core_dev *dev)
|
||||
err_irq_table:
|
||||
mlx5_pagealloc_stop(dev);
|
||||
mlx5_events_stop(dev);
|
||||
mlx5_put_uars_page(dev, dev->priv.uar);
|
||||
mlx5_free_bfreg(dev, &dev->priv.bfreg);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1455,7 +1454,7 @@ static void mlx5_unload(struct mlx5_core_dev *dev)
|
||||
mlx5_irq_table_destroy(dev);
|
||||
mlx5_pagealloc_stop(dev);
|
||||
mlx5_events_stop(dev);
|
||||
mlx5_put_uars_page(dev, dev->priv.uar);
|
||||
mlx5_free_bfreg(dev, &dev->priv.bfreg);
|
||||
}
|
||||
|
||||
int mlx5_init_one_devl_locked(struct mlx5_core_dev *dev)
|
||||
|
||||
@@ -690,7 +690,7 @@ static int hws_send_ring_alloc_sq(struct mlx5_core_dev *mdev,
|
||||
size_t buf_sz;
|
||||
int err;
|
||||
|
||||
sq->uar_map = mdev->mlx5e_res.hw_objs.bfreg.map;
|
||||
sq->uar_map = mdev->priv.bfreg.map;
|
||||
sq->mdev = mdev;
|
||||
|
||||
param.db_numa_node = numa_node;
|
||||
@@ -764,7 +764,7 @@ static int hws_send_ring_create_sq(struct mlx5_core_dev *mdev, u32 pdn,
|
||||
MLX5_SET(sqc, sqc, ts_format, ts_format);
|
||||
|
||||
MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
|
||||
MLX5_SET(wq, wq, uar_page, mdev->mlx5e_res.hw_objs.bfreg.index);
|
||||
MLX5_SET(wq, wq, uar_page, mdev->priv.bfreg.index);
|
||||
MLX5_SET(wq, wq, log_wq_pg_sz, sq->wq_ctrl.buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT);
|
||||
MLX5_SET64(wq, wq, dbr_addr, sq->wq_ctrl.db.dma);
|
||||
|
||||
@@ -940,7 +940,7 @@ static int hws_send_ring_create_cq(struct mlx5_core_dev *mdev,
|
||||
(__be64 *)MLX5_ADDR_OF(create_cq_in, in, pas));
|
||||
|
||||
MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn);
|
||||
MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index);
|
||||
MLX5_SET(cqc, cqc, uar_page, mdev->priv.bfreg.up->index);
|
||||
MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift - MLX5_ADAPTER_PAGE_SHIFT);
|
||||
MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma);
|
||||
|
||||
@@ -963,7 +963,7 @@ static int hws_send_ring_open_cq(struct mlx5_core_dev *mdev,
|
||||
if (!cqc_data)
|
||||
return -ENOMEM;
|
||||
|
||||
MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.uar->index);
|
||||
MLX5_SET(cqc, cqc_data, uar_page, mdev->priv.bfreg.up->index);
|
||||
MLX5_SET(cqc, cqc_data, log_cq_size, ilog2(queue->num_entries));
|
||||
|
||||
err = hws_send_ring_alloc_cq(mdev, numa_node, queue, cqc_data, cq);
|
||||
|
||||
@@ -1131,7 +1131,6 @@ static struct mlx5dr_cq *dr_create_cq(struct mlx5_core_dev *mdev,
|
||||
*cq->mcq.arm_db = cpu_to_be32(2 << 28);
|
||||
|
||||
cq->mcq.vector = 0;
|
||||
cq->mcq.uar = uar;
|
||||
cq->mdev = mdev;
|
||||
|
||||
return cq;
|
||||
|
||||
@@ -94,7 +94,7 @@ static int create_wc_cq(struct mlx5_wc_cq *cq, void *cqc_data)
|
||||
|
||||
MLX5_SET(cqc, cqc, cq_period_mode, MLX5_CQ_PERIOD_MODE_START_FROM_EQE);
|
||||
MLX5_SET(cqc, cqc, c_eqn_or_apu_element, eqn);
|
||||
MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index);
|
||||
MLX5_SET(cqc, cqc, uar_page, mdev->priv.bfreg.up->index);
|
||||
MLX5_SET(cqc, cqc, log_page_size, cq->wq_ctrl.buf.page_shift -
|
||||
MLX5_ADAPTER_PAGE_SHIFT);
|
||||
MLX5_SET64(cqc, cqc, dbr_addr, cq->wq_ctrl.db.dma);
|
||||
@@ -116,7 +116,7 @@ static int mlx5_wc_create_cq(struct mlx5_core_dev *mdev, struct mlx5_wc_cq *cq)
|
||||
return -ENOMEM;
|
||||
|
||||
MLX5_SET(cqc, cqc, log_cq_size, TEST_WC_LOG_CQ_SZ);
|
||||
MLX5_SET(cqc, cqc, uar_page, mdev->priv.uar->index);
|
||||
MLX5_SET(cqc, cqc, uar_page, mdev->priv.bfreg.up->index);
|
||||
if (MLX5_CAP_GEN(mdev, cqe_128_always) && cache_line_size() >= 128)
|
||||
MLX5_SET(cqc, cqc, cqe_sz, CQE_STRIDE_128_PAD);
|
||||
|
||||
@@ -255,7 +255,8 @@ static void mlx5_wc_destroy_sq(struct mlx5_wc_sq *sq)
|
||||
mlx5_wq_destroy(&sq->wq_ctrl);
|
||||
}
|
||||
|
||||
static void mlx5_wc_post_nop(struct mlx5_wc_sq *sq, bool signaled)
|
||||
static void mlx5_wc_post_nop(struct mlx5_wc_sq *sq, unsigned int *offset,
|
||||
bool signaled)
|
||||
{
|
||||
int buf_size = (1 << MLX5_CAP_GEN(sq->cq.mdev, log_bf_reg_size)) / 2;
|
||||
struct mlx5_wqe_ctrl_seg *ctrl;
|
||||
@@ -288,10 +289,10 @@ static void mlx5_wc_post_nop(struct mlx5_wc_sq *sq, bool signaled)
|
||||
*/
|
||||
wmb();
|
||||
|
||||
__iowrite64_copy(sq->bfreg.map + sq->bfreg.offset, mmio_wqe,
|
||||
__iowrite64_copy(sq->bfreg.map + *offset, mmio_wqe,
|
||||
sizeof(mmio_wqe) / 8);
|
||||
|
||||
sq->bfreg.offset ^= buf_size;
|
||||
*offset ^= buf_size;
|
||||
}
|
||||
|
||||
static int mlx5_wc_poll_cq(struct mlx5_wc_sq *sq)
|
||||
@@ -332,6 +333,7 @@ static int mlx5_wc_poll_cq(struct mlx5_wc_sq *sq)
|
||||
|
||||
static void mlx5_core_test_wc(struct mlx5_core_dev *mdev)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
unsigned long expires;
|
||||
struct mlx5_wc_sq *sq;
|
||||
int i, err;
|
||||
@@ -358,9 +360,9 @@ static void mlx5_core_test_wc(struct mlx5_core_dev *mdev)
|
||||
goto err_create_sq;
|
||||
|
||||
for (i = 0; i < TEST_WC_NUM_WQES - 1; i++)
|
||||
mlx5_wc_post_nop(sq, false);
|
||||
mlx5_wc_post_nop(sq, &offset, false);
|
||||
|
||||
mlx5_wc_post_nop(sq, true);
|
||||
mlx5_wc_post_nop(sq, &offset, true);
|
||||
|
||||
expires = jiffies + TEST_WC_POLLING_MAX_TIME_JIFFIES;
|
||||
do {
|
||||
|
||||
@@ -41,7 +41,6 @@ struct mlx5_core_cq {
|
||||
int cqe_sz;
|
||||
__be32 *set_ci_db;
|
||||
__be32 *arm_db;
|
||||
struct mlx5_uars_page *uar;
|
||||
refcount_t refcount;
|
||||
struct completion free;
|
||||
unsigned vector;
|
||||
|
||||
@@ -434,7 +434,6 @@ struct mlx5_sq_bfreg {
|
||||
struct mlx5_uars_page *up;
|
||||
bool wc;
|
||||
u32 index;
|
||||
unsigned int offset;
|
||||
};
|
||||
|
||||
struct mlx5_core_health {
|
||||
@@ -613,7 +612,7 @@ struct mlx5_priv {
|
||||
struct mlx5_ft_pool *ft_pool;
|
||||
|
||||
struct mlx5_bfreg_data bfregs;
|
||||
struct mlx5_uars_page *uar;
|
||||
struct mlx5_sq_bfreg bfreg;
|
||||
#ifdef CONFIG_MLX5_SF
|
||||
struct mlx5_vhca_state_notifier *vhca_state_notifier;
|
||||
struct mlx5_sf_dev_table *sf_dev_table;
|
||||
@@ -659,7 +658,8 @@ struct mlx5e_resources {
|
||||
u32 pdn;
|
||||
struct mlx5_td td;
|
||||
u32 mkey;
|
||||
struct mlx5_sq_bfreg bfreg;
|
||||
struct mlx5_sq_bfreg *bfregs;
|
||||
unsigned int num_bfregs;
|
||||
#define MLX5_MAX_NUM_TC 8
|
||||
u32 tisn[MLX5_MAX_PORTS][MLX5_MAX_NUM_TC];
|
||||
bool tisn_valid;
|
||||
@@ -803,6 +803,8 @@ struct mlx5_db {
|
||||
int index;
|
||||
};
|
||||
|
||||
#define MLX5_DEFAULT_NUM_DOORBELLS 8
|
||||
|
||||
enum {
|
||||
MLX5_COMP_EQ_SIZE = 1024,
|
||||
};
|
||||
|
||||
@@ -531,6 +531,7 @@ enum devlink_param_generic_id {
|
||||
DEVLINK_PARAM_GENERIC_ID_ENABLE_PHC,
|
||||
DEVLINK_PARAM_GENERIC_ID_CLOCK_ID,
|
||||
DEVLINK_PARAM_GENERIC_ID_TOTAL_VFS,
|
||||
DEVLINK_PARAM_GENERIC_ID_NUM_DOORBELLS,
|
||||
|
||||
/* add new param generic ids above here*/
|
||||
__DEVLINK_PARAM_GENERIC_ID_MAX,
|
||||
@@ -598,6 +599,9 @@ enum devlink_param_generic_id {
|
||||
#define DEVLINK_PARAM_GENERIC_TOTAL_VFS_NAME "total_vfs"
|
||||
#define DEVLINK_PARAM_GENERIC_TOTAL_VFS_TYPE DEVLINK_PARAM_TYPE_U32
|
||||
|
||||
#define DEVLINK_PARAM_GENERIC_NUM_DOORBELLS_NAME "num_doorbells"
|
||||
#define DEVLINK_PARAM_GENERIC_NUM_DOORBELLS_TYPE DEVLINK_PARAM_TYPE_U32
|
||||
|
||||
#define DEVLINK_PARAM_GENERIC(_id, _cmodes, _get, _set, _validate) \
|
||||
{ \
|
||||
.id = DEVLINK_PARAM_GENERIC_ID_##_id, \
|
||||
|
||||
@@ -107,6 +107,11 @@ static const struct devlink_param devlink_param_generic[] = {
|
||||
.name = DEVLINK_PARAM_GENERIC_TOTAL_VFS_NAME,
|
||||
.type = DEVLINK_PARAM_GENERIC_TOTAL_VFS_TYPE,
|
||||
},
|
||||
{
|
||||
.id = DEVLINK_PARAM_GENERIC_ID_NUM_DOORBELLS,
|
||||
.name = DEVLINK_PARAM_GENERIC_NUM_DOORBELLS_NAME,
|
||||
.type = DEVLINK_PARAM_GENERIC_NUM_DOORBELLS_TYPE,
|
||||
},
|
||||
};
|
||||
|
||||
static int devlink_param_generic_verify(const struct devlink_param *param)
|
||||
|
||||
Reference in New Issue
Block a user