mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08:00
Merge branch 'mlxsw-next'
Jiri Pirko says: ==================== mlxsw: Preparation for IPv4 router Ido says: This series prepares the driver for IPv4 router support. The router follow-up patches are available at: https://github.com/jpirko/linux_mlxsw/tree/net-next_queue Patches 1-9 simplify the netdevice notification block and also add several checks during PRECHANGEUPPER events against topologies that aren't supported by the device. This will ensure L3 interfaces are only configured on top of valid netdevs. Patches 10-13 contain trivial changes required for the introduction of a generic FID struct - currently only used for vFIDs - in patch 14. Making the FID struct generic will allow us to easily associate the underlying FIDs with their L3-counterparts - Router interfaces (RIFs): FID Type | Used by | RIF Type -------------------------------------------------------- FID | The VLAN-aware bridge | VLAN vFID | VLAN-unaware bridges | FID rFID | non-bridged netdevs (follow-up) | Sub-port Obligatory ASCII art to visualize the above: A.B.C.D + | FID RIF + br0 E.F.G.H + + | | VLAN RIF +---------+---------+ + | | br1.W | vFID | + | | | vPort +-+-+ +-+-+ + swXpY.Z | | | | br1 +-+-+ +-+-+ + | | FID=W | | | +------------+------------+ | | | | +---+---+ +---+-+-+ +---+---+ | | | | | | | | | | | | | | | | | | +-------+ +-------+ +-------+ swXpY Patches 15-16 further generalize the struct by exploiting the fact that the FID is a shared resource among ports. Each FID type is assigned a 'leave' function that is invoked based on CHANGEUPPER events and takes care of the necessary clean-up. Patches 17-22 build upon the previous patches and use the FID struct for the VLAN-aware bridge and take care of cleaning up FID resources in the 'leave' functions. For now, these are only FDB records, but later on we'll have to remove the RIFs associated with these FIDs, which will in turn take care of routes and neighbours clean-up. The last patch adds debug prints that proved very useful during the development of this series. Tested with the existing L2 recipes: https://github.com/jpirko/lnst/tree/master/recipes/switchdev ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
0e9390ebf1
File diff suppressed because it is too large
Load Diff
@ -87,11 +87,12 @@ struct mlxsw_sp_upper {
|
||||
unsigned int ref_count;
|
||||
};
|
||||
|
||||
struct mlxsw_sp_vfid {
|
||||
struct mlxsw_sp_fid {
|
||||
void (*leave)(struct mlxsw_sp_port *mlxsw_sp_vport);
|
||||
struct list_head list;
|
||||
u16 nr_vports;
|
||||
u16 vfid; /* Starting at 0 */
|
||||
struct net_device *br_dev;
|
||||
unsigned int ref_count;
|
||||
struct net_device *dev;
|
||||
u16 fid;
|
||||
u16 vid;
|
||||
};
|
||||
|
||||
@ -155,17 +156,17 @@ struct mlxsw_sp_sb {
|
||||
struct mlxsw_sp {
|
||||
struct {
|
||||
struct list_head list;
|
||||
unsigned long mapped[BITS_TO_LONGS(MLXSW_SP_VFID_PORT_MAX)];
|
||||
DECLARE_BITMAP(mapped, MLXSW_SP_VFID_PORT_MAX);
|
||||
} port_vfids;
|
||||
struct {
|
||||
struct list_head list;
|
||||
unsigned long mapped[BITS_TO_LONGS(MLXSW_SP_VFID_BR_MAX)];
|
||||
DECLARE_BITMAP(mapped, MLXSW_SP_VFID_BR_MAX);
|
||||
} br_vfids;
|
||||
struct {
|
||||
struct list_head list;
|
||||
unsigned long mapped[BITS_TO_LONGS(MLXSW_SP_MID_MAX)];
|
||||
DECLARE_BITMAP(mapped, MLXSW_SP_MID_MAX);
|
||||
} br_mids;
|
||||
unsigned long active_fids[BITS_TO_LONGS(VLAN_N_VID)];
|
||||
struct list_head fids; /* VLAN-aware bridge FIDs */
|
||||
struct mlxsw_sp_port **ports;
|
||||
struct mlxsw_core *core;
|
||||
const struct mlxsw_bus_info *bus_info;
|
||||
@ -217,7 +218,7 @@ struct mlxsw_sp_port {
|
||||
u16 lag_id;
|
||||
struct {
|
||||
struct list_head list;
|
||||
struct mlxsw_sp_vfid *vfid;
|
||||
struct mlxsw_sp_fid *f;
|
||||
u16 vid;
|
||||
} vport;
|
||||
struct {
|
||||
@ -259,28 +260,38 @@ mlxsw_sp_port_lagged_get(struct mlxsw_sp *mlxsw_sp, u16 lag_id, u8 port_index)
|
||||
return mlxsw_sp_port && mlxsw_sp_port->lagged ? mlxsw_sp_port : NULL;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
mlxsw_sp_port_is_vport(const struct mlxsw_sp_port *mlxsw_sp_port)
|
||||
{
|
||||
return mlxsw_sp_port->vport.vfid;
|
||||
}
|
||||
|
||||
static inline struct net_device *
|
||||
mlxsw_sp_vport_br_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
|
||||
{
|
||||
return mlxsw_sp_vport->vport.vfid->br_dev;
|
||||
}
|
||||
|
||||
static inline u16
|
||||
mlxsw_sp_vport_vid_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
|
||||
{
|
||||
return mlxsw_sp_vport->vport.vid;
|
||||
}
|
||||
|
||||
static inline u16
|
||||
mlxsw_sp_vport_vfid_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
|
||||
static inline bool
|
||||
mlxsw_sp_port_is_vport(const struct mlxsw_sp_port *mlxsw_sp_port)
|
||||
{
|
||||
return mlxsw_sp_vport->vport.vfid->vfid;
|
||||
u16 vid = mlxsw_sp_vport_vid_get(mlxsw_sp_port);
|
||||
|
||||
return vid != 0;
|
||||
}
|
||||
|
||||
static inline void mlxsw_sp_vport_fid_set(struct mlxsw_sp_port *mlxsw_sp_vport,
|
||||
struct mlxsw_sp_fid *f)
|
||||
{
|
||||
mlxsw_sp_vport->vport.f = f;
|
||||
}
|
||||
|
||||
static inline struct mlxsw_sp_fid *
|
||||
mlxsw_sp_vport_fid_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
|
||||
{
|
||||
return mlxsw_sp_vport->vport.f;
|
||||
}
|
||||
|
||||
static inline struct net_device *
|
||||
mlxsw_sp_vport_br_get(const struct mlxsw_sp_port *mlxsw_sp_vport)
|
||||
{
|
||||
struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
|
||||
|
||||
return f ? f->dev : NULL;
|
||||
}
|
||||
|
||||
static inline struct mlxsw_sp_port *
|
||||
@ -298,14 +309,16 @@ mlxsw_sp_port_vport_find(const struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
|
||||
}
|
||||
|
||||
static inline struct mlxsw_sp_port *
|
||||
mlxsw_sp_port_vport_find_by_vfid(const struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
u16 vfid)
|
||||
mlxsw_sp_port_vport_find_by_fid(const struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
u16 fid)
|
||||
{
|
||||
struct mlxsw_sp_port *mlxsw_sp_vport;
|
||||
|
||||
list_for_each_entry(mlxsw_sp_vport, &mlxsw_sp_port->vports_list,
|
||||
vport.list) {
|
||||
if (mlxsw_sp_vport_vfid_get(mlxsw_sp_vport) == vfid)
|
||||
struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_vport);
|
||||
|
||||
if (f && f->fid == fid)
|
||||
return mlxsw_sp_vport;
|
||||
}
|
||||
|
||||
@ -366,10 +379,11 @@ int mlxsw_sp_port_add_vid(struct net_device *dev, __be16 __always_unused proto,
|
||||
u16 vid);
|
||||
int mlxsw_sp_port_kill_vid(struct net_device *dev,
|
||||
__be16 __always_unused proto, u16 vid);
|
||||
int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 vfid,
|
||||
bool set, bool only_uc);
|
||||
int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid,
|
||||
bool set);
|
||||
void mlxsw_sp_port_active_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port);
|
||||
int mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid);
|
||||
int mlxsw_sp_port_fdb_flush(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid);
|
||||
int mlxsw_sp_port_ets_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
enum mlxsw_reg_qeec_hr hr, u8 index, u8 next_index,
|
||||
bool dwrr, u8 dwrr_weight);
|
||||
|
@ -55,13 +55,10 @@
|
||||
static u16 mlxsw_sp_port_vid_to_fid_get(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
u16 vid)
|
||||
{
|
||||
struct mlxsw_sp_fid *f = mlxsw_sp_vport_fid_get(mlxsw_sp_port);
|
||||
u16 fid = vid;
|
||||
|
||||
if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) {
|
||||
u16 vfid = mlxsw_sp_vport_vfid_get(mlxsw_sp_port);
|
||||
|
||||
fid = mlxsw_sp_vfid_to_fid(vfid);
|
||||
}
|
||||
fid = f ? f->fid : fid;
|
||||
|
||||
if (!fid)
|
||||
fid = mlxsw_sp_port->pvid;
|
||||
@ -236,7 +233,8 @@ static int mlxsw_sp_port_uc_flood_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
int err;
|
||||
|
||||
if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) {
|
||||
u16 vfid = mlxsw_sp_vport_vfid_get(mlxsw_sp_port);
|
||||
u16 fid = mlxsw_sp_vport_fid_get(mlxsw_sp_port)->fid;
|
||||
u16 vfid = mlxsw_sp_fid_to_vfid(fid);
|
||||
|
||||
return __mlxsw_sp_port_flood_set(mlxsw_sp_port, vfid, vfid,
|
||||
set, true);
|
||||
@ -260,14 +258,17 @@ err_port_flood_set:
|
||||
return err;
|
||||
}
|
||||
|
||||
int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 vfid,
|
||||
bool set, bool only_uc)
|
||||
int mlxsw_sp_vport_flood_set(struct mlxsw_sp_port *mlxsw_sp_vport, u16 fid,
|
||||
bool set)
|
||||
{
|
||||
u16 vfid;
|
||||
|
||||
/* In case of vFIDs, index into the flooding table is relative to
|
||||
* the start of the vFIDs range.
|
||||
*/
|
||||
vfid = mlxsw_sp_fid_to_vfid(fid);
|
||||
return __mlxsw_sp_port_flood_set(mlxsw_sp_vport, vfid, vfid, set,
|
||||
only_uc);
|
||||
false);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
@ -383,6 +384,198 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev,
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct mlxsw_sp_fid *mlxsw_sp_fid_find(struct mlxsw_sp *mlxsw_sp,
|
||||
u16 fid)
|
||||
{
|
||||
struct mlxsw_sp_fid *f;
|
||||
|
||||
list_for_each_entry(f, &mlxsw_sp->fids, list)
|
||||
if (f->fid == fid)
|
||||
return f;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid, bool create)
|
||||
{
|
||||
char sfmr_pl[MLXSW_REG_SFMR_LEN];
|
||||
|
||||
mlxsw_reg_sfmr_pack(sfmr_pl, !create, fid, fid);
|
||||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_fid_map(struct mlxsw_sp *mlxsw_sp, u16 fid, bool valid)
|
||||
{
|
||||
enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID;
|
||||
char svfa_pl[MLXSW_REG_SVFA_LEN];
|
||||
|
||||
mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid, fid);
|
||||
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
|
||||
}
|
||||
|
||||
static struct mlxsw_sp_fid *mlxsw_sp_fid_alloc(u16 fid)
|
||||
{
|
||||
struct mlxsw_sp_fid *f;
|
||||
|
||||
f = kzalloc(sizeof(*f), GFP_KERNEL);
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
f->fid = fid;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp,
|
||||
u16 fid)
|
||||
{
|
||||
struct mlxsw_sp_fid *f;
|
||||
int err;
|
||||
|
||||
err = mlxsw_sp_fid_op(mlxsw_sp, fid, true);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
/* Although all the ports member in the FID might be using a
|
||||
* {Port, VID} to FID mapping, we create a global VID-to-FID
|
||||
* mapping. This allows a port to transition to VLAN mode,
|
||||
* knowing the global mapping exists.
|
||||
*/
|
||||
err = mlxsw_sp_fid_map(mlxsw_sp, fid, true);
|
||||
if (err)
|
||||
goto err_fid_map;
|
||||
|
||||
f = mlxsw_sp_fid_alloc(fid);
|
||||
if (!f) {
|
||||
err = -ENOMEM;
|
||||
goto err_allocate_fid;
|
||||
}
|
||||
|
||||
list_add(&f->list, &mlxsw_sp->fids);
|
||||
|
||||
return f;
|
||||
|
||||
err_allocate_fid:
|
||||
mlxsw_sp_fid_map(mlxsw_sp, fid, false);
|
||||
err_fid_map:
|
||||
mlxsw_sp_fid_op(mlxsw_sp, fid, false);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_fid *f)
|
||||
{
|
||||
u16 fid = f->fid;
|
||||
|
||||
list_del(&f->list);
|
||||
|
||||
kfree(f);
|
||||
|
||||
mlxsw_sp_fid_op(mlxsw_sp, fid, false);
|
||||
}
|
||||
|
||||
static int __mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
u16 fid)
|
||||
{
|
||||
struct mlxsw_sp_fid *f;
|
||||
|
||||
f = mlxsw_sp_fid_find(mlxsw_sp_port->mlxsw_sp, fid);
|
||||
if (!f) {
|
||||
f = mlxsw_sp_fid_create(mlxsw_sp_port->mlxsw_sp, fid);
|
||||
if (IS_ERR(f))
|
||||
return PTR_ERR(f);
|
||||
}
|
||||
|
||||
f->ref_count++;
|
||||
|
||||
netdev_dbg(mlxsw_sp_port->dev, "Joined FID=%d\n", fid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __mlxsw_sp_port_fid_leave(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
u16 fid)
|
||||
{
|
||||
struct mlxsw_sp_fid *f;
|
||||
|
||||
f = mlxsw_sp_fid_find(mlxsw_sp_port->mlxsw_sp, fid);
|
||||
if (WARN_ON(!f))
|
||||
return;
|
||||
|
||||
netdev_dbg(mlxsw_sp_port->dev, "Left FID=%d\n", fid);
|
||||
|
||||
mlxsw_sp_port_fdb_flush(mlxsw_sp_port, fid);
|
||||
|
||||
if (--f->ref_count == 0)
|
||||
mlxsw_sp_fid_destroy(mlxsw_sp_port->mlxsw_sp, f);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid,
|
||||
bool valid)
|
||||
{
|
||||
enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_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))
|
||||
return 0;
|
||||
|
||||
return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, valid, fid, fid);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_fid_join(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
u16 fid_begin, u16 fid_end)
|
||||
{
|
||||
int fid, err;
|
||||
|
||||
for (fid = fid_begin; fid <= fid_end; fid++) {
|
||||
err = __mlxsw_sp_port_fid_join(mlxsw_sp_port, fid);
|
||||
if (err)
|
||||
goto err_port_fid_join;
|
||||
}
|
||||
|
||||
err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end,
|
||||
true, false);
|
||||
if (err)
|
||||
goto err_port_flood_set;
|
||||
|
||||
for (fid = fid_begin; fid <= fid_end; fid++) {
|
||||
err = mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, true);
|
||||
if (err)
|
||||
goto err_port_fid_map;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_port_fid_map:
|
||||
for (fid--; fid >= fid_begin; fid--)
|
||||
mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, false);
|
||||
__mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end, false,
|
||||
false);
|
||||
err_port_flood_set:
|
||||
fid = fid_end;
|
||||
err_port_fid_join:
|
||||
for (fid--; fid >= fid_begin; fid--)
|
||||
__mlxsw_sp_port_fid_leave(mlxsw_sp_port, fid);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mlxsw_sp_port_fid_leave(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
u16 fid_begin, u16 fid_end)
|
||||
{
|
||||
int fid;
|
||||
|
||||
for (fid = fid_begin; fid <= fid_end; fid++)
|
||||
mlxsw_sp_port_fid_map(mlxsw_sp_port, fid, false);
|
||||
|
||||
__mlxsw_sp_port_flood_set(mlxsw_sp_port, fid_begin, fid_end, false,
|
||||
false);
|
||||
|
||||
for (fid = fid_begin; fid <= fid_end; fid++)
|
||||
__mlxsw_sp_port_fid_leave(mlxsw_sp_port, fid);
|
||||
}
|
||||
|
||||
static int __mlxsw_sp_port_pvid_set(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
u16 vid)
|
||||
{
|
||||
@ -440,55 +633,6 @@ err_port_allow_untagged_set:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid)
|
||||
{
|
||||
char sfmr_pl[MLXSW_REG_SFMR_LEN];
|
||||
int err;
|
||||
|
||||
mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, fid, fid);
|
||||
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
set_bit(fid, mlxsw_sp->active_fids);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, u16 fid)
|
||||
{
|
||||
char sfmr_pl[MLXSW_REG_SFMR_LEN];
|
||||
|
||||
clear_bit(fid, mlxsw_sp->active_fids);
|
||||
|
||||
mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_DESTROY_FID,
|
||||
fid, fid);
|
||||
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid)
|
||||
{
|
||||
enum mlxsw_reg_svfa_mt mt;
|
||||
|
||||
if (!list_empty(&mlxsw_sp_port->vports_list))
|
||||
mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
|
||||
else
|
||||
mt = MLXSW_REG_SVFA_MT_VID_TO_FID;
|
||||
|
||||
return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, fid, fid);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_fid_unmap(struct mlxsw_sp_port *mlxsw_sp_port, u16 fid)
|
||||
{
|
||||
enum mlxsw_reg_svfa_mt mt;
|
||||
|
||||
if (list_empty(&mlxsw_sp_port->vports_list))
|
||||
return 0;
|
||||
|
||||
mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
|
||||
return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid, fid);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_port_add_vids(struct net_device *dev, u16 vid_begin,
|
||||
u16 vid_end)
|
||||
{
|
||||
@ -533,10 +677,8 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
u16 vid_begin, u16 vid_end,
|
||||
bool flag_untagged, bool flag_pvid)
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
struct net_device *dev = mlxsw_sp_port->dev;
|
||||
u16 vid, last_visited_vid, old_pvid;
|
||||
enum mlxsw_reg_svfa_mt mt;
|
||||
u16 vid, old_pvid;
|
||||
int err;
|
||||
|
||||
/* In case this is invoked with BRIDGE_FLAGS_SELF and port is
|
||||
@ -546,44 +688,10 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
if (!mlxsw_sp_port->bridged)
|
||||
return mlxsw_sp_port_add_vids(dev, vid_begin, vid_end);
|
||||
|
||||
for (vid = vid_begin; vid <= vid_end; vid++) {
|
||||
if (!test_bit(vid, mlxsw_sp->active_fids)) {
|
||||
err = mlxsw_sp_fid_create(mlxsw_sp, vid);
|
||||
if (err) {
|
||||
netdev_err(dev, "Failed to create FID=%d\n",
|
||||
vid);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* When creating a FID, we set a VID to FID mapping
|
||||
* regardless of the port's mode.
|
||||
*/
|
||||
mt = MLXSW_REG_SVFA_MT_VID_TO_FID;
|
||||
err = mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt,
|
||||
true, vid, vid);
|
||||
if (err) {
|
||||
netdev_err(dev, "Failed to create FID=VID=%d mapping\n",
|
||||
vid);
|
||||
goto err_port_vid_to_fid_set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set FID mapping according to port's mode */
|
||||
for (vid = vid_begin; vid <= vid_end; vid++) {
|
||||
err = mlxsw_sp_port_fid_map(mlxsw_sp_port, vid);
|
||||
if (err) {
|
||||
netdev_err(dev, "Failed to map FID=%d", vid);
|
||||
last_visited_vid = --vid;
|
||||
goto err_port_fid_map;
|
||||
}
|
||||
}
|
||||
|
||||
err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, vid_begin, vid_end,
|
||||
true, false);
|
||||
err = mlxsw_sp_port_fid_join(mlxsw_sp_port, vid_begin, vid_end);
|
||||
if (err) {
|
||||
netdev_err(dev, "Failed to configure flooding\n");
|
||||
goto err_port_flood_set;
|
||||
netdev_err(dev, "Failed to join FIDs\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = __mlxsw_sp_port_vlans_set(mlxsw_sp_port, vid_begin, vid_end,
|
||||
@ -628,10 +736,6 @@ static int __mlxsw_sp_port_vlans_add(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
|
||||
return 0;
|
||||
|
||||
err_port_vid_to_fid_set:
|
||||
mlxsw_sp_fid_destroy(mlxsw_sp, vid);
|
||||
return err;
|
||||
|
||||
err_port_stp_state_set:
|
||||
for (vid = vid_begin; vid <= vid_end; vid++)
|
||||
clear_bit(vid, mlxsw_sp_port->active_vlans);
|
||||
@ -641,13 +745,7 @@ err_port_pvid_set:
|
||||
__mlxsw_sp_port_vlans_set(mlxsw_sp_port, vid_begin, vid_end, false,
|
||||
false);
|
||||
err_port_vlans_set:
|
||||
__mlxsw_sp_port_flood_set(mlxsw_sp_port, vid_begin, vid_end, false,
|
||||
false);
|
||||
err_port_flood_set:
|
||||
last_visited_vid = vid_end;
|
||||
err_port_fid_map:
|
||||
for (vid = last_visited_vid; vid >= vid_begin; vid--)
|
||||
mlxsw_sp_port_fid_unmap(mlxsw_sp_port, vid);
|
||||
mlxsw_sp_port_fid_leave(mlxsw_sp_port, vid_begin, vid_end);
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -970,21 +1068,7 @@ static int __mlxsw_sp_port_vlans_del(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
}
|
||||
}
|
||||
|
||||
err = __mlxsw_sp_port_flood_set(mlxsw_sp_port, vid_begin, vid_end,
|
||||
false, false);
|
||||
if (err) {
|
||||
netdev_err(dev, "Failed to clear flooding\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
for (vid = vid_begin; vid <= vid_end; vid++) {
|
||||
/* Remove FID mapping in case of Virtual mode */
|
||||
err = mlxsw_sp_port_fid_unmap(mlxsw_sp_port, vid);
|
||||
if (err) {
|
||||
netdev_err(dev, "Failed to unmap FID=%d", vid);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
mlxsw_sp_port_fid_leave(mlxsw_sp_port, vid_begin, vid_end);
|
||||
|
||||
out:
|
||||
/* Changing activity bits only if HW operation succeded */
|
||||
@ -1118,7 +1202,8 @@ static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
{
|
||||
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
|
||||
struct mlxsw_sp_port *tmp;
|
||||
u16 vport_fid = 0;
|
||||
struct mlxsw_sp_fid *f;
|
||||
u16 vport_fid;
|
||||
char *sfd_pl;
|
||||
char mac[ETH_ALEN];
|
||||
u16 fid;
|
||||
@ -1133,12 +1218,8 @@ static int mlxsw_sp_port_fdb_dump(struct mlxsw_sp_port *mlxsw_sp_port,
|
||||
if (!sfd_pl)
|
||||
return -ENOMEM;
|
||||
|
||||
if (mlxsw_sp_port_is_vport(mlxsw_sp_port)) {
|
||||
u16 tmp;
|
||||
|
||||
tmp = mlxsw_sp_vport_vfid_get(mlxsw_sp_port);
|
||||
vport_fid = mlxsw_sp_vfid_to_fid(tmp);
|
||||
}
|
||||
f = mlxsw_sp_vport_fid_get(mlxsw_sp_port);
|
||||
vport_fid = f ? f->fid : 0;
|
||||
|
||||
mlxsw_reg_sfd_pack(sfd_pl, MLXSW_REG_SFD_OP_QUERY_DUMP, 0);
|
||||
do {
|
||||
@ -1310,11 +1391,10 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp,
|
||||
}
|
||||
|
||||
if (mlxsw_sp_fid_is_vfid(fid)) {
|
||||
u16 vfid = mlxsw_sp_fid_to_vfid(fid);
|
||||
struct mlxsw_sp_port *mlxsw_sp_vport;
|
||||
|
||||
mlxsw_sp_vport = mlxsw_sp_port_vport_find_by_vfid(mlxsw_sp_port,
|
||||
vfid);
|
||||
mlxsw_sp_vport = mlxsw_sp_port_vport_find_by_fid(mlxsw_sp_port,
|
||||
fid);
|
||||
if (!mlxsw_sp_vport) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Failed to find a matching vPort following FDB notification\n");
|
||||
goto just_remove;
|
||||
@ -1370,11 +1450,10 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp,
|
||||
}
|
||||
|
||||
if (mlxsw_sp_fid_is_vfid(fid)) {
|
||||
u16 vfid = mlxsw_sp_fid_to_vfid(fid);
|
||||
struct mlxsw_sp_port *mlxsw_sp_vport;
|
||||
|
||||
mlxsw_sp_vport = mlxsw_sp_port_vport_find_by_vfid(mlxsw_sp_port,
|
||||
vfid);
|
||||
mlxsw_sp_vport = mlxsw_sp_port_vport_find_by_fid(mlxsw_sp_port,
|
||||
fid);
|
||||
if (!mlxsw_sp_vport) {
|
||||
netdev_err(mlxsw_sp_port->dev, "Failed to find a matching vPort following FDB notification\n");
|
||||
goto just_remove;
|
||||
@ -1495,14 +1574,6 @@ static void mlxsw_sp_fdb_fini(struct mlxsw_sp *mlxsw_sp)
|
||||
cancel_delayed_work_sync(&mlxsw_sp->fdb_notify.dw);
|
||||
}
|
||||
|
||||
static void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
|
||||
{
|
||||
u16 fid;
|
||||
|
||||
for_each_set_bit(fid, mlxsw_sp->active_fids, VLAN_N_VID)
|
||||
mlxsw_sp_fid_destroy(mlxsw_sp, fid);
|
||||
}
|
||||
|
||||
int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp)
|
||||
{
|
||||
return mlxsw_sp_fdb_init(mlxsw_sp);
|
||||
@ -1511,7 +1582,6 @@ int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp)
|
||||
void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp)
|
||||
{
|
||||
mlxsw_sp_fdb_fini(mlxsw_sp);
|
||||
mlxsw_sp_fids_fini(mlxsw_sp);
|
||||
}
|
||||
|
||||
int mlxsw_sp_port_vlan_init(struct mlxsw_sp_port *mlxsw_sp_port)
|
||||
|
Loading…
Reference in New Issue
Block a user