aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Schimmel <idosch@mellanox.com>2016-01-10 03:32:16 -0500
committerDavid S. Miller <davem@davemloft.net>2016-01-11 00:21:19 -0500
commit366ce60315292a579b8ceae2777102e1954a2024 (patch)
tree2429a281a92e136cb22f4444f8d08ffdb49f19c8
parent712f4aad406bb1ed67f3f98d04c044191f0ff593 (diff)
mlxsw: spectrum: Add FDB lock to prevent session interleaving
Dumping the FDB (invoked with a process context) or handling FDB notifications (polled periodicly in delayed work) might each entail multiple EMAD transcations due to the number of entries. While we only allow one EMAD transaction at a time, there is nothing stopping the dump and notification processing sessions from interleaving. However, this is forbidden by the hardware, so we need to make sure only one of these sessions can run at a time. Solve this by adding a mutex ('fdb_lock'), as both kernel threads can sleep while waiting for the response EMAD. Fixes: 56ade8fe3f ("mlxsw: spectrum: Add initial support for Spectrum ASIC") 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>
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c5
2 files changed, 6 insertions, 0 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 4365c8bccc6d..69281ca534b1 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -63,6 +63,7 @@ struct mlxsw_sp {
63 } fdb_notify; 63 } fdb_notify;
64#define MLXSW_SP_DEFAULT_AGEING_TIME 300 64#define MLXSW_SP_DEFAULT_AGEING_TIME 300
65 u32 ageing_time; 65 u32 ageing_time;
66 struct mutex fdb_lock; /* Make sure FDB sessions are atomic. */
66 struct { 67 struct {
67 struct net_device *dev; 68 struct net_device *dev;
68 unsigned int ref_count; 69 unsigned int ref_count;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
index 617fb22b5d81..80e266063aee 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
@@ -650,6 +650,7 @@ static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port,
650 if (!sfd_pl) 650 if (!sfd_pl)
651 return -ENOMEM; 651 return -ENOMEM;
652 652
653 mutex_lock(&mlxsw_sp_port->mlxsw_sp->fdb_lock);
653 mlxsw_reg_sfd_pack(sfd_pl, MLXSW_REG_SFD_OP_QUERY_DUMP, 0); 654 mlxsw_reg_sfd_pack(sfd_pl, MLXSW_REG_SFD_OP_QUERY_DUMP, 0);
654 do { 655 do {
655 mlxsw_reg_sfd_num_rec_set(sfd_pl, MLXSW_REG_SFD_REC_MAX_COUNT); 656 mlxsw_reg_sfd_num_rec_set(sfd_pl, MLXSW_REG_SFD_REC_MAX_COUNT);
@@ -684,6 +685,7 @@ static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port,
684 } while (num_rec == MLXSW_REG_SFD_REC_MAX_COUNT); 685 } while (num_rec == MLXSW_REG_SFD_REC_MAX_COUNT);
685 686
686out: 687out:
688 mutex_unlock(&mlxsw_sp_port->mlxsw_sp->fdb_lock);
687 kfree(sfd_pl); 689 kfree(sfd_pl);
688 return stored_err ? stored_err : err; 690 return stored_err ? stored_err : err;
689} 691}
@@ -812,6 +814,7 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
812 814
813 mlxsw_sp = container_of(work, struct mlxsw_sp, fdb_notify.dw.work); 815 mlxsw_sp = container_of(work, struct mlxsw_sp, fdb_notify.dw.work);
814 816
817 mutex_lock(&mlxsw_sp->fdb_lock);
815 do { 818 do {
816 mlxsw_reg_sfn_pack(sfn_pl); 819 mlxsw_reg_sfn_pack(sfn_pl);
817 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl); 820 err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(sfn), sfn_pl);
@@ -824,6 +827,7 @@ static void mlxsw_sp_fdb_notify_work(struct work_struct *work)
824 mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i); 827 mlxsw_sp_fdb_notify_rec_process(mlxsw_sp, sfn_pl, i);
825 828
826 } while (num_rec); 829 } while (num_rec);
830 mutex_unlock(&mlxsw_sp->fdb_lock);
827 831
828 kfree(sfn_pl); 832 kfree(sfn_pl);
829 mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); 833 mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp);
@@ -838,6 +842,7 @@ static int mlxsw_sp_fdb_init(struct mlxsw_sp *mlxsw_sp)
838 dev_err(mlxsw_sp->bus_info->dev, "Failed to set default ageing time\n"); 842 dev_err(mlxsw_sp->bus_info->dev, "Failed to set default ageing time\n");
839 return err; 843 return err;
840 } 844 }
845 mutex_init(&mlxsw_sp->fdb_lock);
841 INIT_DELAYED_WORK(&mlxsw_sp->fdb_notify.dw, mlxsw_sp_fdb_notify_work); 846 INIT_DELAYED_WORK(&mlxsw_sp->fdb_notify.dw, mlxsw_sp_fdb_notify_work);
842 mlxsw_sp->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL; 847 mlxsw_sp->fdb_notify.interval = MLXSW_SP_DEFAULT_LEARNING_INTERVAL;
843 mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp); 848 mlxsw_sp_fdb_notify_work_schedule(mlxsw_sp);