mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
net/mlx5e: resize non-default RSS indirection tables on channel change
When the channel count changes and the RQT size changes with it, a problem arise for non-default RSS contexts. The driver-side indirection table grows actual_table_size without filling the new entries; stale entries from a prior larger configuration may be re-exposed, causing mlx5e_calc_indir_rqns() to WARN on an out-of-range index. Replace mlx5e_rss_params_indir_modify_actual_size() with mlx5e_rss_ctx_resize(), which fills new entries by replicating the existing pattern, matching what ethtool_rxfh_ctxs_resize() does for the same case. And restrict the loop to non-default contexts. Call ethtool_rxfh_ctxs_can_resize() before acquiring state_lock to validate that all non-default contexts can be resized, and ethtool_rxfh_ctxs_resize() after releasing it to fold or unfold their indirection tables. Both functions acquire rss_lock internally and cannot be called under state_lock. RTNL, held by all set_channels callers, serialises context creation and deletion making the pre-lock check safe. Guard both ethtool calls on mlx5e_rx_res_rss_cnt() > 1: skip the validation and resize when no non-default contexts exist. This naturally covers representors and IPoIB, which share mlx5e_ethtool_set_channels() but cannot have non-default RSS contexts. Signed-off-by: Yael Chemla <ychemla@nvidia.com> Reviewed-by: Nimrod Oren <noren@nvidia.com> Signed-off-by: Tariq Toukan <tariqt@nvidia.com> Link: https://patch.msgid.link/20260511172719.330490-4-tariqt@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
05ebdbaded
commit
6bf1c27586
|
|
@ -85,9 +85,21 @@ bool mlx5e_rss_get_inner_ft_support(struct mlx5e_rss *rss)
|
|||
return rss->params.inner_ft_support;
|
||||
}
|
||||
|
||||
void mlx5e_rss_params_indir_modify_actual_size(struct mlx5e_rss *rss, u32 num_channels)
|
||||
void mlx5e_rss_set_indir_actual_size(struct mlx5e_rss *rss, u32 size)
|
||||
{
|
||||
rss->indir.actual_table_size = mlx5e_rqt_size(rss->mdev, num_channels);
|
||||
rss->indir.actual_table_size = size;
|
||||
}
|
||||
|
||||
/* Handles non-default contexts, replicate existing pattern into new entries,
|
||||
* matching what ethtool_rxfh_ctxs_resize() does.
|
||||
*/
|
||||
void mlx5e_rss_ctx_resize(struct mlx5e_rss *rss, u32 new_size)
|
||||
{
|
||||
u32 old_size = rss->indir.actual_table_size;
|
||||
u32 i;
|
||||
|
||||
for (i = old_size; i < new_size; i++)
|
||||
rss->indir.table[i] = rss->indir.table[i % old_size];
|
||||
}
|
||||
|
||||
int mlx5e_rss_params_indir_init(struct mlx5e_rss_params_indir *indir,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ struct mlx5e_rss;
|
|||
int mlx5e_rss_params_indir_init(struct mlx5e_rss_params_indir *indir,
|
||||
u32 actual_table_size, u32 max_table_size);
|
||||
void mlx5e_rss_params_indir_cleanup(struct mlx5e_rss_params_indir *indir);
|
||||
void mlx5e_rss_params_indir_modify_actual_size(struct mlx5e_rss *rss, u32 num_channels);
|
||||
void mlx5e_rss_ctx_resize(struct mlx5e_rss *rss, u32 new_size);
|
||||
struct mlx5e_rss *
|
||||
mlx5e_rss_init(struct mlx5_core_dev *mdev,
|
||||
const struct mlx5e_rss_params *params,
|
||||
|
|
@ -46,6 +46,7 @@ void mlx5e_rss_refcnt_dec(struct mlx5e_rss *rss);
|
|||
unsigned int mlx5e_rss_refcnt_read(struct mlx5e_rss *rss);
|
||||
|
||||
bool mlx5e_rss_get_inner_ft_support(struct mlx5e_rss *rss);
|
||||
void mlx5e_rss_set_indir_actual_size(struct mlx5e_rss *rss, u32 size);
|
||||
u32 mlx5e_rss_get_tirn(struct mlx5e_rss *rss, enum mlx5_traffic_types tt,
|
||||
bool inner);
|
||||
bool mlx5e_rss_valid_tir(struct mlx5e_rss *rss, enum mlx5_traffic_types tt, bool inner);
|
||||
|
|
|
|||
|
|
@ -42,11 +42,20 @@ static u32 *get_vhca_ids(struct mlx5e_rx_res *res, int offset)
|
|||
|
||||
void mlx5e_rx_res_rss_update_num_channels(struct mlx5e_rx_res *res, u32 nch)
|
||||
{
|
||||
u32 new_size = mlx5e_rqt_size(res->mdev, nch);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MLX5E_MAX_NUM_RSS; i++) {
|
||||
if (res->rss[i])
|
||||
mlx5e_rss_params_indir_modify_actual_size(res->rss[i], nch);
|
||||
WARN_ON_ONCE(res->rss_active);
|
||||
|
||||
/* Default context */
|
||||
mlx5e_rss_set_indir_actual_size(res->rss[0], new_size);
|
||||
|
||||
/* Non-default contexts */
|
||||
for (i = 1; i < MLX5E_MAX_NUM_RSS; i++) {
|
||||
if (res->rss[i]) {
|
||||
mlx5e_rss_ctx_resize(res->rss[i], new_size);
|
||||
mlx5e_rss_set_indir_actual_size(res->rss[i], new_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -499,11 +499,15 @@ int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv,
|
|||
{
|
||||
struct mlx5e_params *cur_params = &priv->channels.params;
|
||||
unsigned int count = ch->combined_count;
|
||||
int new_rqt_size, cur_rqt_size;
|
||||
struct mlx5e_params new_params;
|
||||
bool arfs_enabled;
|
||||
bool has_rss_ctxs;
|
||||
bool opened;
|
||||
int err = 0;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (!count) {
|
||||
netdev_info(priv->netdev, "%s: combined_count=0 not supported\n",
|
||||
__func__);
|
||||
|
|
@ -513,16 +517,33 @@ int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv,
|
|||
if (cur_params->num_channels == count)
|
||||
return 0;
|
||||
|
||||
new_rqt_size = mlx5e_rqt_size(priv->mdev, count);
|
||||
/* Validate that all non-default RSS contexts can be resized before
|
||||
* committing to the channel count change.
|
||||
* ethtool_rxfh_ctxs_can_resize() acquires rss_lock internally and
|
||||
* cannot be called under state_lock (rss_lock -> state_lock ordering).
|
||||
*/
|
||||
has_rss_ctxs = priv->rx_res && mlx5e_rx_res_rss_cnt(priv->rx_res) > 1;
|
||||
if (has_rss_ctxs) {
|
||||
err = ethtool_rxfh_ctxs_can_resize(priv->netdev, new_rqt_size);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
mutex_lock(&priv->state_lock);
|
||||
|
||||
if (!priv->rx_res) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
cur_rqt_size = mlx5e_rqt_size(priv->mdev, cur_params->num_channels);
|
||||
|
||||
/* If RXFH is configured, changing the channels number is allowed only if
|
||||
* it does not require resizing the RSS table. This is because the previous
|
||||
* configuration may no longer be compatible with the new RSS table.
|
||||
*/
|
||||
if (netif_is_rxfh_configured(priv->netdev)) {
|
||||
int cur_rqt_size = mlx5e_rqt_size(priv->mdev, cur_params->num_channels);
|
||||
int new_rqt_size = mlx5e_rqt_size(priv->mdev, count);
|
||||
|
||||
if (new_rqt_size != cur_rqt_size) {
|
||||
err = -EINVAL;
|
||||
netdev_err(priv->netdev,
|
||||
|
|
@ -577,6 +598,14 @@ int mlx5e_ethtool_set_channels(struct mlx5e_priv *priv,
|
|||
out:
|
||||
mutex_unlock(&priv->state_lock);
|
||||
|
||||
/* After a successful channel count change that altered the RQT size,
|
||||
* fold or unfold the indirection tables of all non-default RSS
|
||||
* contexts. Must run after state_lock is released because
|
||||
* ethtool_rxfh_ctxs_resize() acquires rss_lock internally.
|
||||
*/
|
||||
if (!err && cur_rqt_size != new_rqt_size && has_rss_ctxs)
|
||||
ethtool_rxfh_ctxs_resize(priv->netdev, new_rqt_size);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user