cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

spectrum_fid.c (33092B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
      3
      4#include <linux/kernel.h>
      5#include <linux/bitops.h>
      6#include <linux/if_vlan.h>
      7#include <linux/if_bridge.h>
      8#include <linux/netdevice.h>
      9#include <linux/rhashtable.h>
     10#include <linux/rtnetlink.h>
     11#include <linux/refcount.h>
     12
     13#include "spectrum.h"
     14#include "reg.h"
     15
     16struct mlxsw_sp_fid_family;
     17
     18struct mlxsw_sp_fid_core {
     19	struct rhashtable fid_ht;
     20	struct rhashtable vni_ht;
     21	struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
     22	unsigned int *port_fid_mappings;
     23};
     24
     25struct mlxsw_sp_fid {
     26	struct list_head list;
     27	struct mlxsw_sp_rif *rif;
     28	refcount_t ref_count;
     29	u16 fid_index;
     30	struct mlxsw_sp_fid_family *fid_family;
     31	struct rhash_head ht_node;
     32
     33	struct rhash_head vni_ht_node;
     34	enum mlxsw_sp_nve_type nve_type;
     35	__be32 vni;
     36	u32 nve_flood_index;
     37	int nve_ifindex;
     38	u8 vni_valid:1,
     39	   nve_flood_index_valid:1;
     40};
     41
     42struct mlxsw_sp_fid_8021q {
     43	struct mlxsw_sp_fid common;
     44	u16 vid;
     45};
     46
     47struct mlxsw_sp_fid_8021d {
     48	struct mlxsw_sp_fid common;
     49	int br_ifindex;
     50};
     51
     52static const struct rhashtable_params mlxsw_sp_fid_ht_params = {
     53	.key_len = sizeof_field(struct mlxsw_sp_fid, fid_index),
     54	.key_offset = offsetof(struct mlxsw_sp_fid, fid_index),
     55	.head_offset = offsetof(struct mlxsw_sp_fid, ht_node),
     56};
     57
     58static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = {
     59	.key_len = sizeof_field(struct mlxsw_sp_fid, vni),
     60	.key_offset = offsetof(struct mlxsw_sp_fid, vni),
     61	.head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node),
     62};
     63
     64struct mlxsw_sp_flood_table {
     65	enum mlxsw_sp_flood_type packet_type;
     66	enum mlxsw_reg_sfgc_bridge_type bridge_type;
     67	enum mlxsw_flood_table_type table_type;
     68	int table_index;
     69};
     70
     71struct mlxsw_sp_fid_ops {
     72	void (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
     73	int (*configure)(struct mlxsw_sp_fid *fid);
     74	void (*deconfigure)(struct mlxsw_sp_fid *fid);
     75	int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
     76			   u16 *p_fid_index);
     77	bool (*compare)(const struct mlxsw_sp_fid *fid,
     78			const void *arg);
     79	u16 (*flood_index)(const struct mlxsw_sp_fid *fid);
     80	int (*port_vid_map)(struct mlxsw_sp_fid *fid,
     81			    struct mlxsw_sp_port *port, u16 vid);
     82	void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
     83			       struct mlxsw_sp_port *port, u16 vid);
     84	int (*vni_set)(struct mlxsw_sp_fid *fid, __be32 vni);
     85	void (*vni_clear)(struct mlxsw_sp_fid *fid);
     86	int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid,
     87				   u32 nve_flood_index);
     88	void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);
     89	void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid,
     90				  const struct net_device *nve_dev);
     91};
     92
     93struct mlxsw_sp_fid_family {
     94	enum mlxsw_sp_fid_type type;
     95	size_t fid_size;
     96	u16 start_index;
     97	u16 end_index;
     98	struct list_head fids_list;
     99	unsigned long *fids_bitmap;
    100	const struct mlxsw_sp_flood_table *flood_tables;
    101	int nr_flood_tables;
    102	enum mlxsw_sp_rif_type rif_type;
    103	const struct mlxsw_sp_fid_ops *ops;
    104	struct mlxsw_sp *mlxsw_sp;
    105	u8 lag_vid_valid:1;
    106};
    107
    108static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
    109	[MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST]			= 1,
    110};
    111
    112static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
    113	[MLXSW_REG_SFGC_TYPE_BROADCAST]				= 1,
    114	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP]	= 1,
    115	[MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL]			= 1,
    116	[MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST]			= 1,
    117	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6]	= 1,
    118};
    119
    120static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
    121	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4]	= 1,
    122};
    123
    124static const int *mlxsw_sp_packet_type_sfgc_types[] = {
    125	[MLXSW_SP_FLOOD_TYPE_UC]	= mlxsw_sp_sfgc_uc_packet_types,
    126	[MLXSW_SP_FLOOD_TYPE_BC]	= mlxsw_sp_sfgc_bc_packet_types,
    127	[MLXSW_SP_FLOOD_TYPE_MC]	= mlxsw_sp_sfgc_mc_packet_types,
    128};
    129
    130bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index)
    131{
    132	enum mlxsw_sp_fid_type fid_type = MLXSW_SP_FID_TYPE_DUMMY;
    133	struct mlxsw_sp_fid_family *fid_family;
    134
    135	fid_family = mlxsw_sp->fid_core->fid_family_arr[fid_type];
    136
    137	return fid_family->start_index == fid_index;
    138}
    139
    140bool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid)
    141{
    142	return fid->fid_family->lag_vid_valid;
    143}
    144
    145struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
    146						  u16 fid_index)
    147{
    148	struct mlxsw_sp_fid *fid;
    149
    150	fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index,
    151				     mlxsw_sp_fid_ht_params);
    152	if (fid)
    153		refcount_inc(&fid->ref_count);
    154
    155	return fid;
    156}
    157
    158int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex)
    159{
    160	if (!fid->vni_valid)
    161		return -EINVAL;
    162
    163	*nve_ifindex = fid->nve_ifindex;
    164
    165	return 0;
    166}
    167
    168int mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid,
    169			  enum mlxsw_sp_nve_type *p_type)
    170{
    171	if (!fid->vni_valid)
    172		return -EINVAL;
    173
    174	*p_type = fid->nve_type;
    175
    176	return 0;
    177}
    178
    179struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,
    180						__be32 vni)
    181{
    182	struct mlxsw_sp_fid *fid;
    183
    184	fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni,
    185				     mlxsw_sp_fid_vni_ht_params);
    186	if (fid)
    187		refcount_inc(&fid->ref_count);
    188
    189	return fid;
    190}
    191
    192int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni)
    193{
    194	if (!fid->vni_valid)
    195		return -EINVAL;
    196
    197	*vni = fid->vni;
    198
    199	return 0;
    200}
    201
    202int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
    203				     u32 nve_flood_index)
    204{
    205	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    206	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
    207	int err;
    208
    209	if (WARN_ON(!ops->nve_flood_index_set || fid->nve_flood_index_valid))
    210		return -EINVAL;
    211
    212	err = ops->nve_flood_index_set(fid, nve_flood_index);
    213	if (err)
    214		return err;
    215
    216	fid->nve_flood_index = nve_flood_index;
    217	fid->nve_flood_index_valid = true;
    218
    219	return 0;
    220}
    221
    222void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
    223{
    224	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    225	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
    226
    227	if (WARN_ON(!ops->nve_flood_index_clear || !fid->nve_flood_index_valid))
    228		return;
    229
    230	fid->nve_flood_index_valid = false;
    231	ops->nve_flood_index_clear(fid);
    232}
    233
    234bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
    235{
    236	return fid->nve_flood_index_valid;
    237}
    238
    239int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type,
    240			 __be32 vni, int nve_ifindex)
    241{
    242	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    243	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
    244	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
    245	int err;
    246
    247	if (WARN_ON(!ops->vni_set || fid->vni_valid))
    248		return -EINVAL;
    249
    250	fid->nve_type = type;
    251	fid->nve_ifindex = nve_ifindex;
    252	fid->vni = vni;
    253	err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht,
    254					    &fid->vni_ht_node,
    255					    mlxsw_sp_fid_vni_ht_params);
    256	if (err)
    257		return err;
    258
    259	err = ops->vni_set(fid, vni);
    260	if (err)
    261		goto err_vni_set;
    262
    263	fid->vni_valid = true;
    264
    265	return 0;
    266
    267err_vni_set:
    268	rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
    269			       mlxsw_sp_fid_vni_ht_params);
    270	return err;
    271}
    272
    273void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid)
    274{
    275	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    276	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
    277	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
    278
    279	if (WARN_ON(!ops->vni_clear || !fid->vni_valid))
    280		return;
    281
    282	fid->vni_valid = false;
    283	ops->vni_clear(fid);
    284	rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
    285			       mlxsw_sp_fid_vni_ht_params);
    286}
    287
    288bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
    289{
    290	return fid->vni_valid;
    291}
    292
    293void mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
    294				    const struct net_device *nve_dev)
    295{
    296	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    297	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
    298
    299	if (ops->fdb_clear_offload)
    300		ops->fdb_clear_offload(fid, nve_dev);
    301}
    302
    303static const struct mlxsw_sp_flood_table *
    304mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
    305				enum mlxsw_sp_flood_type packet_type)
    306{
    307	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    308	int i;
    309
    310	for (i = 0; i < fid_family->nr_flood_tables; i++) {
    311		if (fid_family->flood_tables[i].packet_type != packet_type)
    312			continue;
    313		return &fid_family->flood_tables[i];
    314	}
    315
    316	return NULL;
    317}
    318
    319int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
    320			   enum mlxsw_sp_flood_type packet_type, u16 local_port,
    321			   bool member)
    322{
    323	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    324	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
    325	const struct mlxsw_sp_flood_table *flood_table;
    326	char *sftr2_pl;
    327	int err;
    328
    329	if (WARN_ON(!fid_family->flood_tables || !ops->flood_index))
    330		return -EINVAL;
    331
    332	flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
    333	if (!flood_table)
    334		return -ESRCH;
    335
    336	sftr2_pl = kmalloc(MLXSW_REG_SFTR2_LEN, GFP_KERNEL);
    337	if (!sftr2_pl)
    338		return -ENOMEM;
    339
    340	mlxsw_reg_sftr2_pack(sftr2_pl, flood_table->table_index,
    341			     ops->flood_index(fid), flood_table->table_type, 1,
    342			     local_port, member);
    343	err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr2),
    344			      sftr2_pl);
    345	kfree(sftr2_pl);
    346	return err;
    347}
    348
    349int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
    350			      struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
    351{
    352	if (WARN_ON(!fid->fid_family->ops->port_vid_map))
    353		return -EINVAL;
    354	return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);
    355}
    356
    357void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
    358				 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
    359{
    360	fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
    361}
    362
    363u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
    364{
    365	return fid->fid_index;
    366}
    367
    368enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
    369{
    370	return fid->fid_family->type;
    371}
    372
    373void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
    374{
    375	fid->rif = rif;
    376}
    377
    378struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
    379{
    380	return fid->rif;
    381}
    382
    383enum mlxsw_sp_rif_type
    384mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
    385			   enum mlxsw_sp_fid_type type)
    386{
    387	struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
    388
    389	return fid_core->fid_family_arr[type]->rif_type;
    390}
    391
    392static struct mlxsw_sp_fid_8021q *
    393mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
    394{
    395	return container_of(fid, struct mlxsw_sp_fid_8021q, common);
    396}
    397
    398u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
    399{
    400	return mlxsw_sp_fid_8021q_fid(fid)->vid;
    401}
    402
    403static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
    404{
    405	u16 vid = *(u16 *) arg;
    406
    407	mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
    408}
    409
    410static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
    411{
    412	return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
    413		       MLXSW_REG_SFMR_OP_DESTROY_FID;
    414}
    415
    416static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
    417			   u16 fid_offset, bool valid)
    418{
    419	char sfmr_pl[MLXSW_REG_SFMR_LEN];
    420
    421	mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index,
    422			    fid_offset);
    423	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
    424}
    425
    426static int mlxsw_sp_fid_vni_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
    427			       __be32 vni, bool vni_valid, u32 nve_flood_index,
    428			       bool nve_flood_index_valid)
    429{
    430	char sfmr_pl[MLXSW_REG_SFMR_LEN];
    431
    432	mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, fid_index,
    433			    0);
    434	mlxsw_reg_sfmr_vv_set(sfmr_pl, vni_valid);
    435	mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(vni));
    436	mlxsw_reg_sfmr_vtfp_set(sfmr_pl, nve_flood_index_valid);
    437	mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, nve_flood_index);
    438	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
    439}
    440
    441static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
    442				       u16 local_port, u16 vid, bool valid)
    443{
    444	enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
    445	char svfa_pl[MLXSW_REG_SVFA_LEN];
    446
    447	mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid);
    448	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
    449}
    450
    451static struct mlxsw_sp_fid_8021d *
    452mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
    453{
    454	return container_of(fid, struct mlxsw_sp_fid_8021d, common);
    455}
    456
    457static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
    458{
    459	int br_ifindex = *(int *) arg;
    460
    461	mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
    462}
    463
    464static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
    465{
    466	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    467
    468	return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true);
    469}
    470
    471static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
    472{
    473	if (fid->vni_valid)
    474		mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
    475	mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
    476}
    477
    478static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
    479					  const void *arg, u16 *p_fid_index)
    480{
    481	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    482	u16 nr_fids, fid_index;
    483
    484	nr_fids = fid_family->end_index - fid_family->start_index + 1;
    485	fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);
    486	if (fid_index == nr_fids)
    487		return -ENOBUFS;
    488	*p_fid_index = fid_family->start_index + fid_index;
    489
    490	return 0;
    491}
    492
    493static bool
    494mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
    495{
    496	int br_ifindex = *(int *) arg;
    497
    498	return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
    499}
    500
    501static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid)
    502{
    503	return fid->fid_index - VLAN_N_VID;
    504}
    505
    506static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
    507{
    508	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
    509	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
    510	int err;
    511
    512	list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
    513			    list) {
    514		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
    515		u16 vid = mlxsw_sp_port_vlan->vid;
    516
    517		if (!fid)
    518			continue;
    519
    520		err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
    521						  mlxsw_sp_port->local_port,
    522						  vid, true);
    523		if (err)
    524			goto err_fid_port_vid_map;
    525	}
    526
    527	err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
    528	if (err)
    529		goto err_port_vp_mode_set;
    530
    531	return 0;
    532
    533err_port_vp_mode_set:
    534err_fid_port_vid_map:
    535	list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
    536					     &mlxsw_sp_port->vlans_list, list) {
    537		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
    538		u16 vid = mlxsw_sp_port_vlan->vid;
    539
    540		if (!fid)
    541			continue;
    542
    543		__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
    544					    mlxsw_sp_port->local_port, vid,
    545					    false);
    546	}
    547	return err;
    548}
    549
    550static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
    551{
    552	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
    553	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
    554
    555	mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
    556
    557	list_for_each_entry_reverse(mlxsw_sp_port_vlan,
    558				    &mlxsw_sp_port->vlans_list, list) {
    559		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
    560		u16 vid = mlxsw_sp_port_vlan->vid;
    561
    562		if (!fid)
    563			continue;
    564
    565		__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
    566					    mlxsw_sp_port->local_port, vid,
    567					    false);
    568	}
    569}
    570
    571static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
    572					   struct mlxsw_sp_port *mlxsw_sp_port,
    573					   u16 vid)
    574{
    575	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
    576	u16 local_port = mlxsw_sp_port->local_port;
    577	int err;
    578
    579	err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
    580					  mlxsw_sp_port->local_port, vid, true);
    581	if (err)
    582		return err;
    583
    584	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
    585		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
    586		if (err)
    587			goto err_port_vp_mode_trans;
    588	}
    589
    590	return 0;
    591
    592err_port_vp_mode_trans:
    593	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
    594	__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
    595				    mlxsw_sp_port->local_port, vid, false);
    596	return err;
    597}
    598
    599static void
    600mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
    601				  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
    602{
    603	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
    604	u16 local_port = mlxsw_sp_port->local_port;
    605
    606	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
    607		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
    608	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
    609	__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
    610				    mlxsw_sp_port->local_port, vid, false);
    611}
    612
    613static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid, __be32 vni)
    614{
    615	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    616
    617	return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, vni,
    618				   true, fid->nve_flood_index,
    619				   fid->nve_flood_index_valid);
    620}
    621
    622static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
    623{
    624	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    625
    626	mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, 0, false,
    627			    fid->nve_flood_index, fid->nve_flood_index_valid);
    628}
    629
    630static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid,
    631						  u32 nve_flood_index)
    632{
    633	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    634
    635	return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index,
    636				   fid->vni, fid->vni_valid, nve_flood_index,
    637				   true);
    638}
    639
    640static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
    641{
    642	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    643
    644	mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, fid->vni,
    645			    fid->vni_valid, 0, false);
    646}
    647
    648static void
    649mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
    650				     const struct net_device *nve_dev)
    651{
    652	br_fdb_clear_offload(nve_dev, 0);
    653}
    654
    655static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
    656	.setup			= mlxsw_sp_fid_8021d_setup,
    657	.configure		= mlxsw_sp_fid_8021d_configure,
    658	.deconfigure		= mlxsw_sp_fid_8021d_deconfigure,
    659	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,
    660	.compare		= mlxsw_sp_fid_8021d_compare,
    661	.flood_index		= mlxsw_sp_fid_8021d_flood_index,
    662	.port_vid_map		= mlxsw_sp_fid_8021d_port_vid_map,
    663	.port_vid_unmap		= mlxsw_sp_fid_8021d_port_vid_unmap,
    664	.vni_set		= mlxsw_sp_fid_8021d_vni_set,
    665	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,
    666	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,
    667	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,
    668	.fdb_clear_offload	= mlxsw_sp_fid_8021d_fdb_clear_offload,
    669};
    670
    671static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
    672	{
    673		.packet_type	= MLXSW_SP_FLOOD_TYPE_UC,
    674		.bridge_type	= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
    675		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID,
    676		.table_index	= 0,
    677	},
    678	{
    679		.packet_type	= MLXSW_SP_FLOOD_TYPE_MC,
    680		.bridge_type	= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
    681		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID,
    682		.table_index	= 1,
    683	},
    684	{
    685		.packet_type	= MLXSW_SP_FLOOD_TYPE_BC,
    686		.bridge_type	= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
    687		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID,
    688		.table_index	= 2,
    689	},
    690};
    691
    692/* Range and flood configuration must match mlxsw_config_profile */
    693static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = {
    694	.type			= MLXSW_SP_FID_TYPE_8021D,
    695	.fid_size		= sizeof(struct mlxsw_sp_fid_8021d),
    696	.start_index		= VLAN_N_VID,
    697	.end_index		= VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1,
    698	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
    699	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
    700	.rif_type		= MLXSW_SP_RIF_TYPE_FID,
    701	.ops			= &mlxsw_sp_fid_8021d_ops,
    702	.lag_vid_valid		= 1,
    703};
    704
    705static bool
    706mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
    707{
    708	u16 vid = *(u16 *) arg;
    709
    710	return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
    711}
    712
    713static void
    714mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
    715				     const struct net_device *nve_dev)
    716{
    717	br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid));
    718}
    719
    720static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_emu_ops = {
    721	.setup			= mlxsw_sp_fid_8021q_setup,
    722	.configure		= mlxsw_sp_fid_8021d_configure,
    723	.deconfigure		= mlxsw_sp_fid_8021d_deconfigure,
    724	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,
    725	.compare		= mlxsw_sp_fid_8021q_compare,
    726	.flood_index		= mlxsw_sp_fid_8021d_flood_index,
    727	.port_vid_map		= mlxsw_sp_fid_8021d_port_vid_map,
    728	.port_vid_unmap		= mlxsw_sp_fid_8021d_port_vid_unmap,
    729	.vni_set		= mlxsw_sp_fid_8021d_vni_set,
    730	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,
    731	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,
    732	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,
    733	.fdb_clear_offload	= mlxsw_sp_fid_8021q_fdb_clear_offload,
    734};
    735
    736/* There are 4K-2 emulated 802.1Q FIDs, starting right after the 802.1D FIDs */
    737#define MLXSW_SP_FID_8021Q_EMU_START	(VLAN_N_VID + MLXSW_SP_FID_8021D_MAX)
    738#define MLXSW_SP_FID_8021Q_EMU_END	(MLXSW_SP_FID_8021Q_EMU_START + \
    739					 VLAN_VID_MASK - 2)
    740
    741/* Range and flood configuration must match mlxsw_config_profile */
    742static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_emu_family = {
    743	.type			= MLXSW_SP_FID_TYPE_8021Q,
    744	.fid_size		= sizeof(struct mlxsw_sp_fid_8021q),
    745	.start_index		= MLXSW_SP_FID_8021Q_EMU_START,
    746	.end_index		= MLXSW_SP_FID_8021Q_EMU_END,
    747	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
    748	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
    749	.rif_type		= MLXSW_SP_RIF_TYPE_VLAN,
    750	.ops			= &mlxsw_sp_fid_8021q_emu_ops,
    751	.lag_vid_valid		= 1,
    752};
    753
    754static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
    755{
    756	/* rFIDs are allocated by the device during init */
    757	return 0;
    758}
    759
    760static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
    761{
    762}
    763
    764static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
    765					 const void *arg, u16 *p_fid_index)
    766{
    767	u16 rif_index = *(u16 *) arg;
    768
    769	*p_fid_index = fid->fid_family->start_index + rif_index;
    770
    771	return 0;
    772}
    773
    774static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
    775				      const void *arg)
    776{
    777	u16 rif_index = *(u16 *) arg;
    778
    779	return fid->fid_index == rif_index + fid->fid_family->start_index;
    780}
    781
    782static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
    783					  struct mlxsw_sp_port *mlxsw_sp_port,
    784					  u16 vid)
    785{
    786	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
    787	u16 local_port = mlxsw_sp_port->local_port;
    788	int err;
    789
    790	/* We only need to transition the port to virtual mode since
    791	 * {Port, VID} => FID is done by the firmware upon RIF creation.
    792	 */
    793	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
    794		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
    795		if (err)
    796			goto err_port_vp_mode_trans;
    797	}
    798
    799	return 0;
    800
    801err_port_vp_mode_trans:
    802	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
    803	return err;
    804}
    805
    806static void
    807mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
    808				 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
    809{
    810	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
    811	u16 local_port = mlxsw_sp_port->local_port;
    812
    813	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
    814		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
    815	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
    816}
    817
    818static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
    819	.configure		= mlxsw_sp_fid_rfid_configure,
    820	.deconfigure		= mlxsw_sp_fid_rfid_deconfigure,
    821	.index_alloc		= mlxsw_sp_fid_rfid_index_alloc,
    822	.compare		= mlxsw_sp_fid_rfid_compare,
    823	.port_vid_map		= mlxsw_sp_fid_rfid_port_vid_map,
    824	.port_vid_unmap		= mlxsw_sp_fid_rfid_port_vid_unmap,
    825};
    826
    827#define MLXSW_SP_RFID_BASE	(15 * 1024)
    828#define MLXSW_SP_RFID_MAX	1024
    829
    830static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
    831	.type			= MLXSW_SP_FID_TYPE_RFID,
    832	.fid_size		= sizeof(struct mlxsw_sp_fid),
    833	.start_index		= MLXSW_SP_RFID_BASE,
    834	.end_index		= MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1,
    835	.rif_type		= MLXSW_SP_RIF_TYPE_SUBPORT,
    836	.ops			= &mlxsw_sp_fid_rfid_ops,
    837};
    838
    839static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
    840{
    841	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
    842
    843	return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true);
    844}
    845
    846static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
    847{
    848	mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
    849}
    850
    851static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
    852					  const void *arg, u16 *p_fid_index)
    853{
    854	*p_fid_index = fid->fid_family->start_index;
    855
    856	return 0;
    857}
    858
    859static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
    860				       const void *arg)
    861{
    862	return true;
    863}
    864
    865static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
    866	.configure		= mlxsw_sp_fid_dummy_configure,
    867	.deconfigure		= mlxsw_sp_fid_dummy_deconfigure,
    868	.index_alloc		= mlxsw_sp_fid_dummy_index_alloc,
    869	.compare		= mlxsw_sp_fid_dummy_compare,
    870};
    871
    872static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = {
    873	.type			= MLXSW_SP_FID_TYPE_DUMMY,
    874	.fid_size		= sizeof(struct mlxsw_sp_fid),
    875	.start_index		= VLAN_N_VID - 1,
    876	.end_index		= VLAN_N_VID - 1,
    877	.ops			= &mlxsw_sp_fid_dummy_ops,
    878};
    879
    880static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = {
    881	[MLXSW_SP_FID_TYPE_8021Q]	= &mlxsw_sp_fid_8021q_emu_family,
    882	[MLXSW_SP_FID_TYPE_8021D]	= &mlxsw_sp_fid_8021d_family,
    883	[MLXSW_SP_FID_TYPE_RFID]	= &mlxsw_sp_fid_rfid_family,
    884	[MLXSW_SP_FID_TYPE_DUMMY]	= &mlxsw_sp_fid_dummy_family,
    885};
    886
    887static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,
    888						enum mlxsw_sp_fid_type type,
    889						const void *arg)
    890{
    891	struct mlxsw_sp_fid_family *fid_family;
    892	struct mlxsw_sp_fid *fid;
    893
    894	fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
    895	list_for_each_entry(fid, &fid_family->fids_list, list) {
    896		if (!fid->fid_family->ops->compare(fid, arg))
    897			continue;
    898		refcount_inc(&fid->ref_count);
    899		return fid;
    900	}
    901
    902	return NULL;
    903}
    904
    905static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
    906					     enum mlxsw_sp_fid_type type,
    907					     const void *arg)
    908{
    909	struct mlxsw_sp_fid_family *fid_family;
    910	struct mlxsw_sp_fid *fid;
    911	u16 fid_index;
    912	int err;
    913
    914	fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg);
    915	if (fid)
    916		return fid;
    917
    918	fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
    919	fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
    920	if (!fid)
    921		return ERR_PTR(-ENOMEM);
    922	fid->fid_family = fid_family;
    923
    924	err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
    925	if (err)
    926		goto err_index_alloc;
    927	fid->fid_index = fid_index;
    928	__set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
    929
    930	if (fid->fid_family->ops->setup)
    931		fid->fid_family->ops->setup(fid, arg);
    932
    933	err = fid->fid_family->ops->configure(fid);
    934	if (err)
    935		goto err_configure;
    936
    937	err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node,
    938				     mlxsw_sp_fid_ht_params);
    939	if (err)
    940		goto err_rhashtable_insert;
    941
    942	list_add(&fid->list, &fid_family->fids_list);
    943	refcount_set(&fid->ref_count, 1);
    944	return fid;
    945
    946err_rhashtable_insert:
    947	fid->fid_family->ops->deconfigure(fid);
    948err_configure:
    949	__clear_bit(fid_index - fid_family->start_index,
    950		    fid_family->fids_bitmap);
    951err_index_alloc:
    952	kfree(fid);
    953	return ERR_PTR(err);
    954}
    955
    956void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
    957{
    958	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
    959	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
    960
    961	if (!refcount_dec_and_test(&fid->ref_count))
    962		return;
    963
    964	list_del(&fid->list);
    965	rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht,
    966			       &fid->ht_node, mlxsw_sp_fid_ht_params);
    967	fid->fid_family->ops->deconfigure(fid);
    968	__clear_bit(fid->fid_index - fid_family->start_index,
    969		    fid_family->fids_bitmap);
    970	kfree(fid);
    971}
    972
    973struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
    974{
    975	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
    976}
    977
    978struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
    979					    int br_ifindex)
    980{
    981	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
    982}
    983
    984struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp,
    985					       u16 vid)
    986{
    987	return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
    988}
    989
    990struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
    991					       int br_ifindex)
    992{
    993	return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D,
    994				   &br_ifindex);
    995}
    996
    997struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
    998					   u16 rif_index)
    999{
   1000	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);
   1001}
   1002
   1003struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
   1004{
   1005	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);
   1006}
   1007
   1008static int
   1009mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
   1010			      const struct mlxsw_sp_flood_table *flood_table)
   1011{
   1012	enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
   1013	const int *sfgc_packet_types;
   1014	int i;
   1015
   1016	sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
   1017	for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
   1018		struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
   1019		char sfgc_pl[MLXSW_REG_SFGC_LEN];
   1020		int err;
   1021
   1022		if (!sfgc_packet_types[i])
   1023			continue;
   1024		mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type,
   1025				    flood_table->table_type,
   1026				    flood_table->table_index);
   1027		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
   1028		if (err)
   1029			return err;
   1030	}
   1031
   1032	return 0;
   1033}
   1034
   1035static int
   1036mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
   1037{
   1038	int i;
   1039
   1040	for (i = 0; i < fid_family->nr_flood_tables; i++) {
   1041		const struct mlxsw_sp_flood_table *flood_table;
   1042		int err;
   1043
   1044		flood_table = &fid_family->flood_tables[i];
   1045		err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
   1046		if (err)
   1047			return err;
   1048	}
   1049
   1050	return 0;
   1051}
   1052
   1053static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
   1054					const struct mlxsw_sp_fid_family *tmpl)
   1055{
   1056	u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
   1057	struct mlxsw_sp_fid_family *fid_family;
   1058	int err;
   1059
   1060	fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);
   1061	if (!fid_family)
   1062		return -ENOMEM;
   1063
   1064	fid_family->mlxsw_sp = mlxsw_sp;
   1065	INIT_LIST_HEAD(&fid_family->fids_list);
   1066	fid_family->fids_bitmap = bitmap_zalloc(nr_fids, GFP_KERNEL);
   1067	if (!fid_family->fids_bitmap) {
   1068		err = -ENOMEM;
   1069		goto err_alloc_fids_bitmap;
   1070	}
   1071
   1072	if (fid_family->flood_tables) {
   1073		err = mlxsw_sp_fid_flood_tables_init(fid_family);
   1074		if (err)
   1075			goto err_fid_flood_tables_init;
   1076	}
   1077
   1078	mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
   1079
   1080	return 0;
   1081
   1082err_fid_flood_tables_init:
   1083	bitmap_free(fid_family->fids_bitmap);
   1084err_alloc_fids_bitmap:
   1085	kfree(fid_family);
   1086	return err;
   1087}
   1088
   1089static void
   1090mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
   1091			       struct mlxsw_sp_fid_family *fid_family)
   1092{
   1093	mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
   1094	bitmap_free(fid_family->fids_bitmap);
   1095	WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
   1096	kfree(fid_family);
   1097}
   1098
   1099int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
   1100{
   1101	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
   1102
   1103	/* Track number of FIDs configured on the port with mapping type
   1104	 * PORT_VID_TO_FID, so that we know when to transition the port
   1105	 * back to non-virtual (VLAN) mode.
   1106	 */
   1107	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
   1108
   1109	return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
   1110}
   1111
   1112void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
   1113{
   1114	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
   1115
   1116	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
   1117}
   1118
   1119int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
   1120{
   1121	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
   1122	struct mlxsw_sp_fid_core *fid_core;
   1123	int err, i;
   1124
   1125	fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
   1126	if (!fid_core)
   1127		return -ENOMEM;
   1128	mlxsw_sp->fid_core = fid_core;
   1129
   1130	err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params);
   1131	if (err)
   1132		goto err_rhashtable_fid_init;
   1133
   1134	err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params);
   1135	if (err)
   1136		goto err_rhashtable_vni_init;
   1137
   1138	fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
   1139					      GFP_KERNEL);
   1140	if (!fid_core->port_fid_mappings) {
   1141		err = -ENOMEM;
   1142		goto err_alloc_port_fid_mappings;
   1143	}
   1144
   1145	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
   1146		err = mlxsw_sp_fid_family_register(mlxsw_sp,
   1147						   mlxsw_sp_fid_family_arr[i]);
   1148
   1149		if (err)
   1150			goto err_fid_ops_register;
   1151	}
   1152
   1153	return 0;
   1154
   1155err_fid_ops_register:
   1156	for (i--; i >= 0; i--) {
   1157		struct mlxsw_sp_fid_family *fid_family;
   1158
   1159		fid_family = fid_core->fid_family_arr[i];
   1160		mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
   1161	}
   1162	kfree(fid_core->port_fid_mappings);
   1163err_alloc_port_fid_mappings:
   1164	rhashtable_destroy(&fid_core->vni_ht);
   1165err_rhashtable_vni_init:
   1166	rhashtable_destroy(&fid_core->fid_ht);
   1167err_rhashtable_fid_init:
   1168	kfree(fid_core);
   1169	return err;
   1170}
   1171
   1172void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
   1173{
   1174	struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
   1175	int i;
   1176
   1177	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
   1178		mlxsw_sp_fid_family_unregister(mlxsw_sp,
   1179					       fid_core->fid_family_arr[i]);
   1180	kfree(fid_core->port_fid_mappings);
   1181	rhashtable_destroy(&fid_core->vni_ht);
   1182	rhashtable_destroy(&fid_core->fid_ht);
   1183	kfree(fid_core);
   1184}