Skip to content

Commit a261414

Browse files
vladimirolteandavem330
authored andcommitted
net: dsa: mv88e6xxx: flush switchdev FDB workqueue before removing VLAN
mv88e6xxx is special among DSA drivers in that it requires the VTU to contain the VID of the FDB entry it modifies in mv88e6xxx_port_db_load_purge(), otherwise it will return -EOPNOTSUPP. Sometimes due to races this is not always satisfied even if external code does everything right (first deletes the FDB entries, then the VLAN), because DSA commits to hardware FDB entries asynchronously since commit c9eb3e0 ("net: dsa: Add support for learning FDB through notification"). Therefore, the mv88e6xxx driver must close this race condition by itself, by asking DSA to flush the switchdev workqueue of any FDB deletions in progress, prior to exiting a VLAN. Fixes: c9eb3e0 ("net: dsa: Add support for learning FDB through notification") Reported-by: Rafael Richter <rafael.richter@gin.de> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 26394fc commit a261414

File tree

4 files changed

+9
-1
lines changed

4 files changed

+9
-1
lines changed

drivers/net/dsa/mv88e6xxx/chip.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,6 +2284,13 @@ static int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
22842284
if (!mv88e6xxx_max_vid(chip))
22852285
return -EOPNOTSUPP;
22862286

2287+
/* The ATU removal procedure needs the FID to be mapped in the VTU,
2288+
* but FDB deletion runs concurrently with VLAN deletion. Flush the DSA
2289+
* switchdev workqueue to ensure that all FDB entries are deleted
2290+
* before we remove the VLAN.
2291+
*/
2292+
dsa_flush_workqueue();
2293+
22872294
mv88e6xxx_reg_lock(chip);
22882295

22892296
err = mv88e6xxx_port_get_pvid(chip, port, &pvid);

include/net/dsa.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,6 +1187,7 @@ void dsa_unregister_switch(struct dsa_switch *ds);
11871187
int dsa_register_switch(struct dsa_switch *ds);
11881188
void dsa_switch_shutdown(struct dsa_switch *ds);
11891189
struct dsa_switch *dsa_switch_find(int tree_index, int sw_index);
1190+
void dsa_flush_workqueue(void);
11901191
#ifdef CONFIG_PM_SLEEP
11911192
int dsa_switch_suspend(struct dsa_switch *ds);
11921193
int dsa_switch_resume(struct dsa_switch *ds);

net/dsa/dsa.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ void dsa_flush_workqueue(void)
349349
{
350350
flush_workqueue(dsa_owq);
351351
}
352+
EXPORT_SYMBOL_GPL(dsa_flush_workqueue);
352353

353354
int dsa_devlink_param_get(struct devlink *dl, u32 id,
354355
struct devlink_param_gset_ctx *ctx)

net/dsa/dsa_priv.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,6 @@ void dsa_tag_driver_put(const struct dsa_device_ops *ops);
147147
const struct dsa_device_ops *dsa_find_tagger_by_name(const char *buf);
148148

149149
bool dsa_schedule_work(struct work_struct *work);
150-
void dsa_flush_workqueue(void);
151150
const char *dsa_tag_protocol_to_str(const struct dsa_device_ops *ops);
152151

153152
static inline int dsa_tag_protocol_overhead(const struct dsa_device_ops *ops)

0 commit comments

Comments
 (0)