diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/Makefile | 3 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 192 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 123 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c | 17 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c | 978 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 301 | ||||
-rw-r--r-- | drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 419 |
8 files changed, 1278 insertions, 761 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Makefile b/drivers/net/ethernet/mellanox/mlxsw/Makefile index 2fb8c6585ac7..62fc42f396bb 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/Makefile +++ b/drivers/net/ethernet/mellanox/mlxsw/Makefile @@ -16,7 +16,8 @@ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \ spectrum_switchdev.o spectrum_router.o \ spectrum_kvdl.o spectrum_acl_tcam.o \ spectrum_acl.o spectrum_flower.o \ - spectrum_cnt.o spectrum_dpipe.o + spectrum_cnt.o spectrum_dpipe.o \ + spectrum_fid.o mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o obj-$(CONFIG_MLXSW_MINIMAL) += mlxsw_minimal.o mlxsw_minimal-objs := minimal.o diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index 3b6056ae457a..666bcf4854e6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -870,8 +870,7 @@ static int mlxsw_sp_port_swid_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 swid) swid); } -static int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, - bool enable) +int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; char svpe_pl[MLXSW_REG_SVPE_LEN]; @@ -880,18 +879,6 @@ static int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svpe), svpe_pl); } -int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port, - enum mlxsw_reg_svfa_mt mt, bool valid, u16 fid, - u16 vid) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - char svfa_pl[MLXSW_REG_SVFA_LEN]; - - mlxsw_reg_svfa_pack(svfa_pl, mlxsw_sp_port->local_port, mt, valid, - fid, vid); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); -} - int mlxsw_sp_port_vid_learning_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, bool learn_enable) { @@ -1398,75 +1385,6 @@ int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, return 0; } -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; - struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct mlxsw_sp_fid *fid; - u16 vid; - int err; - - list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, - list) { - fid = mlxsw_sp_port_vlan->fid; - - if (!fid || fid->fid >= MLXSW_SP_VFID_BASE) - continue; - - vid = mlxsw_sp_port_vlan->vid; - err = mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, - fid->fid, vid); - if (err) - goto err_port_vid_to_fid_set; - } - - err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); - if (err) - goto err_port_vp_mode_set; - - return 0; - -err_port_vp_mode_set: -err_port_vid_to_fid_set: - list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan, - &mlxsw_sp_port->vlans_list, list) { - fid = mlxsw_sp_port_vlan->fid; - - if (!fid || fid->fid >= MLXSW_SP_VFID_BASE) - continue; - - vid = mlxsw_sp_port_vlan->vid; - mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid->fid, - vid); - } - return err; -} - -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; - struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - int err; - - err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); - if (err) - return err; - - list_for_each_entry_reverse(mlxsw_sp_port_vlan, - &mlxsw_sp_port->vlans_list, list) { - struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; - u16 vid = mlxsw_sp_port_vlan->vid; - - if (!fid || fid->fid >= MLXSW_SP_VFID_BASE) - continue; - - mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid->fid, - vid); - } - - return 0; -} - static void mlxsw_sp_port_vlan_flush(struct mlxsw_sp_port *mlxsw_sp_port) { struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, *tmp; @@ -1529,10 +1447,12 @@ mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + if (mlxsw_sp_port_vlan->bridge_port) mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); - else if (mlxsw_sp_port_vlan->fid) - mlxsw_sp_port_vlan->fid->leave(mlxsw_sp_port_vlan); + else if (fid) + mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); mlxsw_sp_port_vlan_destroy(mlxsw_sp_port_vlan); } @@ -2831,11 +2751,11 @@ static int __mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, goto err_port_dcb_init; } - err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); + err = mlxsw_sp_port_fids_init(mlxsw_sp_port); if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to set non-virtual mode\n", + dev_err(mlxsw_sp->bus_info->dev, "Port %d: Failed to initialize FIDs\n", mlxsw_sp_port->local_port); - goto err_port_vp_mode_set; + goto err_port_fids_init; } mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_get(mlxsw_sp_port, 1); @@ -2865,7 +2785,8 @@ err_register_netdev: mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); mlxsw_sp_port_vlan_put(mlxsw_sp_port_vlan); err_port_vlan_get: -err_port_vp_mode_set: + mlxsw_sp_port_fids_fini(mlxsw_sp_port); +err_port_fids_init: mlxsw_sp_port_dcb_fini(mlxsw_sp_port); err_port_dcb_init: err_port_ets_init: @@ -2919,6 +2840,7 @@ static void __mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port) mlxsw_sp->ports[local_port] = NULL; mlxsw_sp_port_switchdev_fini(mlxsw_sp_port); mlxsw_sp_port_vlan_flush(mlxsw_sp_port); + mlxsw_sp_port_fids_fini(mlxsw_sp_port); mlxsw_sp_port_dcb_fini(mlxsw_sp_port); mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT); mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port); @@ -3478,57 +3400,6 @@ static void mlxsw_sp_traps_fini(struct mlxsw_sp *mlxsw_sp) } } -static int __mlxsw_sp_flood_init(struct mlxsw_core *mlxsw_core, - enum mlxsw_reg_sfgc_type type, - enum mlxsw_reg_sfgc_bridge_type bridge_type) -{ - enum mlxsw_flood_table_type table_type; - enum mlxsw_sp_flood_table flood_table; - char sfgc_pl[MLXSW_REG_SFGC_LEN]; - - if (bridge_type == MLXSW_REG_SFGC_BRIDGE_TYPE_VFID) - table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID; - else - table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST; - - switch (type) { - case MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST: - flood_table = MLXSW_SP_FLOOD_TABLE_UC; - break; - case MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4: - flood_table = MLXSW_SP_FLOOD_TABLE_MC; - break; - default: - flood_table = MLXSW_SP_FLOOD_TABLE_BC; - } - - mlxsw_reg_sfgc_pack(sfgc_pl, type, bridge_type, table_type, - flood_table); - return mlxsw_reg_write(mlxsw_core, MLXSW_REG(sfgc), sfgc_pl); -} - -static int mlxsw_sp_flood_init(struct mlxsw_sp *mlxsw_sp) -{ - int type, err; - - for (type = 0; type < MLXSW_REG_SFGC_TYPE_MAX; type++) { - if (type == MLXSW_REG_SFGC_TYPE_RESERVED) - continue; - - err = __mlxsw_sp_flood_init(mlxsw_sp->core, type, - MLXSW_REG_SFGC_BRIDGE_TYPE_VFID); - if (err) - return err; - - err = __mlxsw_sp_flood_init(mlxsw_sp->core, type, - MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID); - if (err) - return err; - } - - return 0; -} - static int mlxsw_sp_lag_init(struct mlxsw_sp *mlxsw_sp) { char slcr_pl[MLXSW_REG_SLCR_LEN]; @@ -3576,16 +3447,6 @@ static int mlxsw_sp_basic_trap_groups_set(struct mlxsw_core *mlxsw_core) return mlxsw_reg_write(mlxsw_core, MLXSW_REG(htgt), htgt_pl); } -static int mlxsw_sp_dummy_fid_init(struct mlxsw_sp *mlxsw_sp) -{ - return mlxsw_sp_fid_op(mlxsw_sp, MLXSW_SP_DUMMY_FID, true); -} - -static void mlxsw_sp_dummy_fid_fini(struct mlxsw_sp *mlxsw_sp) -{ - mlxsw_sp_fid_op(mlxsw_sp, MLXSW_SP_DUMMY_FID, false); -} - static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, const struct mlxsw_bus_info *mlxsw_bus_info) { @@ -3594,8 +3455,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, mlxsw_sp->core = mlxsw_core; mlxsw_sp->bus_info = mlxsw_bus_info; - INIT_LIST_HEAD(&mlxsw_sp->fids); - INIT_LIST_HEAD(&mlxsw_sp->vfids.list); err = mlxsw_sp_fw_rev_validate(mlxsw_sp); if (err) { @@ -3609,16 +3468,16 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, return err; } - err = mlxsw_sp_traps_init(mlxsw_sp); + err = mlxsw_sp_fids_init(mlxsw_sp); if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n"); + dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize FIDs\n"); return err; } - err = mlxsw_sp_flood_init(mlxsw_sp); + err = mlxsw_sp_traps_init(mlxsw_sp); if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize flood tables\n"); - goto err_flood_init; + dev_err(mlxsw_sp->bus_info->dev, "Failed to set traps\n"); + goto err_traps_init; } err = mlxsw_sp_buffers_init(mlxsw_sp); @@ -3669,12 +3528,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, goto err_dpipe_init; } - err = mlxsw_sp_dummy_fid_init(mlxsw_sp); - if (err) { - dev_err(mlxsw_sp->bus_info->dev, "Failed to init dummy FID\n"); - goto err_dummy_fid_init; - } - err = mlxsw_sp_ports_create(mlxsw_sp); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to create ports\n"); @@ -3684,8 +3537,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core, return 0; err_ports_create: - mlxsw_sp_dummy_fid_fini(mlxsw_sp); -err_dummy_fid_init: mlxsw_sp_dpipe_fini(mlxsw_sp); err_dpipe_init: mlxsw_sp_counter_pool_fini(mlxsw_sp); @@ -3702,8 +3553,9 @@ err_switchdev_init: err_lag_init: mlxsw_sp_buffers_fini(mlxsw_sp); err_buffers_init: -err_flood_init: mlxsw_sp_traps_fini(mlxsw_sp); +err_traps_init: + mlxsw_sp_fids_fini(mlxsw_sp); return err; } @@ -3712,7 +3564,6 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) struct mlxsw_sp *mlxsw_sp = mlxsw_core_driver_priv(mlxsw_core); mlxsw_sp_ports_remove(mlxsw_sp); - mlxsw_sp_dummy_fid_fini(mlxsw_sp); mlxsw_sp_dpipe_fini(mlxsw_sp); mlxsw_sp_counter_pool_fini(mlxsw_sp); mlxsw_sp_acl_fini(mlxsw_sp); @@ -3722,8 +3573,7 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core) mlxsw_sp_lag_fini(mlxsw_sp); mlxsw_sp_buffers_fini(mlxsw_sp); mlxsw_sp_traps_fini(mlxsw_sp); - WARN_ON(!list_empty(&mlxsw_sp->vfids.list)); - WARN_ON(!list_empty(&mlxsw_sp->fids)); + mlxsw_sp_fids_fini(mlxsw_sp); } static struct mlxsw_config_profile mlxsw_sp_config_profile = { @@ -3739,7 +3589,7 @@ static struct mlxsw_config_profile mlxsw_sp_config_profile = { .max_fid_offset_flood_tables = 3, .fid_offset_flood_table_size = VLAN_N_VID - 1, .max_fid_flood_tables = 3, - .fid_flood_table_size = MLXSW_SP_VFID_MAX, + .fid_flood_table_size = MLXSW_SP_FID_8021D_MAX, .used_max_ib_mc = 1, .max_ib_mc = 0, .used_max_pkey = 1, @@ -4009,7 +3859,7 @@ static int mlxsw_sp_port_lag_join(struct mlxsw_sp_port *mlxsw_sp_port, /* Port is no longer usable as a router interface */ mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, 1); if (mlxsw_sp_port_vlan->fid) - mlxsw_sp_port_vlan->fid->leave(mlxsw_sp_port_vlan); + mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); return 0; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h index 8c511ff19f84..c542b33e44c0 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h @@ -54,12 +54,7 @@ #include "core_acl_flex_keys.h" #include "core_acl_flex_actions.h" -#define MLXSW_SP_VFID_BASE VLAN_N_VID -#define MLXSW_SP_VFID_MAX 1024 /* Bridged VLAN interfaces */ - -#define MLXSW_SP_DUMMY_FID 15359 - -#define MLXSW_SP_RFID_BASE 15360 +#define MLXSW_SP_FID_8021D_MAX 1024 #define MLXSW_SP_MID_MAX 7000 @@ -70,7 +65,6 @@ #define MLXSW_SP_KVD_LINEAR_SIZE 65536 /* entries */ #define MLXSW_SP_KVD_GRANULARITY 128 -struct mlxsw_sp_port_vlan; struct mlxsw_sp_port; struct mlxsw_sp_rif; @@ -79,13 +73,19 @@ struct mlxsw_sp_upper { unsigned int ref_count; }; -struct mlxsw_sp_fid { - void (*leave)(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); - struct list_head list; - unsigned int ref_count; - struct net_device *dev; - struct mlxsw_sp_rif *rif; - u16 fid; +enum mlxsw_sp_rif_type { + MLXSW_SP_RIF_TYPE_SUBPORT, + MLXSW_SP_RIF_TYPE_VLAN, + MLXSW_SP_RIF_TYPE_FID, + MLXSW_SP_RIF_TYPE_MAX, +}; + +enum mlxsw_sp_fid_type { + MLXSW_SP_FID_TYPE_8021Q, + MLXSW_SP_FID_TYPE_8021D, + MLXSW_SP_FID_TYPE_RFID, + MLXSW_SP_FID_TYPE_DUMMY, + MLXSW_SP_FID_TYPE_MAX, }; struct mlxsw_sp_mid { @@ -96,21 +96,6 @@ struct mlxsw_sp_mid { unsigned int ref_count; }; -static inline u16 mlxsw_sp_vfid_to_fid(u16 vfid) -{ - return MLXSW_SP_VFID_BASE + vfid; -} - -static inline u16 mlxsw_sp_fid_to_vfid(u16 fid) -{ - return fid - MLXSW_SP_VFID_BASE; -} - -static inline bool mlxsw_sp_fid_is_vfid(u16 fid) -{ - return fid >= MLXSW_SP_VFID_BASE && fid < MLXSW_SP_DUMMY_FID; -} - enum mlxsw_sp_span_type { MLXSW_SP_SPAN_EGRESS, MLXSW_SP_SPAN_INGRESS @@ -154,13 +139,9 @@ struct mlxsw_sp_bridge; struct mlxsw_sp_router; struct mlxsw_sp_acl; struct mlxsw_sp_counter_pool; +struct mlxsw_sp_fid_core; struct mlxsw_sp { - struct { - struct list_head list; - DECLARE_BITMAP(mapped, MLXSW_SP_VFID_MAX); - } vfids; - struct list_head fids; /* VLAN-aware bridge FIDs */ struct mlxsw_sp_port **ports; struct mlxsw_core *core; const struct mlxsw_bus_info *bus_info; @@ -171,6 +152,7 @@ struct mlxsw_sp { struct mlxsw_sp_bridge *bridge; struct mlxsw_sp_router *router; struct mlxsw_sp_acl *acl; + struct mlxsw_sp_fid_core *fid_core; struct { DECLARE_BITMAP(usage, MLXSW_SP_KVD_LINEAR_SIZE); } kvdl; @@ -205,6 +187,7 @@ struct mlxsw_sp_port_sample { }; struct mlxsw_sp_bridge_port; +struct mlxsw_sp_fid; struct mlxsw_sp_port_vlan { struct list_head list; @@ -247,7 +230,6 @@ 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 */ struct list_head vlans_list; }; @@ -290,35 +272,10 @@ mlxsw_sp_port_vlan_find_by_vid(const struct mlxsw_sp_port *mlxsw_sp_port, return NULL; } -static inline 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 inline struct mlxsw_sp_fid * -mlxsw_sp_vfid_find(const struct mlxsw_sp *mlxsw_sp, - const struct net_device *br_dev) -{ - struct mlxsw_sp_fid *f; - - list_for_each_entry(f, &mlxsw_sp->vfids.list, list) - if (f->dev == br_dev) - return f; - - return NULL; -} - -enum mlxsw_sp_flood_table { - MLXSW_SP_FLOOD_TABLE_UC, - MLXSW_SP_FLOOD_TABLE_BC, - MLXSW_SP_FLOOD_TABLE_MC, +enum mlxsw_sp_flood_type { + MLXSW_SP_FLOOD_TYPE_UC, + MLXSW_SP_FLOOD_TYPE_BC, + MLXSW_SP_FLOOD_TYPE_MC, }; int mlxsw_sp_buffers_init(struct mlxsw_sp *mlxsw_sp); @@ -362,15 +319,10 @@ int mlxsw_sp_switchdev_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_switchdev_fini(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_port_switchdev_init(struct mlxsw_sp_port *mlxsw_sp_port); void mlxsw_sp_port_switchdev_fini(struct mlxsw_sp_port *mlxsw_sp_port); -int mlxsw_sp_port_vid_to_fid_set(struct mlxsw_sp_port *mlxsw_sp_port, - enum mlxsw_reg_svfa_mt mt, bool valid, u16 fid, - u16 vid); int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin, u16 vid_end, bool is_member, bool untagged); int mlxsw_sp_rif_fdb_op(struct mlxsw_sp *mlxsw_sp, const char *mac, u16 fid, bool adding); -struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, u16 fid); -int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, bool valid); void mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, @@ -393,11 +345,10 @@ int mlxsw_sp_port_ets_maxrate_set(struct mlxsw_sp_port *mlxsw_sp_port, u8 next_index, u32 maxrate); int mlxsw_sp_port_vid_stp_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid, u8 state); +int mlxsw_sp_port_vp_mode_set(struct mlxsw_sp_port *mlxsw_sp_port, bool enable); 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); struct mlxsw_sp_port_vlan * mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); @@ -426,10 +377,11 @@ int mlxsw_sp_router_netevent_event(struct notifier_block *unused, int mlxsw_sp_netdevice_router_port_event(struct net_device *dev); int mlxsw_sp_inetaddr_event(struct notifier_block *unused, unsigned long event, void *ptr); -void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_rif *rif); int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, struct netdev_notifier_changeupper_info *info); +void +mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); +void mlxsw_sp_rif_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif); int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, unsigned int entry_count, u32 *p_entry_index); @@ -535,6 +487,8 @@ int mlxsw_sp_acl_rule_get_stats(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_rule *rule, u64 *packets, u64 *bytes, u64 *last_use); +struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp); + int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp); void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp); @@ -554,4 +508,27 @@ int mlxsw_sp_flow_counter_alloc(struct mlxsw_sp *mlxsw_sp, void mlxsw_sp_flow_counter_free(struct mlxsw_sp *mlxsw_sp, unsigned int counter_index); +int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, + enum mlxsw_sp_flood_type packet_type, u8 local_port, + bool member); +int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); +void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid); +enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid); +u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid); +enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid); +void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif); +struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid); +struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, + int br_ifindex); +struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp, + u16 rif_index); +struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp); +void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid); +int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port); +void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port); +int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp); +void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp); + #endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c index 317f7b14627f..1da889a044df 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c @@ -53,6 +53,7 @@ struct mlxsw_sp_acl { struct mlxsw_sp *mlxsw_sp; struct mlxsw_afk *afk; struct mlxsw_afa *afa; + struct mlxsw_sp_fid *dummy_fid; const struct mlxsw_sp_acl_ops *ops; struct rhashtable ruleset_ht; struct list_head rules; @@ -112,6 +113,11 @@ static const struct rhashtable_params mlxsw_sp_acl_rule_ht_params = { .automatic_shrinking = true, }; +struct mlxsw_sp_fid *mlxsw_sp_acl_dummy_fid(struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_sp->acl->dummy_fid; +} + static struct mlxsw_sp_acl_ruleset * mlxsw_sp_acl_ruleset_create(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_acl_profile_ops *ops) @@ -676,6 +682,7 @@ static const struct mlxsw_afa_ops mlxsw_sp_act_afa_ops = { int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp) { const struct mlxsw_sp_acl_ops *acl_ops = &mlxsw_sp_acl_tcam_ops; + struct mlxsw_sp_fid *fid; struct mlxsw_sp_acl *acl; int err; @@ -706,6 +713,13 @@ int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp) if (err) goto err_rhashtable_init; + fid = mlxsw_sp_fid_dummy_get(mlxsw_sp); + if (IS_ERR(fid)) { + err = PTR_ERR(fid); + goto err_fid_get; + } + acl->dummy_fid = fid; + INIT_LIST_HEAD(&acl->rules); err = acl_ops->init(mlxsw_sp, acl->priv); if (err) @@ -721,6 +735,8 @@ int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp) return 0; err_acl_ops_init: + mlxsw_sp_fid_put(fid); +err_fid_get: rhashtable_destroy(&acl->ruleset_ht); err_rhashtable_init: mlxsw_afa_destroy(acl->afa); @@ -739,6 +755,7 @@ void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp) cancel_delayed_work_sync(&mlxsw_sp->acl->rule_activity_update.dw); acl_ops->fini(mlxsw_sp, acl->priv); WARN_ON(!list_empty(&acl->rules)); + mlxsw_sp_fid_put(acl->dummy_fid); rhashtable_destroy(&acl->ruleset_ht); mlxsw_afa_destroy(acl->afa); mlxsw_afk_destroy(acl->afk); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c new file mode 100644 index 000000000000..379bbe001dd9 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c @@ -0,0 +1,978 @@ +/* + * drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c + * Copyright (c) 2017 Mellanox Technologies. All rights reserved. + * Copyright (c) 2017 Ido Schimmel <idosch@mellanox.com> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/kernel.h> +#include <linux/bitops.h> +#include <linux/if_vlan.h> +#include <linux/if_bridge.h> +#include <linux/netdevice.h> +#include <linux/rtnetlink.h> + +#include "spectrum.h" +#include "reg.h" + +struct mlxsw_sp_fid_family; + +struct mlxsw_sp_fid_core { + struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX]; + unsigned int *port_fid_mappings; +}; + +struct mlxsw_sp_fid { + struct list_head list; + struct mlxsw_sp_rif *rif; + unsigned int ref_count; + u16 fid_index; + struct mlxsw_sp_fid_family *fid_family; +}; + +struct mlxsw_sp_fid_8021q { + struct mlxsw_sp_fid common; + u16 vid; +}; + +struct mlxsw_sp_fid_8021d { + struct mlxsw_sp_fid common; + int br_ifindex; +}; + +struct mlxsw_sp_flood_table { + enum mlxsw_sp_flood_type packet_type; + enum mlxsw_reg_sfgc_bridge_type bridge_type; + enum mlxsw_flood_table_type table_type; + int table_index; +}; + +struct mlxsw_sp_fid_ops { + void (*setup)(struct mlxsw_sp_fid *fid, const void *arg); + int (*configure)(struct mlxsw_sp_fid *fid); + void (*deconfigure)(struct mlxsw_sp_fid *fid); + int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg, + u16 *p_fid_index); + bool (*compare)(const struct mlxsw_sp_fid *fid, + const void *arg); + u16 (*flood_index)(const struct mlxsw_sp_fid *fid); + int (*port_vid_map)(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *port, u16 vid); + void (*port_vid_unmap)(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *port, u16 vid); +}; + +struct mlxsw_sp_fid_family { + enum mlxsw_sp_fid_type type; + size_t fid_size; + u16 start_index; + u16 end_index; + struct list_head fids_list; + unsigned long *fids_bitmap; + const struct mlxsw_sp_flood_table *flood_tables; + int nr_flood_tables; + enum mlxsw_sp_rif_type rif_type; + const struct mlxsw_sp_fid_ops *ops; + struct mlxsw_sp *mlxsw_sp; +}; + +static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1, +}; + +static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1, + [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1, + [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1, +}; + +static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { + [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, +}; + +static const int *mlxsw_sp_packet_type_sfgc_types[] = { + [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types, + [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types, + [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types, +}; + +static const struct mlxsw_sp_flood_table * +mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid, + enum mlxsw_sp_flood_type packet_type) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + int i; + + for (i = 0; i < fid_family->nr_flood_tables; i++) { + if (fid_family->flood_tables[i].packet_type != packet_type) + continue; + return &fid_family->flood_tables[i]; + } + + return NULL; +} + +int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, + enum mlxsw_sp_flood_type packet_type, u8 local_port, + bool member) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + const struct mlxsw_sp_fid_ops *ops = fid_family->ops; + const struct mlxsw_sp_flood_table *flood_table; + char *sftr_pl; + int err; + + if (WARN_ON(!fid_family->flood_tables || !ops->flood_index)) + return -EINVAL; + + flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type); + if (!flood_table) + return -ESRCH; + + sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL); + if (!sftr_pl) + return -ENOMEM; + + mlxsw_reg_sftr_pack(sftr_pl, flood_table->table_index, + ops->flood_index(fid), flood_table->table_type, 1, + local_port, member); + err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr), + sftr_pl); + kfree(sftr_pl); + return err; +} + +int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + if (WARN_ON(!fid->fid_family->ops->port_vid_map)) + return -EINVAL; + return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid); +} + +void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid); +} + +enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_family->rif_type; +} + +u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_index; +} + +enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_family->type; +} + +void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif) +{ + fid->rif = rif; +} + +static struct mlxsw_sp_fid_8021q * +mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid) +{ + return container_of(fid, struct mlxsw_sp_fid_8021q, common); +} + +static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg) +{ + u16 vid = *(u16 *) arg; + + mlxsw_sp_fid_8021q_fid(fid)->vid = vid; +} + +static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) +{ + return valid ? MLXSW_REG_SFMR_OP_CREATE_FID : + MLXSW_REG_SFMR_OP_DESTROY_FID; +} + +static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, + u16 fid_offset, bool valid) +{ + char sfmr_pl[MLXSW_REG_SFMR_LEN]; + + mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index, + fid_offset); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); +} + +static int mlxsw_sp_fid_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, + u16 vid, 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_index, vid); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); +} + +static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, + u8 local_port, u16 vid, bool valid) +{ + enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; + char svfa_pl[MLXSW_REG_SVFA_LEN]; + + mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid); + return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); +} + +static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + struct mlxsw_sp_fid_8021q *fid_8021q; + int err; + + err = mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, fid->fid_index, true); + if (err) + return err; + + fid_8021q = mlxsw_sp_fid_8021q_fid(fid); + err = mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, + true); + if (err) + goto err_fid_map; + + return 0; + +err_fid_map: + mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false); + return err; +} + +static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + struct mlxsw_sp_fid_8021q *fid_8021q; + + fid_8021q = mlxsw_sp_fid_8021q_fid(fid); + mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, false); + mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false); +} + +static int mlxsw_sp_fid_8021q_index_alloc(struct mlxsw_sp_fid *fid, + const void *arg, u16 *p_fid_index) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + u16 vid = *(u16 *) arg; + + /* Use 1:1 mapping for simplicity although not a must */ + if (vid < fid_family->start_index || vid > fid_family->end_index) + return -EINVAL; + *p_fid_index = vid; + + return 0; +} + +static bool +mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg) +{ + u16 vid = *(u16 *) arg; + + return mlxsw_sp_fid_8021q_fid(fid)->vid == vid; +} + +static u16 mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_index; +} + +static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + + /* In case there are no {Port, VID} => FID mappings on the port, + * we can use the global VID => FID mapping we created when the + * FID was configured. + */ + if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0) + return 0; + return __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, + vid, true); +} + +static void +mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + + if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0) + return; + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, vid, + false); +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = { + .setup = mlxsw_sp_fid_8021q_setup, + .configure = mlxsw_sp_fid_8021q_configure, + .deconfigure = mlxsw_sp_fid_8021q_deconfigure, + .index_alloc = mlxsw_sp_fid_8021q_index_alloc, + .compare = mlxsw_sp_fid_8021q_compare, + .flood_index = mlxsw_sp_fid_8021q_flood_index, + .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap, +}; + +static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021q_flood_tables[] = { + { + .packet_type = MLXSW_SP_FLOOD_TYPE_UC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, + .table_index = 0, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_MC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, + .table_index = 1, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_BC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST, + .table_index = 2, + }, +}; + +/* Range and flood configuration must match mlxsw_config_profile */ +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_family = { + .type = MLXSW_SP_FID_TYPE_8021Q, + .fid_size = sizeof(struct mlxsw_sp_fid_8021q), + .start_index = 1, + .end_index = VLAN_VID_MASK, + .flood_tables = mlxsw_sp_fid_8021q_flood_tables, + .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021q_flood_tables), + .rif_type = MLXSW_SP_RIF_TYPE_VLAN, + .ops = &mlxsw_sp_fid_8021q_ops, +}; + +static struct mlxsw_sp_fid_8021d * +mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid) +{ + return container_of(fid, struct mlxsw_sp_fid_8021d, common); +} + +static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg) +{ + int br_ifindex = *(int *) arg; + + mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex; +} + +static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + + return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true); +} + +static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid) +{ + mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); +} + +static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid, + const void *arg, u16 *p_fid_index) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + u16 nr_fids, fid_index; + + nr_fids = fid_family->end_index - fid_family->start_index + 1; + fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids); + if (fid_index == nr_fids) + return -ENOBUFS; + *p_fid_index = fid_family->start_index + fid_index; + + return 0; +} + +static bool +mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg) +{ + int br_ifindex = *(int *) arg; + + return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex; +} + +static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid) +{ + return fid->fid_index - fid->fid_family->start_index; +} + +static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + int err; + + list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, + list) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u16 vid = mlxsw_sp_port_vlan->vid; + + if (!fid) + continue; + + err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, + vid, true); + if (err) + goto err_fid_port_vid_map; + } + + err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); + if (err) + goto err_port_vp_mode_set; + + return 0; + +err_port_vp_mode_set: +err_fid_port_vid_map: + list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan, + &mlxsw_sp_port->vlans_list, list) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u16 vid = mlxsw_sp_port_vlan->vid; + + if (!fid) + continue; + + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, + false); + } + return err; +} + +static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; + + mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); + + list_for_each_entry_reverse(mlxsw_sp_port_vlan, + &mlxsw_sp_port->vlans_list, list) { + struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u16 vid = mlxsw_sp_port_vlan->vid; + + if (!fid) + continue; + + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, + false); + } +} + +static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + int err; + + err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, true); + if (err) + return err; + + if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { + err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); + if (err) + goto err_port_vp_mode_trans; + } + + return 0; + +err_port_vp_mode_trans: + mlxsw_sp->fid_core->port_fid_mappings[local_port]--; + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, false); + return err; +} + +static void +mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + + if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) + mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); + mlxsw_sp->fid_core->port_fid_mappings[local_port]--; + __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, + mlxsw_sp_port->local_port, vid, false); +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { + .setup = mlxsw_sp_fid_8021d_setup, + .configure = mlxsw_sp_fid_8021d_configure, + .deconfigure = mlxsw_sp_fid_8021d_deconfigure, + .index_alloc = mlxsw_sp_fid_8021d_index_alloc, + .compare = mlxsw_sp_fid_8021d_compare, + .flood_index = mlxsw_sp_fid_8021d_flood_index, + .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, +}; + +static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { + { + .packet_type = MLXSW_SP_FLOOD_TYPE_UC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, + .table_index = 0, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_MC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, + .table_index = 1, + }, + { + .packet_type = MLXSW_SP_FLOOD_TYPE_BC, + .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, + .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, + .table_index = 2, + }, +}; + +/* Range and flood configuration must match mlxsw_config_profile */ +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = { + .type = MLXSW_SP_FID_TYPE_8021D, + .fid_size = sizeof(struct mlxsw_sp_fid_8021d), + .start_index = VLAN_N_VID, + .end_index = VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1, + .flood_tables = mlxsw_sp_fid_8021d_flood_tables, + .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), + .rif_type = MLXSW_SP_RIF_TYPE_FID, + .ops = &mlxsw_sp_fid_8021d_ops, +}; + +static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid) +{ + /* rFIDs are allocated by the device during init */ + return 0; +} + +static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid) +{ +} + +static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid, + const void *arg, u16 *p_fid_index) +{ + u16 rif_index = *(u16 *) arg; + + *p_fid_index = fid->fid_family->start_index + rif_index; + + return 0; +} + +static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid, + const void *arg) +{ + u16 rif_index = *(u16 *) arg; + + return fid->fid_index == rif_index + fid->fid_family->start_index; +} + +static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + int err; + + /* We only need to transition the port to virtual mode since + * {Port, VID} => FID is done by the firmware upon RIF creation. + */ + if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { + err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); + if (err) + goto err_port_vp_mode_trans; + } + + return 0; + +err_port_vp_mode_trans: + mlxsw_sp->fid_core->port_fid_mappings[local_port]--; + return err; +} + +static void +mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid, + struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + u8 local_port = mlxsw_sp_port->local_port; + + if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) + mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); + mlxsw_sp->fid_core->port_fid_mappings[local_port]--; +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = { + .configure = mlxsw_sp_fid_rfid_configure, + .deconfigure = mlxsw_sp_fid_rfid_deconfigure, + .index_alloc = mlxsw_sp_fid_rfid_index_alloc, + .compare = mlxsw_sp_fid_rfid_compare, + .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map, + .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap, +}; + +#define MLXSW_SP_RFID_BASE (15 * 1024) +#define MLXSW_SP_RFID_MAX 1024 + +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = { + .type = MLXSW_SP_FID_TYPE_RFID, + .fid_size = sizeof(struct mlxsw_sp_fid), + .start_index = MLXSW_SP_RFID_BASE, + .end_index = MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1, + .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT, + .ops = &mlxsw_sp_fid_rfid_ops, +}; + +static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; + + return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true); +} + +static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid) +{ + mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); +} + +static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid, + const void *arg, u16 *p_fid_index) +{ + *p_fid_index = fid->fid_family->start_index; + + return 0; +} + +static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid, + const void *arg) +{ + return true; +} + +static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = { + .configure = mlxsw_sp_fid_dummy_configure, + .deconfigure = mlxsw_sp_fid_dummy_deconfigure, + .index_alloc = mlxsw_sp_fid_dummy_index_alloc, + .compare = mlxsw_sp_fid_dummy_compare, +}; + +static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = { + .type = MLXSW_SP_FID_TYPE_DUMMY, + .fid_size = sizeof(struct mlxsw_sp_fid), + .start_index = MLXSW_SP_RFID_BASE - 1, + .end_index = MLXSW_SP_RFID_BASE - 1, + .ops = &mlxsw_sp_fid_dummy_ops, +}; + +static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = { + [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp_fid_8021q_family, + [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp_fid_8021d_family, + [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family, + [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family, +}; + +static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, + enum mlxsw_sp_fid_type type, + const void *arg) +{ + struct mlxsw_sp_fid_family *fid_family; + struct mlxsw_sp_fid *fid; + u16 fid_index; + int err; + + fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; + list_for_each_entry(fid, &fid_family->fids_list, list) { + if (!fid->fid_family->ops->compare(fid, arg)) + continue; + fid->ref_count++; + return fid; + } + + fid = kzalloc(fid_family->fid_size, GFP_KERNEL); + if (!fid) + return ERR_PTR(-ENOMEM); + fid->fid_family = fid_family; + + err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index); + if (err) + goto err_index_alloc; + fid->fid_index = fid_index; + __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap); + + if (fid->fid_family->ops->setup) + fid->fid_family->ops->setup(fid, arg); + + err = fid->fid_family->ops->configure(fid); + if (err) + goto err_configure; + + list_add(&fid->list, &fid_family->fids_list); + fid->ref_count++; + return fid; + +err_configure: + __clear_bit(fid_index - fid_family->start_index, + fid_family->fids_bitmap); +err_index_alloc: + kfree(fid); + return ERR_PTR(err); +} + +void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid) +{ + struct mlxsw_sp_fid_family *fid_family = fid->fid_family; + + if (--fid->ref_count == 1 && fid->rif) { + /* Destroy the associated RIF and let it drop the last + * reference on the FID. + */ + return mlxsw_sp_rif_destroy(fid_family->mlxsw_sp, fid->rif); + } else if (fid->ref_count == 0) { + list_del(&fid->list); + fid->fid_family->ops->deconfigure(fid); + __clear_bit(fid->fid_index - fid_family->start_index, + fid_family->fids_bitmap); + kfree(fid); + } +} + +struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid) +{ + return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid); +} + +struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, + int br_ifindex) +{ + return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex); +} + +struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp, + u16 rif_index) +{ + return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index); +} + +struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp) +{ + return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL); +} + +static int +mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, + const struct mlxsw_sp_flood_table *flood_table) +{ + enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; + const int *sfgc_packet_types; + int i; + + sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; + for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { + struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; + char sfgc_pl[MLXSW_REG_SFGC_LEN]; + int err; + + if (!sfgc_packet_types[i]) + continue; + mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type, + flood_table->table_type, + flood_table->table_index); + err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); + if (err) + return err; + } + + return 0; +} + +static int +mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) +{ + int i; + + for (i = 0; i < fid_family->nr_flood_tables; i++) { + const struct mlxsw_sp_flood_table *flood_table; + int err; + + flood_table = &fid_family->flood_tables[i]; + err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table); + if (err) + return err; + } + + return 0; +} + +static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp, + const struct mlxsw_sp_fid_family *tmpl) +{ + u16 nr_fids = tmpl->end_index - tmpl->start_index + 1; + struct mlxsw_sp_fid_family *fid_family; + int err; + + fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL); + if (!fid_family) + return -ENOMEM; + + fid_family->mlxsw_sp = mlxsw_sp; + INIT_LIST_HEAD(&fid_family->fids_list); + fid_family->fids_bitmap = kcalloc(BITS_TO_LONGS(nr_fids), + sizeof(unsigned long), GFP_KERNEL); + if (!fid_family->fids_bitmap) { + err = -ENOMEM; + goto err_alloc_fids_bitmap; + } + + if (fid_family->flood_tables) { + err = mlxsw_sp_fid_flood_tables_init(fid_family); + if (err) + goto err_fid_flood_tables_init; + } + + mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family; + + return 0; + +err_fid_flood_tables_init: + kfree(fid_family->fids_bitmap); +err_alloc_fids_bitmap: + kfree(fid_family); + return err; +} + +static void +mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_fid_family *fid_family) +{ + mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL; + kfree(fid_family->fids_bitmap); + WARN_ON_ONCE(!list_empty(&fid_family->fids_list)); + kfree(fid_family); +} + +int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + + /* Track number of FIDs configured on the port with mapping type + * PORT_VID_TO_FID, so that we know when to transition the port + * back to non-virtual (VLAN) mode. + */ + mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; + + return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); +} + +void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + + mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; +} + +int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) +{ + unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); + struct mlxsw_sp_fid_core *fid_core; + int err, i; + + fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL); + if (!fid_core) + return -ENOMEM; + mlxsw_sp->fid_core = fid_core; + + fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int), + GFP_KERNEL); + if (!fid_core->port_fid_mappings) { + err = -ENOMEM; + goto err_alloc_port_fid_mappings; + } + + for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) { + err = mlxsw_sp_fid_family_register(mlxsw_sp, + mlxsw_sp_fid_family_arr[i]); + + if (err) + goto err_fid_ops_register; + } + + return 0; + +err_fid_ops_register: + for (i--; i >= 0; i--) { + struct mlxsw_sp_fid_family *fid_family; + + fid_family = fid_core->fid_family_arr[i]; + mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family); + } + kfree(fid_core->port_fid_mappings); +err_alloc_port_fid_mappings: + kfree(fid_core); + return err; +} + +void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) +{ + struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; + int i; + + for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) + mlxsw_sp_fid_family_unregister(mlxsw_sp, + fid_core->fid_family_arr[i]); + kfree(fid_core->port_fid_mappings); + kfree(fid_core); +} diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c index 739dc1ed759b..ed75c6a85bc3 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c @@ -70,9 +70,13 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp, } else if (is_tcf_mirred_egress_redirect(a)) { int ifindex = tcf_mirred_ifindex(a); struct net_device *out_dev; + struct mlxsw_sp_fid *fid; + u16 fid_index; + fid = mlxsw_sp_acl_dummy_fid(mlxsw_sp); + fid_index = mlxsw_sp_fid_index(fid); err = mlxsw_sp_acl_rulei_act_fid_set(mlxsw_sp, rulei, - MLXSW_SP_DUMMY_FID); + fid_index); if (err) return err; diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 0c0ec2aa1933..3c2e47deca0c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -86,7 +86,7 @@ struct mlxsw_sp_rif { struct list_head nexthop_list; struct list_head neigh_list; struct net_device *dev; - struct mlxsw_sp_fid *f; + struct mlxsw_sp_fid *fid; unsigned char addr[ETH_ALEN]; int mtu; u16 rif_index; @@ -2946,34 +2946,9 @@ mlxsw_sp_port_vlan_rif_sp_op(struct mlxsw_sp *mlxsw_sp, return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); } -static void -mlxsw_sp_port_vlan_rif_sp_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan); - -static u16 mlxsw_sp_rif_sp_to_fid(u16 rif_index) -{ - return MLXSW_SP_RFID_BASE + rif_index; -} - -static struct mlxsw_sp_fid * -mlxsw_sp_rfid_alloc(u16 fid, struct net_device *l3_dev) -{ - struct mlxsw_sp_fid *f; - - f = kzalloc(sizeof(*f), GFP_KERNEL); - if (!f) - return NULL; - - f->leave = mlxsw_sp_port_vlan_rif_sp_leave; - f->ref_count = 0; - f->dev = l3_dev; - f->fid = fid; - - return f; -} - static struct mlxsw_sp_rif * mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev, - struct mlxsw_sp_fid *f, bool is_subport) + struct mlxsw_sp_fid *fid, bool is_subport) { size_t size = is_subport ? sizeof(struct mlxsw_sp_rif_subport) : sizeof(struct mlxsw_sp_rif); @@ -2990,7 +2965,7 @@ mlxsw_sp_rif_alloc(u16 rif_index, u16 vr_id, struct net_device *l3_dev, rif->vr_id = vr_id; rif->dev = l3_dev; rif->rif_index = rif_index; - rif->f = f; + rif->fid = fid; return rif; } @@ -3019,10 +2994,10 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp_rif_subport *rif_subport; u32 tb_id = l3mdev_fib_table(l3_dev); - struct mlxsw_sp_vr *vr; - struct mlxsw_sp_fid *f; struct mlxsw_sp_rif *rif; - u16 fid, rif_index; + struct mlxsw_sp_fid *fid; + struct mlxsw_sp_vr *vr; + u16 rif_index; int err; vr = mlxsw_sp_vr_get(mlxsw_sp, tb_id ? : RT_TABLE_MAIN); @@ -3035,14 +3010,13 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, goto err_avail_rif_get; } - fid = mlxsw_sp_rif_sp_to_fid(rif_index); - f = mlxsw_sp_rfid_alloc(fid, l3_dev); - if (!f) { - err = -ENOMEM; - goto err_rfid_alloc; + fid = mlxsw_sp_fid_rfid_get(mlxsw_sp, rif_index); + if (IS_ERR(fid)) { + err = PTR_ERR(fid); + goto err_fid_get; } - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, true); + rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, fid, true); if (!rif) { err = -ENOMEM; goto err_rif_alloc; @@ -3062,7 +3036,8 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, if (err) goto err_port_vlan_rif_sp_op; - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, true); + err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, + mlxsw_sp_fid_index(fid), true); if (err) goto err_rif_fdb_op; @@ -3075,7 +3050,7 @@ mlxsw_sp_port_vlan_rif_sp_create(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, "Counter alloc Failed err=%d\n", err); } - f->rif = rif; + mlxsw_sp_fid_rif_set(fid, rif); mlxsw_sp->router->rifs[rif_index] = rif; vr->rif_count++; @@ -3086,8 +3061,8 @@ err_rif_fdb_op: err_port_vlan_rif_sp_op: kfree(rif); err_rif_alloc: - kfree(f); -err_rfid_alloc: + mlxsw_sp_fid_put(fid); +err_fid_get: err_avail_rif_get: mlxsw_sp_vr_put(vr); return ERR_PTR(err); @@ -3099,9 +3074,8 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id]; struct net_device *l3_dev = rif->dev; - struct mlxsw_sp_fid *f = rif->f; + struct mlxsw_sp_fid *fid = rif->fid; u16 rif_index = rif->rif_index; - u16 fid = f->fid; mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif); @@ -3110,24 +3084,25 @@ mlxsw_sp_port_vlan_rif_sp_destroy(struct mlxsw_sp *mlxsw_sp, vr->rif_count--; mlxsw_sp->router->rifs[rif_index] = NULL; - f->rif = NULL; - - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, fid, false); + mlxsw_sp_fid_rif_set(fid, NULL); + mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, mlxsw_sp_fid_index(fid), + false); mlxsw_sp_port_vlan_rif_sp_op(mlxsw_sp, rif, false); kfree(rif); - kfree(f); + mlxsw_sp_fid_put(fid); mlxsw_sp_vr_put(vr); } static int -mlxsw_sp_port_vlan_rif_sp_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, +mlxsw_sp_port_vlan_router_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, struct net_device *l3_dev) { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; u16 vid = mlxsw_sp_port_vlan->vid; struct mlxsw_sp_rif *rif; + struct mlxsw_sp_fid *fid; int err; rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); @@ -3138,6 +3113,12 @@ mlxsw_sp_port_vlan_rif_sp_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, return PTR_ERR(rif); } + /* FID was already created, just take a reference */ + fid = mlxsw_sp_fid_rfid_get(mlxsw_sp_port->mlxsw_sp, rif->rif_index); + err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid); + if (err) + goto err_fid_port_vid_map; + err = mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false); if (err) goto err_port_vid_learning_set; @@ -3147,47 +3128,37 @@ mlxsw_sp_port_vlan_rif_sp_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, if (err) goto err_port_vid_stp_set; - 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_port_vlan->fid = rif->f; - rif->f->ref_count++; + mlxsw_sp_port_vlan->fid = fid; return 0; -err_port_vp_mode_trans: - mlxsw_sp_port->nr_port_vid_map--; - mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING); err_port_vid_stp_set: mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); err_port_vid_learning_set: - if (rif->f->ref_count == 0) - mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, rif); + mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid); +err_fid_port_vid_map: + mlxsw_sp_fid_put(fid); return err; } -static void -mlxsw_sp_port_vlan_rif_sp_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) +void +mlxsw_sp_port_vlan_router_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; u16 vid = mlxsw_sp_port_vlan->vid; - fid->ref_count--; - mlxsw_sp_port_vlan->fid = NULL; + if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_RFID)) + return; - 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_vlan->fid = NULL; mlxsw_sp_port_vid_stp_set(mlxsw_sp_port, vid, BR_STATE_BLOCKING); mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, true); - - if (fid->ref_count == 0) - mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, fid->rif); + mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid); + /* If router port holds the last reference on the rFID, then the + * associated Sub-port RIF will be destroyed. + */ + mlxsw_sp_fid_put(fid); } static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev, @@ -3203,10 +3174,10 @@ static int mlxsw_sp_inetaddr_port_vlan_event(struct net_device *l3_dev, switch (event) { case NETDEV_UP: - return mlxsw_sp_port_vlan_rif_sp_join(mlxsw_sp_port_vlan, + return mlxsw_sp_port_vlan_router_join(mlxsw_sp_port_vlan, l3_dev); case NETDEV_DOWN: - mlxsw_sp_port_vlan_rif_sp_leave(mlxsw_sp_port_vlan); + mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); break; } @@ -3254,96 +3225,65 @@ static int mlxsw_sp_inetaddr_lag_event(struct net_device *lag_dev, return __mlxsw_sp_inetaddr_lag_event(lag_dev, lag_dev, event, 1); } -static struct mlxsw_sp_fid *mlxsw_sp_bridge_fid_get(struct mlxsw_sp *mlxsw_sp, - struct net_device *l3_dev) -{ - struct mlxsw_sp_fid *fid; - u16 fid_index; - - if (is_vlan_dev(l3_dev)) - fid_index = vlan_dev_vlan_id(l3_dev); - else if (br_vlan_enabled(l3_dev)) - fid_index = 1; - else - return mlxsw_sp_vfid_find(mlxsw_sp, l3_dev); - - fid = mlxsw_sp_fid_find(mlxsw_sp, fid_index); - if (fid) - return fid; - - fid = mlxsw_sp_fid_create(mlxsw_sp, fid_index); - if (IS_ERR(fid)) - return NULL; - return fid; -} - static u8 mlxsw_sp_router_port(const struct mlxsw_sp *mlxsw_sp) { return mlxsw_core_max_ports(mlxsw_sp->core) + 1; } -static enum mlxsw_flood_table_type mlxsw_sp_flood_table_type_get(u16 fid) -{ - return mlxsw_sp_fid_is_vfid(fid) ? MLXSW_REG_SFGC_TABLE_TYPE_FID : - MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST; -} - -static u16 mlxsw_sp_flood_table_index_get(u16 fid) -{ - return mlxsw_sp_fid_is_vfid(fid) ? mlxsw_sp_fid_to_vfid(fid) : fid; -} - -static int mlxsw_sp_router_port_flood_set(struct mlxsw_sp *mlxsw_sp, u16 fid, - bool set) -{ - u8 router_port = mlxsw_sp_router_port(mlxsw_sp); - enum mlxsw_flood_table_type table_type; - char *sftr_pl; - u16 index; - int err; - - sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL); - if (!sftr_pl) - return -ENOMEM; - - table_type = mlxsw_sp_flood_table_type_get(fid); - index = mlxsw_sp_flood_table_index_get(fid); - mlxsw_reg_sftr_pack(sftr_pl, MLXSW_SP_FLOOD_TABLE_BC, index, table_type, - 1, router_port, set); - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl); - - kfree(sftr_pl); - return err; -} - -static enum mlxsw_reg_ritr_if_type mlxsw_sp_rif_type_get(u16 fid) +static enum mlxsw_reg_ritr_if_type +mlxsw_sp_rif_type_ritr_if_type(enum mlxsw_sp_rif_type rif_type) { - if (mlxsw_sp_fid_is_vfid(fid)) - return MLXSW_REG_RITR_FID_IF; - else + switch (rif_type) { + case MLXSW_SP_RIF_TYPE_SUBPORT: + return MLXSW_REG_RITR_SP_IF; + case MLXSW_SP_RIF_TYPE_VLAN: return MLXSW_REG_RITR_VLAN_IF; + case MLXSW_SP_RIF_TYPE_FID: + return MLXSW_REG_RITR_FID_IF; + default: + WARN_ON(1); + return 0; + } } static int mlxsw_sp_rif_bridge_op(struct mlxsw_sp *mlxsw_sp, const struct mlxsw_sp_rif *rif, bool create) { - enum mlxsw_reg_ritr_if_type rif_type; + enum mlxsw_reg_ritr_if_type ritr_if_type; + enum mlxsw_sp_rif_type rif_type; char ritr_pl[MLXSW_REG_RITR_LEN]; - rif_type = mlxsw_sp_rif_type_get(rif->f->fid); + rif_type = mlxsw_sp_fid_rif_type(rif->fid); + ritr_if_type = mlxsw_sp_rif_type_ritr_if_type(rif_type); mlxsw_reg_ritr_pack(ritr_pl, create, rif_type, rif->rif_index, rif->vr_id, rif->dev->mtu, rif->dev->dev_addr); - mlxsw_reg_ritr_fid_set(ritr_pl, rif_type, rif->f->fid); + mlxsw_reg_ritr_fid_set(ritr_pl, ritr_if_type, + mlxsw_sp_fid_index(rif->fid)); return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl); } +static struct mlxsw_sp_fid * +mlxsw_sp_rif_bridge_fid_get(struct mlxsw_sp *mlxsw_sp, + const struct net_device *dev) +{ + if (netif_is_bridge_master(dev) && !br_vlan_enabled(dev)) + return mlxsw_sp_fid_8021d_get(mlxsw_sp, dev->ifindex); + else if (netif_is_bridge_master(dev) && br_vlan_enabled(dev)) + return mlxsw_sp_fid_8021q_get(mlxsw_sp, 1); + else if (is_vlan_dev(dev) && + netif_is_bridge_master(vlan_dev_real_dev(dev))) + return mlxsw_sp_fid_8021q_get(mlxsw_sp, vlan_dev_vlan_id(dev)); + else + return ERR_PTR(-EINVAL); +} + static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, - struct net_device *l3_dev, - struct mlxsw_sp_fid *f) + struct net_device *l3_dev) { u32 tb_id = l3mdev_fib_table(l3_dev); struct mlxsw_sp_rif *rif; + struct mlxsw_sp_fid *fid; struct mlxsw_sp_vr *vr; u16 rif_index; int err; @@ -3358,7 +3298,13 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, goto err_avail_rif_get; } - rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, f, false); + fid = mlxsw_sp_rif_bridge_fid_get(mlxsw_sp, l3_dev); + if (IS_ERR(fid)) { + err = PTR_ERR(fid); + goto err_fid_get; + } + + rif = mlxsw_sp_rif_alloc(rif_index, vr->id, l3_dev, fid, false); if (!rif) { err = -ENOMEM; goto err_rif_alloc; @@ -3368,15 +3314,17 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, if (err) goto err_rif_bridge_op; - err = mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, true); + err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), true); if (err) - goto err_port_flood_set; + goto err_fid_bc_flood_set; - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, true); + err = mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, + mlxsw_sp_fid_index(fid), true); if (err) goto err_rif_fdb_op; - f->rif = rif; + mlxsw_sp_fid_rif_set(fid, rif); mlxsw_sp->router->rifs[rif_index] = rif; vr->rif_count++; @@ -3385,64 +3333,58 @@ static int mlxsw_sp_rif_bridge_create(struct mlxsw_sp *mlxsw_sp, return 0; err_rif_fdb_op: - mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false); -err_port_flood_set: + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), false); +err_fid_bc_flood_set: mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false); err_rif_bridge_op: kfree(rif); err_rif_alloc: + mlxsw_sp_fid_put(fid); +err_fid_get: err_avail_rif_get: mlxsw_sp_vr_put(vr); return err; } -void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_rif *rif) +static void mlxsw_sp_rif_bridge_destroy(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_rif *rif) { struct mlxsw_sp_vr *vr = &mlxsw_sp->router->vrs[rif->vr_id]; struct net_device *l3_dev = rif->dev; - struct mlxsw_sp_fid *f = rif->f; + struct mlxsw_sp_fid *fid = rif->fid; u16 rif_index = rif->rif_index; mlxsw_sp_router_rif_gone_sync(mlxsw_sp, rif); vr->rif_count--; mlxsw_sp->router->rifs[rif_index] = NULL; - f->rif = NULL; - - mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, f->fid, false); - - mlxsw_sp_router_port_flood_set(mlxsw_sp, f->fid, false); + mlxsw_sp_fid_rif_set(fid, NULL); + mlxsw_sp_rif_fdb_op(mlxsw_sp, l3_dev->dev_addr, mlxsw_sp_fid_index(fid), + false); + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, + mlxsw_sp_router_port(mlxsw_sp), false); mlxsw_sp_rif_bridge_op(mlxsw_sp, rif, false); - kfree(rif); - + mlxsw_sp_fid_put(fid); mlxsw_sp_vr_put(vr); netdev_dbg(l3_dev, "RIF=%d destroyed\n", rif_index); } static int mlxsw_sp_inetaddr_bridge_event(struct net_device *l3_dev, - struct net_device *br_dev, unsigned long event) { struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(l3_dev); - struct mlxsw_sp_fid *f; - - /* FID can either be an actual FID if the L3 device is the - * VLAN-aware bridge or a VLAN device on top. Otherwise, the - * L3 device is a VLAN-unaware bridge and we get a vFID. - */ - f = mlxsw_sp_bridge_fid_get(mlxsw_sp, l3_dev); - if (WARN_ON(!f)) - return -EINVAL; + struct mlxsw_sp_rif *rif; switch (event) { case NETDEV_UP: - return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev, f); + return mlxsw_sp_rif_bridge_create(mlxsw_sp, l3_dev); case NETDEV_DOWN: - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, f->rif); + rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, l3_dev); + mlxsw_sp_rif_bridge_destroy(mlxsw_sp, rif); break; } @@ -3462,8 +3404,7 @@ static int mlxsw_sp_inetaddr_vlan_event(struct net_device *vlan_dev, return __mlxsw_sp_inetaddr_lag_event(vlan_dev, real_dev, event, vid); else if (netif_is_bridge_master(real_dev) && br_vlan_enabled(real_dev)) - return mlxsw_sp_inetaddr_bridge_event(vlan_dev, real_dev, - event); + return mlxsw_sp_inetaddr_bridge_event(vlan_dev, event); return 0; } @@ -3476,7 +3417,7 @@ static int __mlxsw_sp_inetaddr_event(struct net_device *dev, else if (netif_is_lag_master(dev)) return mlxsw_sp_inetaddr_lag_event(dev, event); else if (netif_is_bridge_master(dev)) - return mlxsw_sp_inetaddr_bridge_event(dev, dev, event); + return mlxsw_sp_inetaddr_bridge_event(dev, event); else if (is_vlan_dev(dev)) return mlxsw_sp_inetaddr_vlan_event(dev, event); else @@ -3526,6 +3467,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) { struct mlxsw_sp *mlxsw_sp; struct mlxsw_sp_rif *rif; + u16 fid_index; int err; mlxsw_sp = mlxsw_sp_lower_get(dev); @@ -3535,8 +3477,9 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) rif = mlxsw_sp_rif_find_by_dev(mlxsw_sp, dev); if (!rif) return 0; + fid_index = mlxsw_sp_fid_index(rif->fid); - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, rif->f->fid, false); + err = mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, false); if (err) return err; @@ -3545,7 +3488,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) if (err) goto err_rif_edit; - err = mlxsw_sp_rif_fdb_op(mlxsw_sp, dev->dev_addr, rif->f->fid, true); + err = mlxsw_sp_rif_fdb_op(mlxsw_sp, dev->dev_addr, fid_index, true); if (err) goto err_rif_fdb_op; @@ -3559,7 +3502,7 @@ int mlxsw_sp_netdevice_router_port_event(struct net_device *dev) err_rif_fdb_op: mlxsw_sp_rif_edit(mlxsw_sp, rif->rif_index, rif->addr, rif->mtu); err_rif_edit: - mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, rif->f->fid, true); + mlxsw_sp_rif_fdb_op(mlxsw_sp, rif->addr, fid_index, true); return err; } @@ -3612,6 +3555,14 @@ int mlxsw_sp_netdevice_vrf_event(struct net_device *l3_dev, unsigned long event, return err; } +void mlxsw_sp_rif_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_rif *rif) +{ + if (mlxsw_sp_fid_rif_type(rif->fid) == MLXSW_SP_RIF_TYPE_SUBPORT) + mlxsw_sp_port_vlan_rif_sp_destroy(mlxsw_sp, rif); + else + mlxsw_sp_rif_bridge_destroy(mlxsw_sp, rif); +} + static int mlxsw_sp_rifs_init(struct mlxsw_sp *mlxsw_sp) { u64 max_rifs = MLXSW_CORE_RES_GET(mlxsw_sp->core, MAX_RIFS); diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index b17b224f2b1c..edcc273d7597 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -113,6 +113,9 @@ struct mlxsw_sp_bridge_ops { void (*port_leave)(struct mlxsw_sp_bridge_device *bridge_device, struct mlxsw_sp_bridge_port *bridge_port, struct mlxsw_sp_port *mlxsw_sp_port); + struct mlxsw_sp_fid * + (*fid_get)(struct mlxsw_sp_bridge_device *bridge_device, + u16 vid); }; static int @@ -361,7 +364,7 @@ mlxsw_sp_port_vlan_find_by_fid(struct mlxsw_sp_port *mlxsw_sp_port, list) { struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; - if (fid && fid->fid == fid_index) + if (fid && mlxsw_sp_fid_index(fid) == fid_index) return mlxsw_sp_port_vlan; } @@ -517,40 +520,10 @@ err_port_bridge_vlan_stp_set: return err; } -static int mlxsw_sp_port_fid_flood_set(struct mlxsw_sp_port *mlxsw_sp_port, - struct mlxsw_sp_fid *fid, - enum mlxsw_sp_flood_table table, - bool member) -{ - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; - u16 local_port = mlxsw_sp_port->local_port; - enum mlxsw_flood_table_type table_type; - u16 flood_index = fid->fid; - char *sftr_pl; - int err; - - table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFEST; - if (mlxsw_sp_fid_is_vfid(fid->fid)) { - table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID; - flood_index = mlxsw_sp_fid_to_vfid(fid->fid); - } - - sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL); - if (!sftr_pl) - return -ENOMEM; - - mlxsw_reg_sftr_pack(sftr_pl, table, flood_index, table_type, 1, - local_port, member); - err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sftr), sftr_pl); - - kfree(sftr_pl); - return err; -} - static int mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port, struct mlxsw_sp_bridge_vlan *bridge_vlan, - enum mlxsw_sp_flood_table table, + enum mlxsw_sp_flood_type packet_type, bool member) { struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; @@ -559,9 +532,10 @@ mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port, bridge_vlan_node) { if (mlxsw_sp_port_vlan->mlxsw_sp_port != mlxsw_sp_port) continue; - return mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, - mlxsw_sp_port_vlan->fid, - table, member); + return mlxsw_sp_fid_flood_set(mlxsw_sp_port_vlan->fid, + packet_type, + mlxsw_sp_port->local_port, + member); } return 0; @@ -570,7 +544,7 @@ mlxsw_sp_port_bridge_vlan_flood_set(struct mlxsw_sp_port *mlxsw_sp_port, static int mlxsw_sp_bridge_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port, struct mlxsw_sp_bridge_port *bridge_port, - enum mlxsw_sp_flood_table table, + enum mlxsw_sp_flood_type packet_type, bool member) { struct mlxsw_sp_bridge_vlan *bridge_vlan; @@ -578,7 +552,8 @@ mlxsw_sp_bridge_port_flood_table_set(struct mlxsw_sp_port *mlxsw_sp_port, list_for_each_entry(bridge_vlan, &bridge_port->vlans_list, list) { err = mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port, - bridge_vlan, table, + bridge_vlan, + packet_type, member); if (err) goto err_port_bridge_vlan_flood_set; @@ -590,7 +565,7 @@ err_port_bridge_vlan_flood_set: list_for_each_entry_continue_reverse(bridge_vlan, &bridge_port->vlans_list, list) mlxsw_sp_port_bridge_vlan_flood_set(mlxsw_sp_port, bridge_vlan, - table, !member); + packet_type, !member); return err; } @@ -654,7 +629,7 @@ static int mlxsw_sp_port_attr_br_flags_set(struct mlxsw_sp_port *mlxsw_sp_port, return -EINVAL; err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port, - MLXSW_SP_FLOOD_TABLE_UC, + MLXSW_SP_FLOOD_TYPE_UC, brport_flags & BR_FLOOD); if (err) return err; @@ -742,7 +717,7 @@ static int mlxsw_sp_port_attr_mc_router_set(struct mlxsw_sp_port *mlxsw_sp_port, return 0; return mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, bridge_port, - MLXSW_SP_FLOOD_TABLE_MC, + MLXSW_SP_FLOOD_TYPE_MC, is_port_mc_router); } @@ -767,12 +742,12 @@ static int mlxsw_sp_port_mc_disabled_set(struct mlxsw_sp_port *mlxsw_sp_port, return 0; list_for_each_entry(bridge_port, &bridge_device->ports_list, list) { - enum mlxsw_sp_flood_table table = MLXSW_SP_FLOOD_TABLE_MC; + enum mlxsw_sp_flood_type packet_type = MLXSW_SP_FLOOD_TYPE_MC; bool member = mc_disabled ? true : bridge_port->mrouter; err = mlxsw_sp_bridge_port_flood_table_set(mlxsw_sp_port, - bridge_port, table, - member); + bridge_port, + packet_type, member); if (err) return err; } @@ -827,189 +802,6 @@ static int mlxsw_sp_port_attr_set(struct net_device *dev, return err; } -static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) -{ - return valid ? MLXSW_REG_SFMR_OP_CREATE_FID : - MLXSW_REG_SFMR_OP_DESTROY_FID; -} - -int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, bool valid) -{ - u16 fid_offset = fid_index < MLXSW_SP_VFID_BASE ? fid_index : 0; - char sfmr_pl[MLXSW_REG_SFMR_LEN]; - - mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index, - fid_offset); - 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_index, - 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_index, fid_index); - return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); -} - -struct mlxsw_sp_fid *mlxsw_sp_fid_create(struct mlxsw_sp *mlxsw_sp, - u16 fid_index) -{ - struct mlxsw_sp_fid *fid; - int err; - - err = mlxsw_sp_fid_op(mlxsw_sp, fid_index, true); - if (err) - return ERR_PTR(err); - - err = mlxsw_sp_fid_map(mlxsw_sp, fid_index, true); - if (err) - goto err_fid_map; - - fid = kzalloc(sizeof(*fid), GFP_KERNEL); - if (!fid) { - err = -ENOMEM; - goto err_allocate_fid; - } - - fid->fid = fid_index; - fid->ref_count = 1; - list_add(&fid->list, &mlxsw_sp->fids); - - return fid; - -err_allocate_fid: - mlxsw_sp_fid_map(mlxsw_sp, fid_index, false); -err_fid_map: - mlxsw_sp_fid_op(mlxsw_sp, fid_index, false); - return ERR_PTR(err); -} - -static void mlxsw_sp_fid_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_fid *fid) -{ - u16 fid_index = fid->fid; - - list_del(&fid->list); - if (fid->rif) - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, fid->rif); - kfree(fid); - mlxsw_sp_fid_map(mlxsw_sp, fid_index, false); - mlxsw_sp_fid_op(mlxsw_sp, fid_index, false); -} - -static struct mlxsw_sp_fid *mlxsw_sp_vfid_create(struct mlxsw_sp *mlxsw_sp, - struct net_device *dev) -{ - u16 vfid_index, fid_index; - struct mlxsw_sp_fid *fid; - int err; - - vfid_index = find_first_zero_bit(mlxsw_sp->vfids.mapped, - MLXSW_SP_VFID_MAX); - if (vfid_index == MLXSW_SP_VFID_MAX) - return ERR_PTR(-ENOBUFS); - - fid_index = mlxsw_sp_vfid_to_fid(vfid_index); - err = mlxsw_sp_fid_op(mlxsw_sp, fid_index, true); - if (err) - return ERR_PTR(err); - - fid = kzalloc(sizeof(*fid), GFP_KERNEL); - if (!fid) { - err = -ENOMEM; - goto err_allocate_fid; - } - - fid->fid = fid_index; - fid->ref_count = 1; - fid->dev = dev; - list_add(&fid->list, &mlxsw_sp->vfids.list); - __set_bit(vfid_index, mlxsw_sp->vfids.mapped); - - return fid; - -err_allocate_fid: - mlxsw_sp_fid_op(mlxsw_sp, fid_index, false); - return ERR_PTR(err); -} - -static void mlxsw_sp_vfid_destroy(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_fid *fid) -{ - u16 vfid_index = mlxsw_sp_fid_to_vfid(fid->fid); - u16 fid_index = fid->fid; - - __clear_bit(vfid_index, mlxsw_sp->vfids.mapped); - list_del(&fid->list); - if (fid->rif) - mlxsw_sp_rif_bridge_destroy(mlxsw_sp, fid->rif); - kfree(fid); - mlxsw_sp_fid_op(mlxsw_sp, fid_index, false); -} - -static struct mlxsw_sp_fid *__mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, - u16 fid_index) -{ - struct mlxsw_sp_fid *fid; - - fid = mlxsw_sp_fid_find(mlxsw_sp, fid_index); - if (fid) { - fid->ref_count++; - return fid; - } - - return mlxsw_sp_fid_create(mlxsw_sp, fid_index); -} - -static struct mlxsw_sp_fid *mlxsw_sp_vfid_get(struct mlxsw_sp *mlxsw_sp, - struct net_device *dev) -{ - struct mlxsw_sp_fid *fid; - - fid = mlxsw_sp_vfid_find(mlxsw_sp, dev); - if (fid) { - fid->ref_count++; - return fid; - } - - return mlxsw_sp_vfid_create(mlxsw_sp, dev); -} - -static struct mlxsw_sp_fid * -mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, u16 vid, - struct mlxsw_sp_bridge_device *bridge_device) -{ - if (bridge_device->vlan_enabled) - return __mlxsw_sp_fid_get(mlxsw_sp, vid); - else - return mlxsw_sp_vfid_get(mlxsw_sp, bridge_device->dev); -} - -static void __mlxsw_sp_fid_put(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_fid *fid) -{ - if (--fid->ref_count == 0) - mlxsw_sp_fid_destroy(mlxsw_sp, fid); -} - -static void mlxsw_sp_vfid_put(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_fid *fid) -{ - if (--fid->ref_count == 0) - mlxsw_sp_vfid_destroy(mlxsw_sp, fid); -} - -static void mlxsw_sp_fid_put(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_fid *fid) -{ - if (!mlxsw_sp_fid_is_vfid(fid->fid)) - __mlxsw_sp_fid_put(mlxsw_sp, fid); - else - mlxsw_sp_vfid_put(mlxsw_sp, fid); -} - static bool mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port *bridge_port) { const struct mlxsw_sp_bridge_device *bridge_device; @@ -1018,126 +810,53 @@ static bool mlxsw_sp_mc_flood(const struct mlxsw_sp_bridge_port *bridge_port) return !bridge_device->multicast_enabled ? true : bridge_port->mrouter; } -static int __mlxsw_sp_port_vid_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid, u16 fid_index) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - int err; - - err = mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, fid_index, - vid); - if (err) - return err; - - 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; - } - - return 0; - -err_port_vp_mode_trans: - mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid_index, vid); - return err; -} - -static int __mlxsw_sp_port_vid_fid_unmap(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid, u16 fid_index) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - - 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_to_fid_set(mlxsw_sp_port, mt, false, fid_index, vid); - - return 0; -} - -static int mlxsw_sp_port_vid_fid_map(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid, u16 fid_index) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - - if (mlxsw_sp_fid_is_vfid(fid_index)) - return __mlxsw_sp_port_vid_fid_map(mlxsw_sp_port, vid, - fid_index); - - if (mlxsw_sp_port->nr_port_vid_map == 0) - return 0; - - return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, true, fid_index, - fid_index); -} - -static int mlxsw_sp_port_vid_fid_unmap(struct mlxsw_sp_port *mlxsw_sp_port, - u16 vid, u16 fid_index) -{ - enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; - - if (mlxsw_sp_fid_is_vfid(fid_index)) - return __mlxsw_sp_port_vid_fid_unmap(mlxsw_sp_port, vid, - fid_index); - - if (mlxsw_sp_port->nr_port_vid_map == 0) - return 0; - - return mlxsw_sp_port_vid_to_fid_set(mlxsw_sp_port, mt, false, fid_index, - fid_index); -} - static int mlxsw_sp_port_vlan_fid_join(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan, struct mlxsw_sp_bridge_port *bridge_port) { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; + struct mlxsw_sp_bridge_device *bridge_device; + u8 local_port = mlxsw_sp_port->local_port; u16 vid = mlxsw_sp_port_vlan->vid; struct mlxsw_sp_fid *fid; int err; - fid = mlxsw_sp_fid_get(mlxsw_sp, vid, bridge_port->bridge_device); + bridge_device = bridge_port->bridge_device; + fid = bridge_device->ops->fid_get(bridge_device, vid); if (IS_ERR(fid)) return PTR_ERR(fid); - err = mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, - MLXSW_SP_FLOOD_TABLE_UC, - bridge_port->flags & BR_FLOOD); + err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, + bridge_port->flags & BR_FLOOD); if (err) - goto err_port_fid_uc_flood_set; + goto err_fid_uc_flood_set; - err = mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, - MLXSW_SP_FLOOD_TABLE_MC, - mlxsw_sp_mc_flood(bridge_port)); + err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, + mlxsw_sp_mc_flood(bridge_port)); if (err) - goto err_port_fid_mc_flood_set; + goto err_fid_mc_flood_set; - err = mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, - MLXSW_SP_FLOOD_TABLE_BC, true); + err = mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, + true); if (err) - goto err_port_fid_bc_flood_set; + goto err_fid_bc_flood_set; - err = mlxsw_sp_port_vid_fid_map(mlxsw_sp_port, vid, fid->fid); + err = mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port, vid); if (err) - goto err_port_vid_fid_map; + goto err_fid_port_vid_map; mlxsw_sp_port_vlan->fid = fid; return 0; -err_port_vid_fid_map: - mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_BC, - false); -err_port_fid_bc_flood_set: - mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_MC, - false); -err_port_fid_mc_flood_set: - mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_UC, - false); -err_port_fid_uc_flood_set: - mlxsw_sp_fid_put(mlxsw_sp, fid); +err_fid_port_vid_map: + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false); +err_fid_bc_flood_set: + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false); +err_fid_mc_flood_set: + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false); +err_fid_uc_flood_set: + mlxsw_sp_fid_put(fid); return err; } @@ -1145,19 +864,16 @@ static void mlxsw_sp_port_vlan_fid_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) { struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp_port_vlan->mlxsw_sp_port; - struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; + u8 local_port = mlxsw_sp_port->local_port; u16 vid = mlxsw_sp_port_vlan->vid; mlxsw_sp_port_vlan->fid = NULL; - mlxsw_sp_port_vid_fid_unmap(mlxsw_sp_port, vid, fid->fid); - mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_BC, - false); - mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_MC, - false); - mlxsw_sp_port_fid_flood_set(mlxsw_sp_port, fid, MLXSW_SP_FLOOD_TABLE_UC, - false); - mlxsw_sp_fid_put(mlxsw_sp, fid); + mlxsw_sp_fid_port_vid_unmap(fid, mlxsw_sp_port, vid); + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_BC, local_port, false); + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_MC, local_port, false); + mlxsw_sp_fid_flood_set(fid, MLXSW_SP_FLOOD_TYPE_UC, local_port, false); + mlxsw_sp_fid_put(fid); } static u16 @@ -1233,6 +949,10 @@ mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) u16 vid = mlxsw_sp_port_vlan->vid; bool last; + if (WARN_ON(mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021Q && + mlxsw_sp_fid_type(fid) != MLXSW_SP_FID_TYPE_8021D)) + return; + bridge_port = mlxsw_sp_port_vlan->bridge_port; bridge_vlan = mlxsw_sp_bridge_vlan_find(bridge_port, vid); last = list_is_singular(&bridge_vlan->port_vlan_list); @@ -1243,7 +963,8 @@ mlxsw_sp_port_vlan_bridge_leave(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan) mlxsw_sp_port_vid_learning_set(mlxsw_sp_port, vid, false); if (last) mlxsw_sp_bridge_port_fdb_flush(mlxsw_sp_port->mlxsw_sp, - bridge_port, fid->fid); + bridge_port, + mlxsw_sp_fid_index(fid)); mlxsw_sp_port_vlan_fid_leave(mlxsw_sp_port_vlan); mlxsw_sp_bridge_port_put(mlxsw_sp_port->mlxsw_sp->bridge, bridge_port); @@ -1446,7 +1167,7 @@ mlxsw_sp_port_fdb_static_add(struct mlxsw_sp_port *mlxsw_sp_port, if (!mlxsw_sp_port_vlan) return 0; - fid_index = mlxsw_sp_port_vlan->fid->fid; + fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); vid = mlxsw_sp_port_vlan->vid; if (!mlxsw_sp_port->lagged) @@ -1580,7 +1301,7 @@ static int mlxsw_sp_port_mdb_add(struct mlxsw_sp_port *mlxsw_sp_port, if (WARN_ON(!mlxsw_sp_port_vlan)) return -EINVAL; - fid_index = mlxsw_sp_port_vlan->fid->fid; + fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid_index); if (!mid) { @@ -1706,7 +1427,7 @@ mlxsw_sp_port_fdb_static_del(struct mlxsw_sp_port *mlxsw_sp_port, if (!mlxsw_sp_port_vlan) return 0; - fid_index = mlxsw_sp_port_vlan->fid->fid; + fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); vid = mlxsw_sp_port_vlan->vid; if (!mlxsw_sp_port->lagged) @@ -1746,7 +1467,7 @@ static int mlxsw_sp_port_mdb_del(struct mlxsw_sp_port *mlxsw_sp_port, if (WARN_ON(!mlxsw_sp_port_vlan)) return -EINVAL; - fid_index = mlxsw_sp_port_vlan->fid->fid; + fid_index = mlxsw_sp_fid_index(mlxsw_sp_port_vlan->fid); mid = __mlxsw_sp_mc_get(mlxsw_sp, mdb->addr, fid_index); if (!mid) { @@ -2000,9 +1721,19 @@ mlxsw_sp_bridge_8021q_port_leave(struct mlxsw_sp_bridge_device *bridge_device, mlxsw_sp_port_pvid_set(mlxsw_sp_port, 1); } +static struct mlxsw_sp_fid * +mlxsw_sp_bridge_8021q_fid_get(struct mlxsw_sp_bridge_device *bridge_device, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); + + return mlxsw_sp_fid_8021q_get(mlxsw_sp, vid); +} + static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021q_ops = { .port_join = mlxsw_sp_bridge_8021q_port_join, .port_leave = mlxsw_sp_bridge_8021q_port_leave, + .fid_get = mlxsw_sp_bridge_8021q_fid_get, }; static bool @@ -2028,7 +1759,6 @@ mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device, struct mlxsw_sp_port *mlxsw_sp_port) { struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; - struct mlxsw_sp_fid *fid; u16 vid; if (!is_vlan_dev(bridge_port->dev)) @@ -2038,7 +1768,6 @@ mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device, mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid); if (WARN_ON(!mlxsw_sp_port_vlan)) return -EINVAL; - fid = mlxsw_sp_port_vlan->fid; if (mlxsw_sp_port_is_br_member(mlxsw_sp_port, bridge_device->dev)) { netdev_err(mlxsw_sp_port->dev, "Can't bridge VLAN uppers of the same port\n"); @@ -2046,8 +1775,8 @@ mlxsw_sp_bridge_8021d_port_join(struct mlxsw_sp_bridge_device *bridge_device, } /* Port is no longer usable as a router interface */ - if (fid) - fid->leave(mlxsw_sp_port_vlan); + if (mlxsw_sp_port_vlan->fid) + mlxsw_sp_port_vlan_router_leave(mlxsw_sp_port_vlan); return mlxsw_sp_port_vlan_bridge_join(mlxsw_sp_port_vlan, bridge_port); } @@ -2067,9 +1796,19 @@ mlxsw_sp_bridge_8021d_port_leave(struct mlxsw_sp_bridge_device *bridge_device, mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan); } +static struct mlxsw_sp_fid * +mlxsw_sp_bridge_8021d_fid_get(struct mlxsw_sp_bridge_device *bridge_device, + u16 vid) +{ + struct mlxsw_sp *mlxsw_sp = mlxsw_sp_lower_get(bridge_device->dev); + + return mlxsw_sp_fid_8021d_get(mlxsw_sp, bridge_device->dev->ifindex); +} + static const struct mlxsw_sp_bridge_ops mlxsw_sp_bridge_8021d_ops = { .port_join = mlxsw_sp_bridge_8021d_port_join, .port_leave = mlxsw_sp_bridge_8021d_port_leave, + .fid_get = mlxsw_sp_bridge_8021d_fid_get, }; int mlxsw_sp_port_bridge_join(struct mlxsw_sp_port *mlxsw_sp_port, |