Skip to content

Commit 8bf30be

Browse files
nvmmaxSaeed Mahameed
authored and
Saeed Mahameed
committed
net/mlx5e: Introduce select queue parameters
ndo_select_queue can be called at any time, and there is no way to stop the kernel from calling it to synchronize with configuration changes (real_num_tx_queues, num_tc). This commit introduces an internal way in mlx5e to sync mlx5e_select_queue() with these changes. The configuration needed by this function is stored in a struct mlx5e_selq_params, which is modified and accessed in an atomic way using RCU methods. The whole ndo_select_queue is called under an RCU lock, providing the necessary guarantees. The parameters stored in the new struct mlx5e_selq_params should only be used from inside mlx5e_select_queue. It's the minimal set of parameters needed for mlx5e_select_queue to do its job efficiently, derived from parameters stored elsewhere. That means that when the configuration change, mlx5e_selq_params may need to be updated. In such cases, the mlx5e_selq_prepare/mlx5e_selq_apply API should be used. struct mlx5e_selq contains two slots for the params: active and standby. mlx5e_selq_prepare updates the standby slot, and mlx5e_selq_apply swaps the slots in a safe atomic way using the RCU API. It integrates well with the open/activate stages of the configuration change flow. Signed-off-by: Maxim Mikityanskiy <[email protected]> Reviewed-by: Tariq Toukan <[email protected]> Signed-off-by: Saeed Mahameed <[email protected]>
1 parent 17c84cb commit 8bf30be

File tree

6 files changed

+165
-5
lines changed

6 files changed

+165
-5
lines changed

drivers/net/ethernet/mellanox/mlx5/core/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ mlx5_core-$(CONFIG_MLX5_CORE_EN) += en/rqt.o en/tir.o en/rss.o en/rx_res.o \
2828
en_selftest.o en/port.o en/monitor_stats.o en/health.o \
2929
en/reporter_tx.o en/reporter_rx.o en/params.o en/xsk/pool.o \
3030
en/xsk/setup.o en/xsk/rx.o en/xsk/tx.o en/devlink.o en/ptp.o \
31-
en/qos.o en/trap.o en/fs_tt_redirect.o
31+
en/qos.o en/trap.o en/fs_tt_redirect.o en/selq.o
3232

3333
#
3434
# Netdev extra

drivers/net/ethernet/mellanox/mlx5/core/en.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#include "lib/hv_vhca.h"
6060
#include "lib/clock.h"
6161
#include "en/rx_res.h"
62+
#include "en/selq.h"
6263

6364
extern const struct net_device_ops mlx5e_netdev_ops;
6465
struct page_pool;
@@ -908,6 +909,7 @@ struct mlx5e_trap;
908909

