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;
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;
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;
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;
}
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;
{
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)
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;
}
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,
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;
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++;
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:
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);
}
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);
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)
{
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
{
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;
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++;
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:
{
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);
}