diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 9594e9d215e86..5d673363154b4 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -1398,7 +1398,7 @@ int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, return 0; } -static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) +int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) { enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; u16 vid, last_visited_vid; @@ -1428,7 +1428,7 @@ static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) return err; } -static int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) +int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) { enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; u16 vid; @@ -1501,16 +1501,6 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev, if (!mlxsw_sp_vport) return -ENOMEM; - /* When adding the first VLAN interface on a bridged port we need to - * transition all the active 802.1Q bridge VLANs to use explicit - * {Port, VID} to FID mappings and set the port's mode to Virtual mode. - */ - if (list_is_singular(&mlxsw_sp_port->vports_list)) { - err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); - if (err) - goto err_port_vp_mode_trans; - } - err = mlxsw_sp_port_vlan_set(mlxsw_sp_vport, vid, vid, true, untagged); if (err) goto err_port_add_vid; @@ -1518,9 +1508,6 @@ static int mlxsw_sp_port_add_vid(struct net_device *dev, return 0; err_port_add_vid: - if (list_is_singular(&mlxsw_sp_port->vports_list)) - mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); -err_port_vp_mode_trans: mlxsw_sp_port_vport_destroy(mlxsw_sp_vport); return err; } @@ -1551,13 +1538,6 @@ static int mlxsw_sp_port_kill_vid(struct net_device *dev, if (f && !WARN_ON(!f->leave)) f->leave(mlxsw_sp_vport); - /* When removing the last VLAN interface on a bridged port we need to - * transition all active 802.1Q bridge VLANs to use VID to FID - * mappings and set port's mode to VLAN mode. - */ - if (list_is_singular(&mlxsw_sp_port->vports_list)) - mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); - mlxsw_sp_port_vport_destroy(mlxsw_sp_vport); return 0; @@ -4382,9 +4362,12 @@ static int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port) { int err; - err = mlxsw_sp_port_stp_set(mlxsw_sp_port, true); + err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); if (err) return err; + err = mlxsw_sp_port_stp_set(mlxsw_sp_port, true); + if (err) + goto err_port_stp_set; err = mlxsw_sp_port_vlan_set(mlxsw_sp_port, 2, VLAN_N_VID - 1, true, false); if (err) @@ -4393,6 +4376,8 @@ static int mlxsw_sp_port_ovs_join(struct mlxsw_sp_port *mlxsw_sp_port) err_port_vlan_set: mlxsw_sp_port_stp_set(mlxsw_sp_port, false); +err_port_stp_set: + mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); return err; } @@ -4401,6 +4386,7 @@ static void mlxsw_sp_port_ovs_leave(struct mlxsw_sp_port *mlxsw_sp_port) mlxsw_sp_port_vlan_set(mlxsw_sp_port, 2, VLAN_N_VID - 1, false, false); mlxsw_sp_port_stp_set(mlxsw_sp_port, false); + mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); } static int mlxsw_sp_netdevice_port_upper_event(struct net_device *dev, @@ -4695,6 +4681,7 @@ static int mlxsw_sp_vport_fid_map(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid, static int mlxsw_sp_vport_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport, struct net_device *br_dev) { + struct mlxsw_sp_port *mlxsw_sp_port; struct mlxsw_sp_fid *f; int err; @@ -4713,6 +4700,13 @@ static int mlxsw_sp_vport_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport, if (err) goto err_vport_fid_map; + mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); + if (mlxsw_sp_port->nr_port_vid_map++ == 0) { + err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); + if (err) + goto err_port_vp_mode_trans; + } + mlxsw_sp_vport_fid_set(mlxsw_sp_vport, f); f->ref_count++; @@ -4720,6 +4714,9 @@ static int mlxsw_sp_vport_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport, return 0; +err_port_vp_mode_trans: + mlxsw_sp_port->nr_port_vid_map--; + mlxsw_sp_vport_fid_map(mlxsw_sp_vport, f->fid, false); err_vport_fid_map: mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, false); err_vport_flood_set: @@ -4731,17 +4728,25 @@ static int mlxsw_sp_vport_vfid_join(struct mlxsw_sp_port *mlxsw_sp_vport, static void mlxsw_sp_vport_vfid_leave(struct mlxsw_sp_port *mlxsw_sp_vport) { struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); + struct mlxsw_sp_port *mlxsw_sp_port; netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid); + mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); + f->ref_count--; + + mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); + if (mlxsw_sp_port->nr_port_vid_map == 1) + mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); + mlxsw_sp_port->nr_port_vid_map--; + mlxsw_sp_vport_fid_map(mlxsw_sp_vport, f->fid, false); mlxsw_sp_vport_flood_set(mlxsw_sp_vport, f->fid, false); mlxsw_sp_port_fdb_flush(mlxsw_sp_vport, f->fid); - mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); - if (--f->ref_count == 0) + if (f->ref_count == 0) mlxsw_sp_vfid_destroy(mlxsw_sp_vport->mlxsw_sp, f); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 7caf175211a81..277a432af3196 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -253,6 +253,7 @@ struct mlxsw_sp_port { struct delayed_work update_dw; } hw_stats; struct mlxsw_sp_port_sample *sample; + unsigned int nr_port_vid_map; /* {Port, VID} => FID mappings */ }; bool mlxsw_sp_port_dev_check(const struct net_device *dev); @@ -343,6 +344,14 @@ mlxsw_sp_port_vport_find_by_fid(const struct mlxsw_sp_port *mlxsw_sp_port, return NULL; } +static inline struct mlxsw_sp_port * +mlxsw_sp_vport_port(const struct mlxsw_sp_port *mlxsw_sp_vport) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; + + return mlxsw_sp->ports[mlxsw_sp_vport->local_port]; +} + static inline struct mlxsw_sp_fid *mlxsw_sp_fid_find(struct mlxsw_sp *mlxsw_sp, u16 fid) { @@ -446,6 +455,8 @@ int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, bool learn_enable); int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); +int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port); +int mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port); #ifdef CONFIG_MLXSW_SPECTRUM_DCB diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 8165b1148bcea..cb5e86ad0f666 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -3111,6 +3111,7 @@ static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport, { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_vport->mlxsw_sp; u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); + struct mlxsw_sp_port *mlxsw_sp_port; struct mlxsw_sp_rif *rif; int err; @@ -3130,6 +3131,13 @@ static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport, if (err) goto err_port_vid_stp_set; + mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); + if (mlxsw_sp_port->nr_port_vid_map++ == 0) { + err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); + if (err) + goto err_port_vp_mode_trans; + } + mlxsw_sp_vport_fid_set(mlxsw_sp_vport, rif->f); rif->f->ref_count++; @@ -3137,6 +3145,9 @@ static int mlxsw_sp_vport_rif_sp_join(struct mlxsw_sp_port *mlxsw_sp_vport, return 0; +err_port_vp_mode_trans: + mlxsw_sp_port->nr_port_vid_map--; + mlxsw_sp_port_vid_stp_set(mlxsw_sp_vport, vid, BR_STATE_BLOCKING); err_port_vid_stp_set: mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true); err_port_vid_learning_set: @@ -3149,13 +3160,21 @@ static void mlxsw_sp_vport_rif_sp_leave(struct mlxsw_sp_port *mlxsw_sp_vport) { struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport); u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_vport); + struct mlxsw_sp_port *mlxsw_sp_port; netdev_dbg(mlxsw_sp_vport->dev, "Left FID=%d\n", f->fid); + f->ref_count--; + mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); + + mlxsw_sp_port = mlxsw_sp_vport_port(mlxsw_sp_vport); + if (mlxsw_sp_port->nr_port_vid_map == 1) + mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); + mlxsw_sp_port->nr_port_vid_map--; mlxsw_sp_port_vid_stp_set(mlxsw_sp_vport, vid, BR_STATE_BLOCKING); mlxsw_sp_port_vid_learning_set(mlxsw_sp_vport, vid, true); - mlxsw_sp_vport_fid_set(mlxsw_sp_vport, NULL); - if (--f->ref_count == 0) + + if (f->ref_count == 0) mlxsw_sp_vport_rif_sp_destroy(mlxsw_sp_vport, f->rif); } diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index ea0f4a5787c38..0d173bebcf3a6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -617,7 +617,7 @@ static int mlxsw_sp_port_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid, /* If port doesn't have vPorts, then it can use the global * VID-to-FID mapping. */ - if (list_empty(&mlxsw_sp_port->vports_list)) + if (mlxsw_sp_port->nr_port_vid_map == 0) return 0; return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, valid, fid, fid);