909910
struct mlx5e_priv {
910911
/* priv data path fields - start */
912+
struct mlx5e_selq selq;
911913
struct mlx5e_txqsq **txq2sq;
912914
int **channel_tc2realtxq;
913915
int port_ptp_tc2realtxq[MLX5E_MAX_NUM_TC];

drivers/net/ethernet/mellanox/mlx5/core/en/qos.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -501,9 +501,11 @@ int mlx5e_htb_root_add(struct mlx5e_priv *priv, u16 htb_maj_id, u16 htb_defcls,
501501

502502
opened = test_bit(MLX5E_STATE_OPENED, &priv->state);
503503
if (opened) {
504+
mlx5e_selq_prepare(&priv->selq, &priv->channels.params, true);
505+
504506
err = mlx5e_qos_alloc_queues(priv, &priv->channels);
505507
if (err)
506-
return err;
508+
goto err_cancel_selq;
507509
}
508510

509511
root = mlx5e_sw_node_create_root(priv);
@@ -524,6 +526,9 @@ int mlx5e_htb_root_add(struct mlx5e_priv *priv, u16 htb_maj_id, u16 htb_defcls,
524526
*/
525527
smp_store_release(&priv->htb.maj_id, htb_maj_id);
526528

529+
if (opened)
530+
mlx5e_selq_apply(&priv->selq);
531+
527532
return 0;
528533

529534
err_sw_node_delete:
@@ -532,6 +537,8 @@ int mlx5e_htb_root_add(struct mlx5e_priv *priv, u16 htb_maj_id, u16 htb_defcls,
532537
err_free_queues:
533538
if (opened)
534539
mlx5e_qos_close_all_queues(&priv->channels);
540+
err_cancel_selq:
541+
mlx5e_selq_cancel(&priv->selq);
535542
return err;
536543
}
537544

@@ -542,6 +549,9 @@ int mlx5e_htb_root_del(struct mlx5e_priv *priv)
542549

543550
qos_dbg(priv->mdev, "TC_HTB_DESTROY\n");
544551

552+
mlx5e_selq_prepare(&priv->selq, &priv->channels.params, false);
553+
mlx5e_selq_apply(&priv->selq);
554+
545555
WRITE_ONCE(priv->htb.maj_id, 0);
546556
synchronize_rcu(); /* Sync with mlx5e_select_htb_queue and TX data path. */
547557

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2+
/* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3+
4+
#include "selq.h"
5+
#include <linux/slab.h>
6+
#include <linux/netdevice.h>
7+
#include "en.h"
8+
9+
struct mlx5e_selq_params {
10+
unsigned int num_regular_queues;
11+
unsigned int num_channels;
12+
unsigned int num_tcs;
13+
bool is_htb;
14+
bool is_ptp;
15+
};
16+
17+
int mlx5e_selq_init(struct mlx5e_selq *selq, struct mutex *state_lock)
18+
{
19+
struct mlx5e_selq_params *init_params;
20+
21+
selq->state_lock = state_lock;
22+
23+
selq->standby = kvzalloc(sizeof(*selq->standby), GFP_KERNEL);
24+
if (!selq->standby)
25+
return -ENOMEM;
26+
27+
init_params = kvzalloc(sizeof(*selq->active), GFP_KERNEL);
28+
if (!init_params) {
29+
kvfree(selq->standby);
30+
selq->standby = NULL;
31+
return -ENOMEM;
32+
}
33+
/* Assign dummy values, so that mlx5e_select_queue won't crash. */
34+
*init_params = (struct mlx5e_selq_params) {
35+
.num_regular_queues = 1,
36+
.num_channels = 1,
37+
.num_tcs = 1,
38+
.is_htb = false,
39+
.is_ptp = false,
40+
};
41+
rcu_assign_pointer(selq->active, init_params);
42+
43+
return 0;
44+
}
45+
46+
void mlx5e_selq_cleanup(struct mlx5e_selq *selq)
47+
{
48+
WARN_ON_ONCE(selq->is_prepared);
49+
50+
kvfree(selq->standby);
51+
selq->standby = NULL;
52+
selq->is_prepared = true;
53+
54+
mlx5e_selq_apply(selq);
55+
56+
kvfree(selq->standby);
57+
selq->standby = NULL;
58+
}
59+
60+
void mlx5e_selq_prepare(struct mlx5e_selq *selq, struct mlx5e_params *params, bool htb)
61+
{
62+
lockdep_assert_held(selq->state_lock);
63+
WARN_ON_ONCE(selq->is_prepared);
64+
65+
selq->is_prepared = true;
66+
67+
selq->standby->num_channels = params->num_channels;
68+
selq->standby->num_tcs = mlx5e_get_dcb_num_tc(params);
69+
selq->standby->num_regular_queues =
70+
selq->standby->num_channels * selq->standby->num_tcs;
71+
selq->standby->is_htb = htb;
72+
selq->standby->is_ptp = MLX5E_GET_PFLAG(params, MLX5E_PFLAG_TX_PORT_TS);
73+
}
74+
75+
void mlx5e_selq_apply(struct mlx5e_selq *selq)
76+
{
77+
struct mlx5e_selq_params *old_params;
78+
79+
WARN_ON_ONCE(!selq->is_prepared);
80+
81+
selq->is_prepared = false;
82+
83+
old_params = rcu_replace_pointer(selq->active, selq->standby,
84+
lockdep_is_held(selq->state_lock));
85+
synchronize_net(); /* Wait until ndo_select_queue starts emitting correct values. */
86+
selq->standby = old_params;
87+
}
88+
89+
void mlx5e_selq_cancel(struct mlx5e_selq *selq)
90+
{
91+
lockdep_assert_held(selq->state_lock);
92+
WARN_ON_ONCE(!selq->is_prepared);
93+
94+
selq->is_prepared = false;
95+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */
2+
/* Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
3+
4+
#ifndef __MLX5_EN_SELQ_H__
5+
#define __MLX5_EN_SELQ_H__
6+
7+
#include <linux/kernel.h>
8+
9+
struct mlx5e_selq_params;
10+
11+
struct mlx5e_selq {
12+
struct mlx5e_selq_params __rcu *active;
13+
struct mlx5e_selq_params *standby;
14+
struct mutex *state_lock; /* points to priv->state_lock */
15+
bool is_prepared;
16+
};
17+
18+
struct mlx5e_params;
19+
20+
int mlx5e_selq_init(struct mlx5e_selq *selq, struct mutex *state_lock);
21+
void mlx5e_selq_cleanup(struct mlx5e_selq *selq);
22+
void mlx5e_selq_prepare(struct mlx5e_selq *selq, struct mlx5e_params *params, bool htb);
23+
void mlx5e_selq_apply(struct mlx5e_selq *selq);
24+
void mlx5e_selq_cancel(struct mlx5e_selq *selq);
25+
26+
#endif /* __MLX5_EN_SELQ_H__ */

drivers/net/ethernet/mellanox/mlx5/core/en_main.c

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2813,6 +2813,7 @@ static int mlx5e_switch_priv_channels(struct mlx5e_priv *priv,
28132813
mlx5e_close_channels(&old_chs);
28142814
priv->profile->update_rx(priv);
28152815

2816+
mlx5e_selq_apply(&priv->selq);
28162817
out:
28172818
mlx5e_activate_priv_channels(priv);
28182819

@@ -2836,13 +2837,24 @@ int mlx5e_safe_switch_params(struct mlx5e_priv *priv,
28362837
return mlx5e_switch_priv_params(priv, params, preactivate, context);
28372838

28382839
new_chs.params = *params;
2840+
2841+
mlx5e_selq_prepare(&priv->selq, &new_chs.params, !!priv->htb.maj_id);
2842+
28392843
err = mlx5e_open_channels(priv, &new_chs);
28402844
if (err)
2841-
return err;
2845+
goto err_cancel_selq;
2846+
28422847
err = mlx5e_switch_priv_channels(priv, &new_chs, preactivate, context);
28432848
if (err)
2844-
mlx5e_close_channels(&new_chs);
2849+
goto err_close;
28452850

2851+
return 0;
2852+
2853+
err_close:
2854+
mlx5e_close_channels(&new_chs);
2855+
2856+
err_cancel_selq:
2857+
mlx5e_selq_cancel(&priv->selq);
28462858
return err;
28472859
}
28482860

@@ -2882,13 +2894,16 @@ int mlx5e_open_locked(struct net_device *netdev)
28822894
struct mlx5e_priv *priv = netdev_priv(netdev);
28832895
int err;
28842896

2897+
mlx5e_selq_prepare(&priv->selq, &priv->channels.params, !!priv->htb.maj_id);
2898+
28852899
set_bit(MLX5E_STATE_OPENED, &priv->state);
28862900

28872901
err = mlx5e_open_channels(priv, &priv->channels);
28882902
if (err)
28892903
goto err_clear_state_opened_flag;
28902904

28912905
priv->profile->update_rx(priv);
2906+
mlx5e_selq_apply(&priv->selq);
28922907
mlx5e_activate_priv_channels(priv);
28932908
mlx5e_apply_traps(priv, true);
28942909
if (priv->profile->update_carrier)
@@ -2899,6 +2914,7 @@ int mlx5e_open_locked(struct net_device *netdev)
28992914

29002915
err_clear_state_opened_flag:
29012916
clear_bit(MLX5E_STATE_OPENED, &priv->state);
2917+
mlx5e_selq_cancel(&priv->selq);
29022918
return err;
29032919
}
29042920

@@ -5215,6 +5231,7 @@ int mlx5e_priv_init(struct mlx5e_priv *priv,
52155231
struct mlx5_core_dev *mdev)
52165232
{
52175233
int nch, num_txqs, node, i;
5234+
int err;
52185235

52195236
num_txqs = netdev->num_tx_queues;
52205237
nch = mlx5e_calc_max_nch(mdev, netdev, profile);
@@ -5231,6 +5248,11 @@ int mlx5e_priv_init(struct mlx5e_priv *priv,
52315248
return -ENOMEM;
52325249

52335250
mutex_init(&priv->state_lock);
5251+
5252+
err = mlx5e_selq_init(&priv->selq, &priv->state_lock);
5253+
if (err)
5254+
goto err_free_cpumask;
5255+
52345256
hash_init(priv->htb.qos_tc2node);
52355257
INIT_WORK(&priv->update_carrier_work, mlx5e_update_carrier_work);
52365258
INIT_WORK(&priv->set_rx_mode_work, mlx5e_set_rx_mode_work);
@@ -5239,7 +5261,7 @@ int mlx5e_priv_init(struct mlx5e_priv *priv,
52395261

52405262
priv->wq = create_singlethread_workqueue("mlx5e");
52415263
if (!priv->wq)
5242-
goto err_free_cpumask;
5264+
goto err_free_selq;
52435265

52445266
priv->txq2sq = kcalloc_node(num_txqs, sizeof(*priv->txq2sq), GFP_KERNEL, node);
52455267
if (!priv->txq2sq)
@@ -5279,6 +5301,8 @@ int mlx5e_priv_init(struct mlx5e_priv *priv,
52795301
kfree(priv->txq2sq);
52805302
err_destroy_workqueue:
52815303
destroy_workqueue(priv->wq);
5304+
err_free_selq:
5305+
mlx5e_selq_cleanup(&priv->selq);
52825306
err_free_cpumask:
52835307
free_cpumask_var(priv->scratchpad.cpumask);
52845308
return -ENOMEM;
@@ -5301,6 +5325,9 @@ void mlx5e_priv_cleanup(struct mlx5e_priv *priv)
53015325
kfree(priv->tx_rates);
53025326
kfree(priv->txq2sq);
53035327
destroy_workqueue(priv->wq);
5328+
mutex_lock(&priv->state_lock);
5329+
mlx5e_selq_cleanup(&priv->selq);
5330+
mutex_unlock(&priv->state_lock);
53045331
free_cpumask_var(priv->scratchpad.cpumask);
53055332

53065333
for (i = 0; i < priv->htb.max_qos_sqs; i++)

0 commit comments

Comments
 (0)