Commit 648e53ca authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller

mlxsw: spectrum_switchdev: Optimize SFN records processing

Currently, only one SFN query is done from repetitive work at a time,
processing 64 entries. Another work iteration is scheduled in 100ms,
that means that the max rate of learned FDB entries is limited to 6400/s.
That is slow. Fix this by doing 2 optimizations:
1) Run 10 SFN queries at a time.
2) In case the SFN is not drained, schedule work with 0 delay to allow
   to continue processing rest of the records.

On a testing setup with 500K entries the time to process decreased
from 870secs to 10secs.
Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Tested-by: default avatarAlex Kushnarov <alexanderk@mellanox.com>
Signed-off-by: default avatarIdo Schimmel <idosch@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c535f920
...@@ -621,7 +621,7 @@ static inline void mlxsw_reg_sfn_pack(char *payload) ...@@ -621,7 +621,7 @@ static inline void mlxsw_reg_sfn_pack(char *payload)
{ {
MLXSW_REG_ZERO(sfn, payload); MLXSW_REG_ZERO(sfn, payload);
mlxsw_reg_sfn_swid_set(payload, 0); mlxsw_reg_sfn_swid_set(payload, 0);
mlxsw_reg_sfn_end_set(payload, 1); mlxsw_reg_sfn_end_set(payload, 0);
mlxsw_reg_sfn_num_rec_set(payload, MLXSW_REG_SFN_REC_MAX_COUNT); mlxsw_reg_sfn_num_rec_set(payload, MLXSW_REG_SFN_REC_MAX_COUNT);
} }
......
...@@ -2674,19 +2674,24 @@ static void mlxsw_sp_fdb_notify_rec_process(struct mlxsw_sp *mlxsw_sp, ...@@ -2674,19 +2674,24 @@ static void mlxsw_sp_fdb_notify_rec_process(struct mlxsw_sp *mlxsw_sp,
} }
} }
static void mlxsw_sp_fdb_notify_work_schedule(struct mlxsw_sp *mlxsw_sp) static void mlxsw_sp_fdb_notify_work_schedule(struct mlxsw_sp *mlxsw_sp,
bool no_delay)
{ {
struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge; struct mlxsw_sp_bridge *bridge = mlxsw_sp->bridge;
unsigned int interval = no_delay ? 0 : bridge->fdb_notify.interval;
mlxsw_core_schedule_dw(&bridge->fdb_notify.dw, mlxsw_core_schedule_dw(&bridge->fdb_notify.dw,
msecs_to_jiffies(bridge->fdb_notify.interval)); msecs_to_jiffies(interval));
} }
#define MLXSW_SP_FDB_SFN_QUERIES_PER_SESSION 10
static void mlxsw_sp_fdb_notify_work(struct work_struct *work) static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
{ {
struct mlxsw_sp_bridge *bridge; struct mlxsw_sp_bridge *bridge;
struct mlxsw_sp *mlxsw_sp; struct mlxsw_sp *mlxsw_sp;
char *sfn_pl; char *sfn_pl;
int queries;
u8 num_rec; u8 num_rec;
int i; int i;
int err; int err;
...@@ -2699,20 +2704,26 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work) ...@@ -2699,20 +2704,26 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
mlxsw_sp = bridge->mlxsw_sp; mlxsw_sp = bridge->mlxsw_sp;
rtnl_lock(); rtnl_lock();
mlxsw_reg_sfn_pack(sfn_pl); queries = MLXSW_SP_FDB_SFN_QUERIES_PER_SESSION;
err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl); while (queries > 0) {
if (err) { mlxsw_reg_sfn_pack(sfn_pl);
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get FDB notifications\n"); err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl);
goto out; if (err) {
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get FDB notifications\n");
goto out;
}
num_rec = mlxsw_reg_sfn_num_rec_get(sfn_pl);
for (i = 0; i < num_rec; i++)
mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i);
if (num_rec != MLXSW_REG_SFN_REC_MAX_COUNT)
goto out;
queries--;
} }
num_rec = mlxsw_reg_sfn_num_rec_get(sfn_pl);
for (i = 0; i < num_rec; i++)
mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i);
out: out:
rtnl_unlock(); rtnl_unlock();
kfree(sfn_pl); kfree(sfn_pl);
mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp, !queries);
} }
struct mlxsw_sp_switchdev_event_work { struct mlxsw_sp_switchdev_event_work {
...@@ -3458,7 +3469,7 @@ static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp) ...@@ -3458,7 +3469,7 @@ static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp)
INIT_DELAYED_WORK(&bridge->fdb_notify.dw, mlxsw_sp_fdb_notify_work); INIT_DELAYED_WORK(&bridge->fdb_notify.dw, mlxsw_sp_fdb_notify_work);
bridge->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL; bridge->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL;
mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp, false);
return 0; return 0;
err_register_switchdev_blocking_notifier: err_register_switchdev_blocking_notifier:
......
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