The only reason why the rtnl_lock is held in the dpaa2_switch_event_work() is so that there is no concurency between the changeupper notifier which manages the per port FDB assignment and the workqueue which adds / deletes addresses into that forwarding database. To avoid this kind of concurency without a rtnl_lock, flush the event workqueue as the last step from the pre_bridge_leave so that any in-flight operations targeting the current FDB are finalized before the bridge layout (and the per port FDB assignment) changes. Signed-off-by: Ioana Ciornei --- Changes in v4: - New patch. --- drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c index d70e6f06ac15..67c639fad0db 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c @@ -2069,7 +2069,15 @@ static int dpaa2_switch_port_restore_rxvlan(struct net_device *vdev, int vid, vo static void dpaa2_switch_port_pre_bridge_leave(struct net_device *netdev) { + struct ethsw_port_priv *port_priv = netdev_priv(netdev); + struct ethsw_core *ethsw = port_priv->ethsw_data; + switchdev_bridge_port_unoffload(netdev, NULL, NULL, NULL); + + /* Make sure that any FDB add/del operations are completed before the + * bridge layout changes + */ + flush_workqueue(ethsw->workqueue); } static int dpaa2_switch_port_bridge_leave(struct net_device *netdev) @@ -2281,7 +2289,6 @@ static void dpaa2_switch_event_work(struct work_struct *work) struct switchdev_notifier_fdb_info *fdb_info; int err; - rtnl_lock(); fdb_info = &switchdev_work->fdb_info; switch (switchdev_work->event) { @@ -2310,7 +2317,6 @@ static void dpaa2_switch_event_work(struct work_struct *work) break; } - rtnl_unlock(); kfree(switchdev_work->fdb_info.addr); kfree(switchdev_work); dev_put(dev); -- 2.25.1