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

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -621,7 +621,7 @@ static inline void mlxsw_reg_sfn_pack(char *payload)
{
	MLXSW_REG_ZERO(sfn, payload);
	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);
}

+23 −12
Original line number Diff line number Diff line
@@ -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;
	unsigned int interval = no_delay ? 0 : bridge->fdb_notify.interval;

	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)
{
	struct mlxsw_sp_bridge *bridge;
	struct mlxsw_sp *mlxsw_sp;
	char *sfn_pl;
	int queries;
	u8 num_rec;
	int i;
	int err;
@@ -2699,6 +2704,8 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
	mlxsw_sp = bridge->mlxsw_sp;

	rtnl_lock();
	queries = MLXSW_SP_FDB_SFN_QUERIES_PER_SESSION;
	while (queries > 0) {
		mlxsw_reg_sfn_pack(sfn_pl);
		err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl);
		if (err) {
@@ -2708,11 +2715,15 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
		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--;
	}

out:
	rtnl_unlock();
	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 {
@@ -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);
	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;

err_register_switchdev_blocking_notifier: