mlxsw: spectrum: Limit number of FDB records per learning session
authorIdo Schimmel <idosch@mellanox.com>
Wed, 24 Aug 2016 10:00:23 +0000 (12:00 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 24 Aug 2016 16:41:11 +0000 (09:41 -0700)
Up until now a learning session ended whenever the number of queried
records was zero. This turned out to be problematic in situations where
a large number of MACs (48K) had to be processed by the switch driver,
as RTNL mutex is held during the learning session.

Instead, limit the number of FDB records that can be processed in a
session to 64. This means that every time the device is queried for
learning notifications (currently, every 100ms), up to 64 records will
be processed by the switch driver.

Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@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 1721098eef131773471bb99aa281f7959ff817ff..b83d0a7a0b49b2f30bea1af97eea5dc093e2b97d 100644 (file)
@@ -591,6 +591,12 @@ static const struct mlxsw_reg_info mlxsw_reg_sfn = {
  */
 MLXSW_ITEM32(reg, sfn, swid, 0x00, 24, 8);
 
+/* reg_sfn_end
+ * Forces the current session to end.
+ * Access: OP
+ */
+MLXSW_ITEM32(reg, sfn, end, 0x04, 20, 1);
+
 /* reg_sfn_num_rec
  * Request: Number of learned notifications and aged-out notification
  * records requested.
@@ -605,6 +611,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_num_rec_set(payload, MLXSW_REG_SFN_REC_MAX_COUNT);
 }
 
index d1b59cdfacc13824a642f0db6ffcd4c05678d4ef..02de24080e792bd1baf4309e907b8e110ee9455f 100644 (file)
@@ -1496,20 +1496,18 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
        mlxsw_sp = container_of(work, struct mlxsw_sp, fdb_notify.dw.work);
 
        rtnl_lock();
-       do {
-               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");
-                       break;
-               }
-               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);
+       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);
 
-       } while (num_rec);
+out:
        rtnl_unlock();
-
        kfree(sfn_pl);
        mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp);
 }