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
 
                                        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];
        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)
 {
        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;
 
 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);
 }
                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);
        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:
        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);
        }
 }
 
-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];
        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)
 {
 
        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) {
                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);
                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");
        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);
 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;
 }
 
        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);
        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 = {
        .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,
        /* 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;
 
 
 #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
 
 #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;
 
        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 {
        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
 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;
        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;
 };
 
 struct mlxsw_sp_bridge_port;
+struct mlxsw_sp_fid;
 
 struct mlxsw_sp_port_vlan {
        struct list_head list;
                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;
 };
 
        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);
 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,
                                  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);
 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);
                                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);
 
 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
 
        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;
        .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)
 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;
 
        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)
        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);
        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);
 
--- /dev/null
+/*
+ * 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);
+}
 
                } 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;
 
 
        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;
        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);
        rif->vr_id = vr_id;
        rif->dev = l3_dev;
        rif->rif_index = rif_index;
-       rif->f = f;
+       rif->fid = fid;
 
        return rif;
 }
        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);
                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;
        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;
 
                                   "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++;
 
 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);
 {
        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);
 
 
        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);
                        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;
        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,
 
        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;
        }
 
        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;
                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;
        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++;
 
        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;
        }
 
                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;
 }
        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
 {
        struct mlxsw_sp *mlxsw_sp;
        struct mlxsw_sp_rif *rif;
+       u16 fid_index;
        int err;
 
        mlxsw_sp = mlxsw_sp_lower_get(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;
 
        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;
 
 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;
 }
 
        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);
 
        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
                            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;
        }
 
        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;
                            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;
 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;
 
        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;
        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;
 }
 
                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;
                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);
 }
 
                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;
        }
        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;
        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;
 }
 
 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
        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);
        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);
        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)
        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) {
        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)
        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) {
        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
                                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))
        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");
        }
 
        /* 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);
 }
        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,