mlxsw: spectrum_switchdev: Optimize SFN records processing
authorJiri Pirko <jiri@mellanox.com>
Wed, 26 Feb 2020 08:39:17 +0000 (09:39 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 27 Feb 2020 04:44:42 +0000 (20:44 -0800)
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: Jiri Pirko <jiri@mellanox.com>
Tested-by: Alex Kushnarov <alexanderk@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/reg.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c

index e22cea9..26ac0a5 100644 (file)
@@ -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);
 }
 
index 339c69d..a26162b 100644 (file)
@@ -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,20 +2704,26 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
        mlxsw_sp = bridge->mlxsw_sp;
 
        rtnl_lock();
-       mlxsw_reg_sfn_pack(sfn_pl);
-       err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl);
-       if (err) {
-               dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get FDB notifications\n");
-               goto out;
+       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) {
+                       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:
        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: