162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/kernel.h>
562306a36Sopenharmony_ci#include <linux/bitops.h>
662306a36Sopenharmony_ci#include <linux/if_vlan.h>
762306a36Sopenharmony_ci#include <linux/if_bridge.h>
862306a36Sopenharmony_ci#include <linux/netdevice.h>
962306a36Sopenharmony_ci#include <linux/rhashtable.h>
1062306a36Sopenharmony_ci#include <linux/rtnetlink.h>
1162306a36Sopenharmony_ci#include <linux/refcount.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "spectrum.h"
1462306a36Sopenharmony_ci#include "reg.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistruct mlxsw_sp_fid_family;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistruct mlxsw_sp_fid_core {
1962306a36Sopenharmony_ci	struct rhashtable fid_ht;
2062306a36Sopenharmony_ci	struct rhashtable vni_ht;
2162306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
2262306a36Sopenharmony_ci	unsigned int *port_fid_mappings;
2362306a36Sopenharmony_ci};
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct mlxsw_sp_fid_port_vid {
2662306a36Sopenharmony_ci	struct list_head list;
2762306a36Sopenharmony_ci	u16 local_port;
2862306a36Sopenharmony_ci	u16 vid;
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistruct mlxsw_sp_fid {
3262306a36Sopenharmony_ci	struct list_head list;
3362306a36Sopenharmony_ci	struct mlxsw_sp_rif *rif;
3462306a36Sopenharmony_ci	refcount_t ref_count;
3562306a36Sopenharmony_ci	u16 fid_index;
3662306a36Sopenharmony_ci	u16 fid_offset;
3762306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family;
3862306a36Sopenharmony_ci	struct rhash_head ht_node;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	struct rhash_head vni_ht_node;
4162306a36Sopenharmony_ci	enum mlxsw_sp_nve_type nve_type;
4262306a36Sopenharmony_ci	__be32 vni;
4362306a36Sopenharmony_ci	u32 nve_flood_index;
4462306a36Sopenharmony_ci	int nve_ifindex;
4562306a36Sopenharmony_ci	u8 vni_valid:1,
4662306a36Sopenharmony_ci	   nve_flood_index_valid:1;
4762306a36Sopenharmony_ci	struct list_head port_vid_list; /* Ordered by local port. */
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistruct mlxsw_sp_fid_8021q {
5162306a36Sopenharmony_ci	struct mlxsw_sp_fid common;
5262306a36Sopenharmony_ci	u16 vid;
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistruct mlxsw_sp_fid_8021d {
5662306a36Sopenharmony_ci	struct mlxsw_sp_fid common;
5762306a36Sopenharmony_ci	int br_ifindex;
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic const struct rhashtable_params mlxsw_sp_fid_ht_params = {
6162306a36Sopenharmony_ci	.key_len = sizeof_field(struct mlxsw_sp_fid, fid_index),
6262306a36Sopenharmony_ci	.key_offset = offsetof(struct mlxsw_sp_fid, fid_index),
6362306a36Sopenharmony_ci	.head_offset = offsetof(struct mlxsw_sp_fid, ht_node),
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cistatic const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = {
6762306a36Sopenharmony_ci	.key_len = sizeof_field(struct mlxsw_sp_fid, vni),
6862306a36Sopenharmony_ci	.key_offset = offsetof(struct mlxsw_sp_fid, vni),
6962306a36Sopenharmony_ci	.head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node),
7062306a36Sopenharmony_ci};
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistruct mlxsw_sp_flood_table {
7362306a36Sopenharmony_ci	enum mlxsw_sp_flood_type packet_type;
7462306a36Sopenharmony_ci	enum mlxsw_flood_table_type table_type;
7562306a36Sopenharmony_ci	int table_index;
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistruct mlxsw_sp_fid_ops {
7962306a36Sopenharmony_ci	void (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
8062306a36Sopenharmony_ci	int (*configure)(struct mlxsw_sp_fid *fid);
8162306a36Sopenharmony_ci	void (*deconfigure)(struct mlxsw_sp_fid *fid);
8262306a36Sopenharmony_ci	int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
8362306a36Sopenharmony_ci			   u16 *p_fid_index);
8462306a36Sopenharmony_ci	bool (*compare)(const struct mlxsw_sp_fid *fid,
8562306a36Sopenharmony_ci			const void *arg);
8662306a36Sopenharmony_ci	int (*port_vid_map)(struct mlxsw_sp_fid *fid,
8762306a36Sopenharmony_ci			    struct mlxsw_sp_port *port, u16 vid);
8862306a36Sopenharmony_ci	void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
8962306a36Sopenharmony_ci			       struct mlxsw_sp_port *port, u16 vid);
9062306a36Sopenharmony_ci	int (*vni_set)(struct mlxsw_sp_fid *fid);
9162306a36Sopenharmony_ci	void (*vni_clear)(struct mlxsw_sp_fid *fid);
9262306a36Sopenharmony_ci	int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid);
9362306a36Sopenharmony_ci	void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);
9462306a36Sopenharmony_ci	void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid,
9562306a36Sopenharmony_ci				  const struct net_device *nve_dev);
9662306a36Sopenharmony_ci	int (*vid_to_fid_rif_update)(const struct mlxsw_sp_fid *fid,
9762306a36Sopenharmony_ci				     const struct mlxsw_sp_rif *rif);
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistruct mlxsw_sp_fid_family {
10162306a36Sopenharmony_ci	enum mlxsw_sp_fid_type type;
10262306a36Sopenharmony_ci	size_t fid_size;
10362306a36Sopenharmony_ci	u16 start_index;
10462306a36Sopenharmony_ci	u16 end_index;
10562306a36Sopenharmony_ci	struct list_head fids_list;
10662306a36Sopenharmony_ci	unsigned long *fids_bitmap;
10762306a36Sopenharmony_ci	const struct mlxsw_sp_flood_table *flood_tables;
10862306a36Sopenharmony_ci	int nr_flood_tables;
10962306a36Sopenharmony_ci	enum mlxsw_sp_rif_type rif_type;
11062306a36Sopenharmony_ci	const struct mlxsw_sp_fid_ops *ops;
11162306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp;
11262306a36Sopenharmony_ci	bool flood_rsp;
11362306a36Sopenharmony_ci	enum mlxsw_reg_bridge_type bridge_type;
11462306a36Sopenharmony_ci	u16 pgt_base;
11562306a36Sopenharmony_ci	bool smpe_index_valid;
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
11962306a36Sopenharmony_ci	[MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST]			= 1,
12062306a36Sopenharmony_ci};
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
12362306a36Sopenharmony_ci	[MLXSW_REG_SFGC_TYPE_BROADCAST]				= 1,
12462306a36Sopenharmony_ci	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP]	= 1,
12562306a36Sopenharmony_ci	[MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL]			= 1,
12662306a36Sopenharmony_ci	[MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST]			= 1,
12762306a36Sopenharmony_ci	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6]	= 1,
12862306a36Sopenharmony_ci};
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
13162306a36Sopenharmony_ci	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4]	= 1,
13262306a36Sopenharmony_ci};
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_cistatic const int *mlxsw_sp_packet_type_sfgc_types[] = {
13562306a36Sopenharmony_ci	[MLXSW_SP_FLOOD_TYPE_UC]	= mlxsw_sp_sfgc_uc_packet_types,
13662306a36Sopenharmony_ci	[MLXSW_SP_FLOOD_TYPE_BC]	= mlxsw_sp_sfgc_bc_packet_types,
13762306a36Sopenharmony_ci	[MLXSW_SP_FLOOD_TYPE_MC]	= mlxsw_sp_sfgc_mc_packet_types,
13862306a36Sopenharmony_ci};
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
14162306a36Sopenharmony_ci						  u16 fid_index)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	struct mlxsw_sp_fid *fid;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index,
14662306a36Sopenharmony_ci				     mlxsw_sp_fid_ht_params);
14762306a36Sopenharmony_ci	if (fid)
14862306a36Sopenharmony_ci		refcount_inc(&fid->ref_count);
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return fid;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ciint mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	if (!fid->vni_valid)
15662306a36Sopenharmony_ci		return -EINVAL;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	*nve_ifindex = fid->nve_ifindex;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	return 0;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ciint mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid,
16462306a36Sopenharmony_ci			  enum mlxsw_sp_nve_type *p_type)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	if (!fid->vni_valid)
16762306a36Sopenharmony_ci		return -EINVAL;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	*p_type = fid->nve_type;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	return 0;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,
17562306a36Sopenharmony_ci						__be32 vni)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	struct mlxsw_sp_fid *fid;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni,
18062306a36Sopenharmony_ci				     mlxsw_sp_fid_vni_ht_params);
18162306a36Sopenharmony_ci	if (fid)
18262306a36Sopenharmony_ci		refcount_inc(&fid->ref_count);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	return fid;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ciint mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	if (!fid->vni_valid)
19062306a36Sopenharmony_ci		return -EINVAL;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	*vni = fid->vni;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	return 0;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ciint mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
19862306a36Sopenharmony_ci				     u32 nve_flood_index)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
20162306a36Sopenharmony_ci	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
20262306a36Sopenharmony_ci	int err;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (WARN_ON(fid->nve_flood_index_valid))
20562306a36Sopenharmony_ci		return -EINVAL;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	fid->nve_flood_index = nve_flood_index;
20862306a36Sopenharmony_ci	fid->nve_flood_index_valid = true;
20962306a36Sopenharmony_ci	err = ops->nve_flood_index_set(fid);
21062306a36Sopenharmony_ci	if (err)
21162306a36Sopenharmony_ci		goto err_nve_flood_index_set;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return 0;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cierr_nve_flood_index_set:
21662306a36Sopenharmony_ci	fid->nve_flood_index_valid = false;
21762306a36Sopenharmony_ci	return err;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_civoid mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
22362306a36Sopenharmony_ci	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	if (WARN_ON(!fid->nve_flood_index_valid))
22662306a36Sopenharmony_ci		return;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	fid->nve_flood_index_valid = false;
22962306a36Sopenharmony_ci	ops->nve_flood_index_clear(fid);
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_cibool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	return fid->nve_flood_index_valid;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ciint mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type,
23862306a36Sopenharmony_ci			 __be32 vni, int nve_ifindex)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
24162306a36Sopenharmony_ci	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
24262306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
24362306a36Sopenharmony_ci	int err;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	if (WARN_ON(fid->vni_valid))
24662306a36Sopenharmony_ci		return -EINVAL;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	fid->nve_type = type;
24962306a36Sopenharmony_ci	fid->nve_ifindex = nve_ifindex;
25062306a36Sopenharmony_ci	fid->vni = vni;
25162306a36Sopenharmony_ci	err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht,
25262306a36Sopenharmony_ci					    &fid->vni_ht_node,
25362306a36Sopenharmony_ci					    mlxsw_sp_fid_vni_ht_params);
25462306a36Sopenharmony_ci	if (err)
25562306a36Sopenharmony_ci		return err;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	fid->vni_valid = true;
25862306a36Sopenharmony_ci	err = ops->vni_set(fid);
25962306a36Sopenharmony_ci	if (err)
26062306a36Sopenharmony_ci		goto err_vni_set;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	return 0;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cierr_vni_set:
26562306a36Sopenharmony_ci	fid->vni_valid = false;
26662306a36Sopenharmony_ci	rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
26762306a36Sopenharmony_ci			       mlxsw_sp_fid_vni_ht_params);
26862306a36Sopenharmony_ci	return err;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_civoid mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
27462306a36Sopenharmony_ci	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
27562306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	if (WARN_ON(!fid->vni_valid))
27862306a36Sopenharmony_ci		return;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	fid->vni_valid = false;
28162306a36Sopenharmony_ci	ops->vni_clear(fid);
28262306a36Sopenharmony_ci	rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
28362306a36Sopenharmony_ci			       mlxsw_sp_fid_vni_ht_params);
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cibool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
28762306a36Sopenharmony_ci{
28862306a36Sopenharmony_ci	return fid->vni_valid;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_civoid mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
29262306a36Sopenharmony_ci				    const struct net_device *nve_dev)
29362306a36Sopenharmony_ci{
29462306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
29562306a36Sopenharmony_ci	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	if (ops->fdb_clear_offload)
29862306a36Sopenharmony_ci		ops->fdb_clear_offload(fid, nve_dev);
29962306a36Sopenharmony_ci}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_cistatic const struct mlxsw_sp_flood_table *
30262306a36Sopenharmony_cimlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
30362306a36Sopenharmony_ci				enum mlxsw_sp_flood_type packet_type)
30462306a36Sopenharmony_ci{
30562306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
30662306a36Sopenharmony_ci	int i;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	for (i = 0; i < fid_family->nr_flood_tables; i++) {
30962306a36Sopenharmony_ci		if (fid_family->flood_tables[i].packet_type != packet_type)
31062306a36Sopenharmony_ci			continue;
31162306a36Sopenharmony_ci		return &fid_family->flood_tables[i];
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return NULL;
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic u16
31862306a36Sopenharmony_cimlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family *fid_family)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	return fid_family->end_index - fid_family->start_index + 1;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic u16
32462306a36Sopenharmony_cimlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family *fid_family,
32562306a36Sopenharmony_ci			     const struct mlxsw_sp_flood_table *flood_table,
32662306a36Sopenharmony_ci			     u16 fid_offset)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	u16 num_fids;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
33162306a36Sopenharmony_ci	return fid_family->pgt_base + num_fids * flood_table->table_index +
33262306a36Sopenharmony_ci	       fid_offset;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ciint mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
33662306a36Sopenharmony_ci			   enum mlxsw_sp_flood_type packet_type, u16 local_port,
33762306a36Sopenharmony_ci			   bool member)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
34062306a36Sopenharmony_ci	const struct mlxsw_sp_flood_table *flood_table;
34162306a36Sopenharmony_ci	u16 mid_index;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (WARN_ON(!fid_family->flood_tables))
34462306a36Sopenharmony_ci		return -EINVAL;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
34762306a36Sopenharmony_ci	if (!flood_table)
34862306a36Sopenharmony_ci		return -ESRCH;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	mid_index = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table,
35162306a36Sopenharmony_ci						 fid->fid_offset);
35262306a36Sopenharmony_ci	return mlxsw_sp_pgt_entry_port_set(fid_family->mlxsw_sp, mid_index,
35362306a36Sopenharmony_ci					   fid->fid_index, local_port, member);
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ciint mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
35762306a36Sopenharmony_ci			      struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	if (WARN_ON(!fid->fid_family->ops->port_vid_map))
36062306a36Sopenharmony_ci		return -EINVAL;
36162306a36Sopenharmony_ci	return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_civoid mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
36562306a36Sopenharmony_ci				 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ciu16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	return fid->fid_index;
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cienum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	return fid->fid_family->type;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistruct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
38162306a36Sopenharmony_ci{
38262306a36Sopenharmony_ci	return fid->rif;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cienum mlxsw_sp_rif_type
38662306a36Sopenharmony_cimlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
38762306a36Sopenharmony_ci			   enum mlxsw_sp_fid_type type)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	return fid_core->fid_family_arr[type]->rif_type;
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_cistatic struct mlxsw_sp_fid_8021q *
39562306a36Sopenharmony_cimlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	return container_of(fid, struct mlxsw_sp_fid_8021q, common);
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ciu16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	return mlxsw_sp_fid_8021q_fid(fid)->vid;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	u16 vid = *(u16 *) arg;
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
41062306a36Sopenharmony_ci	fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
41462306a36Sopenharmony_ci{
41562306a36Sopenharmony_ci	return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
41662306a36Sopenharmony_ci		       MLXSW_REG_SFMR_OP_DESTROY_FID;
41762306a36Sopenharmony_ci}
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_cistatic int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid)
42062306a36Sopenharmony_ci{
42162306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
42262306a36Sopenharmony_ci	char sfmr_pl[MLXSW_REG_SFMR_LEN];
42362306a36Sopenharmony_ci	u16 smpe;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid->fid_index,
42862306a36Sopenharmony_ci			    fid->fid_offset, fid->fid_family->flood_rsp,
42962306a36Sopenharmony_ci			    fid->fid_family->bridge_type,
43062306a36Sopenharmony_ci			    fid->fid_family->smpe_index_valid, smpe);
43162306a36Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_cistatic int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid,
43562306a36Sopenharmony_ci				const struct mlxsw_sp_rif *rif)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
43862306a36Sopenharmony_ci	char sfmr_pl[MLXSW_REG_SFMR_LEN];
43962306a36Sopenharmony_ci	u16 smpe;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID,
44462306a36Sopenharmony_ci			    fid->fid_index, fid->fid_offset,
44562306a36Sopenharmony_ci			    fid->fid_family->flood_rsp,
44662306a36Sopenharmony_ci			    fid->fid_family->bridge_type,
44762306a36Sopenharmony_ci			    fid->fid_family->smpe_index_valid, smpe);
44862306a36Sopenharmony_ci	mlxsw_reg_sfmr_vv_set(sfmr_pl, fid->vni_valid);
44962306a36Sopenharmony_ci	mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(fid->vni));
45062306a36Sopenharmony_ci	mlxsw_reg_sfmr_vtfp_set(sfmr_pl, fid->nve_flood_index_valid);
45162306a36Sopenharmony_ci	mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, fid->nve_flood_index);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (rif) {
45462306a36Sopenharmony_ci		mlxsw_reg_sfmr_irif_v_set(sfmr_pl, true);
45562306a36Sopenharmony_ci		mlxsw_reg_sfmr_irif_set(sfmr_pl, mlxsw_sp_rif_index(rif));
45662306a36Sopenharmony_ci	}
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic int mlxsw_sp_fid_vni_to_fid_map(const struct mlxsw_sp_fid *fid,
46262306a36Sopenharmony_ci				       const struct mlxsw_sp_rif *rif,
46362306a36Sopenharmony_ci				       bool valid)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
46662306a36Sopenharmony_ci	char svfa_pl[MLXSW_REG_SVFA_LEN];
46762306a36Sopenharmony_ci	bool irif_valid;
46862306a36Sopenharmony_ci	u16 irif_index;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	irif_valid = !!rif;
47162306a36Sopenharmony_ci	irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	mlxsw_reg_svfa_vni_pack(svfa_pl, valid, fid->fid_index,
47462306a36Sopenharmony_ci				be32_to_cpu(fid->vni), irif_valid, irif_index);
47562306a36Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic int mlxsw_sp_fid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
47962306a36Sopenharmony_ci					  const struct mlxsw_sp_rif *rif)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	return mlxsw_sp_fid_edit_op(fid, rif);
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic int mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
48562306a36Sopenharmony_ci					      const struct mlxsw_sp_rif *rif)
48662306a36Sopenharmony_ci{
48762306a36Sopenharmony_ci	if (!fid->vni_valid)
48862306a36Sopenharmony_ci		return 0;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	return mlxsw_sp_fid_vni_to_fid_map(fid, rif, fid->vni_valid);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistatic int
49462306a36Sopenharmony_cimlxsw_sp_fid_vid_to_fid_map(const struct mlxsw_sp_fid *fid, u16 vid, bool valid,
49562306a36Sopenharmony_ci			    const struct mlxsw_sp_rif *rif)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
49862306a36Sopenharmony_ci	char svfa_pl[MLXSW_REG_SVFA_LEN];
49962306a36Sopenharmony_ci	bool irif_valid;
50062306a36Sopenharmony_ci	u16 irif_index;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	irif_valid = !!rif;
50362306a36Sopenharmony_ci	irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	mlxsw_reg_svfa_vid_pack(svfa_pl, valid, fid->fid_index, vid, irif_valid,
50662306a36Sopenharmony_ci				irif_index);
50762306a36Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
50862306a36Sopenharmony_ci}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cistatic int
51162306a36Sopenharmony_cimlxsw_sp_fid_8021q_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
51262306a36Sopenharmony_ci					 const struct mlxsw_sp_rif *rif)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	/* Update the global VID => FID mapping we created when the FID was
51762306a36Sopenharmony_ci	 * configured.
51862306a36Sopenharmony_ci	 */
51962306a36Sopenharmony_ci	return mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, rif);
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic int
52362306a36Sopenharmony_cimlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid *fid,
52462306a36Sopenharmony_ci					    struct mlxsw_sp_fid_port_vid *pv,
52562306a36Sopenharmony_ci					    bool irif_valid, u16 irif_index)
52662306a36Sopenharmony_ci{
52762306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
52862306a36Sopenharmony_ci	char svfa_pl[MLXSW_REG_SVFA_LEN];
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	mlxsw_reg_svfa_port_vid_pack(svfa_pl, pv->local_port, true,
53162306a36Sopenharmony_ci				     fid->fid_index, pv->vid, irif_valid,
53262306a36Sopenharmony_ci				     irif_index);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic int mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid *fid,
53862306a36Sopenharmony_ci					   const struct mlxsw_sp_rif *rif)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
54162306a36Sopenharmony_ci	struct mlxsw_sp_fid_port_vid *pv;
54262306a36Sopenharmony_ci	u16 irif_index;
54362306a36Sopenharmony_ci	int err;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	err = fid->fid_family->ops->vid_to_fid_rif_update(fid, rif);
54662306a36Sopenharmony_ci	if (err)
54762306a36Sopenharmony_ci		return err;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	irif_index = mlxsw_sp_rif_index(rif);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	list_for_each_entry(pv, &fid->port_vid_list, list) {
55262306a36Sopenharmony_ci		/* If port is not in virtual mode, then it does not have any
55362306a36Sopenharmony_ci		 * {Port, VID}->FID mappings that need to be updated with the
55462306a36Sopenharmony_ci		 * ingress RIF.
55562306a36Sopenharmony_ci		 */
55662306a36Sopenharmony_ci		if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
55762306a36Sopenharmony_ci			continue;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci		err = mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv,
56062306a36Sopenharmony_ci								  true,
56162306a36Sopenharmony_ci								  irif_index);
56262306a36Sopenharmony_ci		if (err)
56362306a36Sopenharmony_ci			goto err_port_vid_to_fid_rif_update_one;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	return 0;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cierr_port_vid_to_fid_rif_update_one:
56962306a36Sopenharmony_ci	list_for_each_entry_continue_reverse(pv, &fid->port_vid_list, list) {
57062306a36Sopenharmony_ci		if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
57162306a36Sopenharmony_ci			continue;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci		mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
57762306a36Sopenharmony_ci	return err;
57862306a36Sopenharmony_ci}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cistatic void mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid *fid)
58162306a36Sopenharmony_ci{
58262306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
58362306a36Sopenharmony_ci	struct mlxsw_sp_fid_port_vid *pv;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	list_for_each_entry(pv, &fid->port_vid_list, list) {
58662306a36Sopenharmony_ci		/* If port is not in virtual mode, then it does not have any
58762306a36Sopenharmony_ci		 * {Port, VID}->FID mappings that need to be updated.
58862306a36Sopenharmony_ci		 */
58962306a36Sopenharmony_ci		if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
59062306a36Sopenharmony_ci			continue;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci		mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic int mlxsw_sp_fid_reiv_handle(struct mlxsw_sp_fid *fid, u16 rif_index,
59962306a36Sopenharmony_ci				    bool valid, u8 port_page)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	u16 local_port_end = (port_page + 1) * MLXSW_REG_REIV_REC_MAX_COUNT - 1;
60262306a36Sopenharmony_ci	u16 local_port_start = port_page * MLXSW_REG_REIV_REC_MAX_COUNT;
60362306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
60462306a36Sopenharmony_ci	struct mlxsw_sp_fid_port_vid *port_vid;
60562306a36Sopenharmony_ci	u8 rec_num, entries_num = 0;
60662306a36Sopenharmony_ci	char *reiv_pl;
60762306a36Sopenharmony_ci	int err;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
61062306a36Sopenharmony_ci	if (!reiv_pl)
61162306a36Sopenharmony_ci		return -ENOMEM;
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	list_for_each_entry(port_vid, &fid->port_vid_list, list) {
61662306a36Sopenharmony_ci		/* port_vid_list is sorted by local_port. */
61762306a36Sopenharmony_ci		if (port_vid->local_port < local_port_start)
61862306a36Sopenharmony_ci			continue;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		if (port_vid->local_port > local_port_end)
62162306a36Sopenharmony_ci			break;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci		rec_num = port_vid->local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
62462306a36Sopenharmony_ci		mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);
62562306a36Sopenharmony_ci		mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num,
62662306a36Sopenharmony_ci					    valid ? port_vid->vid : 0);
62762306a36Sopenharmony_ci		entries_num++;
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	if (!entries_num) {
63162306a36Sopenharmony_ci		kfree(reiv_pl);
63262306a36Sopenharmony_ci		return 0;
63362306a36Sopenharmony_ci	}
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);
63662306a36Sopenharmony_ci	if (err)
63762306a36Sopenharmony_ci		goto err_reg_write;
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	kfree(reiv_pl);
64062306a36Sopenharmony_ci	return 0;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_cierr_reg_write:
64362306a36Sopenharmony_ci	kfree(reiv_pl);
64462306a36Sopenharmony_ci	return err;
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic int mlxsw_sp_fid_erif_eport_to_vid_map(struct mlxsw_sp_fid *fid,
64862306a36Sopenharmony_ci					      u16 rif_index, bool valid)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
65162306a36Sopenharmony_ci	u8 num_port_pages;
65262306a36Sopenharmony_ci	int err, i;
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	num_port_pages = mlxsw_core_max_ports(mlxsw_sp->core) /
65562306a36Sopenharmony_ci			 MLXSW_REG_REIV_REC_MAX_COUNT + 1;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	for (i = 0; i < num_port_pages; i++) {
65862306a36Sopenharmony_ci		err = mlxsw_sp_fid_reiv_handle(fid, rif_index, valid, i);
65962306a36Sopenharmony_ci		if (err)
66062306a36Sopenharmony_ci			goto err_reiv_handle;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci
66362306a36Sopenharmony_ci	return 0;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_cierr_reiv_handle:
66662306a36Sopenharmony_ci	for (; i >= 0; i--)
66762306a36Sopenharmony_ci		mlxsw_sp_fid_reiv_handle(fid, rif_index, !valid, i);
66862306a36Sopenharmony_ci	return err;
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ciint mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
67262306a36Sopenharmony_ci{
67362306a36Sopenharmony_ci	u16 rif_index = mlxsw_sp_rif_index(rif);
67462306a36Sopenharmony_ci	int err;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	err = mlxsw_sp_fid_to_fid_rif_update(fid, rif);
67762306a36Sopenharmony_ci	if (err)
67862306a36Sopenharmony_ci		return err;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	err = mlxsw_sp_fid_vni_to_fid_rif_update(fid, rif);
68162306a36Sopenharmony_ci	if (err)
68262306a36Sopenharmony_ci		goto err_vni_to_fid_rif_update;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	err = mlxsw_sp_fid_vid_to_fid_rif_set(fid, rif);
68562306a36Sopenharmony_ci	if (err)
68662306a36Sopenharmony_ci		goto err_vid_to_fid_rif_set;
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	err = mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, true);
68962306a36Sopenharmony_ci	if (err)
69062306a36Sopenharmony_ci		goto err_erif_eport_to_vid_map;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	fid->rif = rif;
69362306a36Sopenharmony_ci	return 0;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_cierr_erif_eport_to_vid_map:
69662306a36Sopenharmony_ci	mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
69762306a36Sopenharmony_cierr_vid_to_fid_rif_set:
69862306a36Sopenharmony_ci	mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
69962306a36Sopenharmony_cierr_vni_to_fid_rif_update:
70062306a36Sopenharmony_ci	mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
70162306a36Sopenharmony_ci	return err;
70262306a36Sopenharmony_ci}
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_civoid mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid *fid)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci	u16 rif_index;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	if (!fid->rif)
70962306a36Sopenharmony_ci		return;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	rif_index = mlxsw_sp_rif_index(fid->rif);
71262306a36Sopenharmony_ci	fid->rif = NULL;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, false);
71562306a36Sopenharmony_ci	mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
71662306a36Sopenharmony_ci	mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
71762306a36Sopenharmony_ci	mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_cistatic int mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid *fid)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	int err;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	err = mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, fid->vni_valid);
72562306a36Sopenharmony_ci	if (err)
72662306a36Sopenharmony_ci		return err;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	err = mlxsw_sp_fid_edit_op(fid, fid->rif);
72962306a36Sopenharmony_ci	if (err)
73062306a36Sopenharmony_ci		goto err_fid_edit_op;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	return 0;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cierr_fid_edit_op:
73562306a36Sopenharmony_ci	mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, !fid->vni_valid);
73662306a36Sopenharmony_ci	return err;
73762306a36Sopenharmony_ci}
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_cistatic int __mlxsw_sp_fid_port_vid_map(const struct mlxsw_sp_fid *fid,
74062306a36Sopenharmony_ci				       u16 local_port, u16 vid, bool valid)
74162306a36Sopenharmony_ci{
74262306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
74362306a36Sopenharmony_ci	char svfa_pl[MLXSW_REG_SVFA_LEN];
74462306a36Sopenharmony_ci	bool irif_valid = false;
74562306a36Sopenharmony_ci	u16 irif_index = 0;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (fid->rif) {
74862306a36Sopenharmony_ci		irif_valid = true;
74962306a36Sopenharmony_ci		irif_index = mlxsw_sp_rif_index(fid->rif);
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	mlxsw_reg_svfa_port_vid_pack(svfa_pl, local_port, valid, fid->fid_index,
75362306a36Sopenharmony_ci				     vid, irif_valid, irif_index);
75462306a36Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
75562306a36Sopenharmony_ci}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_cistatic struct mlxsw_sp_fid_8021d *
75862306a36Sopenharmony_cimlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	return container_of(fid, struct mlxsw_sp_fid_8021d, common);
76162306a36Sopenharmony_ci}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_cistatic void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	int br_ifindex = *(int *) arg;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
76862306a36Sopenharmony_ci	fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	return mlxsw_sp_fid_op(fid, true);
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_cistatic void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	if (fid->vni_valid)
77962306a36Sopenharmony_ci		mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
78062306a36Sopenharmony_ci	mlxsw_sp_fid_op(fid, false);
78162306a36Sopenharmony_ci}
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
78462306a36Sopenharmony_ci					  const void *arg, u16 *p_fid_index)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
78762306a36Sopenharmony_ci	u16 nr_fids, fid_index;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	nr_fids = fid_family->end_index - fid_family->start_index + 1;
79062306a36Sopenharmony_ci	fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);
79162306a36Sopenharmony_ci	if (fid_index == nr_fids)
79262306a36Sopenharmony_ci		return -ENOBUFS;
79362306a36Sopenharmony_ci	*p_fid_index = fid_family->start_index + fid_index;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	return 0;
79662306a36Sopenharmony_ci}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_cistatic bool
79962306a36Sopenharmony_cimlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	int br_ifindex = *(int *) arg;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
80462306a36Sopenharmony_ci}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_cistatic int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
80762306a36Sopenharmony_ci{
80862306a36Sopenharmony_ci	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
80962306a36Sopenharmony_ci	int err;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
81262306a36Sopenharmony_ci			    list) {
81362306a36Sopenharmony_ci		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
81462306a36Sopenharmony_ci		u16 vid = mlxsw_sp_port_vlan->vid;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci		if (!fid)
81762306a36Sopenharmony_ci			continue;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci		err = __mlxsw_sp_fid_port_vid_map(fid,
82062306a36Sopenharmony_ci						  mlxsw_sp_port->local_port,
82162306a36Sopenharmony_ci						  vid, true);
82262306a36Sopenharmony_ci		if (err)
82362306a36Sopenharmony_ci			goto err_fid_port_vid_map;
82462306a36Sopenharmony_ci	}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
82762306a36Sopenharmony_ci	if (err)
82862306a36Sopenharmony_ci		goto err_port_vp_mode_set;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	return 0;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_cierr_port_vp_mode_set:
83362306a36Sopenharmony_cierr_fid_port_vid_map:
83462306a36Sopenharmony_ci	list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
83562306a36Sopenharmony_ci					     &mlxsw_sp_port->vlans_list, list) {
83662306a36Sopenharmony_ci		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
83762306a36Sopenharmony_ci		u16 vid = mlxsw_sp_port_vlan->vid;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci		if (!fid)
84062306a36Sopenharmony_ci			continue;
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci		__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
84362306a36Sopenharmony_ci					    false);
84462306a36Sopenharmony_ci	}
84562306a36Sopenharmony_ci	return err;
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistatic void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
84962306a36Sopenharmony_ci{
85062306a36Sopenharmony_ci	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	list_for_each_entry_reverse(mlxsw_sp_port_vlan,
85562306a36Sopenharmony_ci				    &mlxsw_sp_port->vlans_list, list) {
85662306a36Sopenharmony_ci		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
85762306a36Sopenharmony_ci		u16 vid = mlxsw_sp_port_vlan->vid;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci		if (!fid)
86062306a36Sopenharmony_ci			continue;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci		__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
86362306a36Sopenharmony_ci					    false);
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci}
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_cistatic int
86862306a36Sopenharmony_cimlxsw_sp_fid_port_vid_list_add(struct mlxsw_sp_fid *fid, u16 local_port,
86962306a36Sopenharmony_ci			       u16 vid)
87062306a36Sopenharmony_ci{
87162306a36Sopenharmony_ci	struct mlxsw_sp_fid_port_vid *port_vid, *tmp_port_vid;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	port_vid = kzalloc(sizeof(*port_vid), GFP_KERNEL);
87462306a36Sopenharmony_ci	if (!port_vid)
87562306a36Sopenharmony_ci		return -ENOMEM;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	port_vid->local_port = local_port;
87862306a36Sopenharmony_ci	port_vid->vid = vid;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	list_for_each_entry(tmp_port_vid, &fid->port_vid_list, list) {
88162306a36Sopenharmony_ci		if (tmp_port_vid->local_port > local_port)
88262306a36Sopenharmony_ci			break;
88362306a36Sopenharmony_ci	}
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	list_add_tail(&port_vid->list, &tmp_port_vid->list);
88662306a36Sopenharmony_ci	return 0;
88762306a36Sopenharmony_ci}
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_cistatic void
89062306a36Sopenharmony_cimlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid *fid, u16 local_port,
89162306a36Sopenharmony_ci			       u16 vid)
89262306a36Sopenharmony_ci{
89362306a36Sopenharmony_ci	struct mlxsw_sp_fid_port_vid *port_vid, *tmp;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	list_for_each_entry_safe(port_vid, tmp, &fid->port_vid_list, list) {
89662306a36Sopenharmony_ci		if (port_vid->local_port != local_port || port_vid->vid != vid)
89762306a36Sopenharmony_ci			continue;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci		list_del(&port_vid->list);
90062306a36Sopenharmony_ci		kfree(port_vid);
90162306a36Sopenharmony_ci		return;
90262306a36Sopenharmony_ci	}
90362306a36Sopenharmony_ci}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_cistatic int
90662306a36Sopenharmony_cimlxsw_sp_fid_mpe_table_map(const struct mlxsw_sp_fid *fid, u16 local_port,
90762306a36Sopenharmony_ci			   u16 vid, bool valid)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
91062306a36Sopenharmony_ci	char smpe_pl[MLXSW_REG_SMPE_LEN];
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	mlxsw_reg_smpe_pack(smpe_pl, local_port, fid->fid_index,
91362306a36Sopenharmony_ci			    valid ? vid : 0);
91462306a36Sopenharmony_ci	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smpe), smpe_pl);
91562306a36Sopenharmony_ci}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_cistatic int
91862306a36Sopenharmony_cimlxsw_sp_fid_erif_eport_to_vid_map_one(const struct mlxsw_sp_fid *fid,
91962306a36Sopenharmony_ci				       u16 local_port, u16 vid, bool valid)
92062306a36Sopenharmony_ci{
92162306a36Sopenharmony_ci	u8 port_page = local_port / MLXSW_REG_REIV_REC_MAX_COUNT;
92262306a36Sopenharmony_ci	u8 rec_num = local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
92362306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
92462306a36Sopenharmony_ci	u16 rif_index = mlxsw_sp_rif_index(fid->rif);
92562306a36Sopenharmony_ci	char *reiv_pl;
92662306a36Sopenharmony_ci	int err;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
92962306a36Sopenharmony_ci	if (!reiv_pl)
93062306a36Sopenharmony_ci		return -ENOMEM;
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);
93362306a36Sopenharmony_ci	mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);
93462306a36Sopenharmony_ci	mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num, valid ? vid : 0);
93562306a36Sopenharmony_ci	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);
93662306a36Sopenharmony_ci	kfree(reiv_pl);
93762306a36Sopenharmony_ci	return err;
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_cistatic int mlxsw_sp_fid_evid_map(const struct mlxsw_sp_fid *fid, u16 local_port,
94162306a36Sopenharmony_ci				 u16 vid, bool valid)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	int err;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	err = mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, valid);
94662306a36Sopenharmony_ci	if (err)
94762306a36Sopenharmony_ci		return err;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	if (!fid->rif)
95062306a36Sopenharmony_ci		return 0;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
95362306a36Sopenharmony_ci						     valid);
95462306a36Sopenharmony_ci	if (err)
95562306a36Sopenharmony_ci		goto err_erif_eport_to_vid_map_one;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	return 0;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_cierr_erif_eport_to_vid_map_one:
96062306a36Sopenharmony_ci	mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, !valid);
96162306a36Sopenharmony_ci	return err;
96262306a36Sopenharmony_ci}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
96562306a36Sopenharmony_ci					   struct mlxsw_sp_port *mlxsw_sp_port,
96662306a36Sopenharmony_ci					   u16 vid)
96762306a36Sopenharmony_ci{
96862306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
96962306a36Sopenharmony_ci	u16 local_port = mlxsw_sp_port->local_port;
97062306a36Sopenharmony_ci	int err;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
97362306a36Sopenharmony_ci					  true);
97462306a36Sopenharmony_ci	if (err)
97562306a36Sopenharmony_ci		return err;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);
97862306a36Sopenharmony_ci	if (err)
97962306a36Sopenharmony_ci		goto err_fid_evid_map;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
98262306a36Sopenharmony_ci					     vid);
98362306a36Sopenharmony_ci	if (err)
98462306a36Sopenharmony_ci		goto err_port_vid_list_add;
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
98762306a36Sopenharmony_ci		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
98862306a36Sopenharmony_ci		if (err)
98962306a36Sopenharmony_ci			goto err_port_vp_mode_trans;
99062306a36Sopenharmony_ci	}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	return 0;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_cierr_port_vp_mode_trans:
99562306a36Sopenharmony_ci	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
99662306a36Sopenharmony_ci	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
99762306a36Sopenharmony_cierr_port_vid_list_add:
99862306a36Sopenharmony_ci	mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
99962306a36Sopenharmony_cierr_fid_evid_map:
100062306a36Sopenharmony_ci	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
100162306a36Sopenharmony_ci	return err;
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_cistatic void
100562306a36Sopenharmony_cimlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
100662306a36Sopenharmony_ci				  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
100762306a36Sopenharmony_ci{
100862306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
100962306a36Sopenharmony_ci	u16 local_port = mlxsw_sp_port->local_port;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
101262306a36Sopenharmony_ci		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
101362306a36Sopenharmony_ci	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
101462306a36Sopenharmony_ci	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
101562306a36Sopenharmony_ci	mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
101662306a36Sopenharmony_ci	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid)
102062306a36Sopenharmony_ci{
102162306a36Sopenharmony_ci	return mlxsw_sp_fid_vni_op(fid);
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
102562306a36Sopenharmony_ci{
102662306a36Sopenharmony_ci	mlxsw_sp_fid_vni_op(fid);
102762306a36Sopenharmony_ci}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid)
103062306a36Sopenharmony_ci{
103162306a36Sopenharmony_ci	return mlxsw_sp_fid_edit_op(fid, fid->rif);
103262306a36Sopenharmony_ci}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_cistatic void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci	mlxsw_sp_fid_edit_op(fid, fid->rif);
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cistatic void
104062306a36Sopenharmony_cimlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
104162306a36Sopenharmony_ci				     const struct net_device *nve_dev)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	br_fdb_clear_offload(nve_dev, 0);
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_cistatic int
104762306a36Sopenharmony_cimlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
104862306a36Sopenharmony_ci					 const struct mlxsw_sp_rif *rif)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	return 0;
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
105462306a36Sopenharmony_ci	.setup			= mlxsw_sp_fid_8021d_setup,
105562306a36Sopenharmony_ci	.configure		= mlxsw_sp_fid_8021d_configure,
105662306a36Sopenharmony_ci	.deconfigure		= mlxsw_sp_fid_8021d_deconfigure,
105762306a36Sopenharmony_ci	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,
105862306a36Sopenharmony_ci	.compare		= mlxsw_sp_fid_8021d_compare,
105962306a36Sopenharmony_ci	.port_vid_map		= mlxsw_sp_fid_8021d_port_vid_map,
106062306a36Sopenharmony_ci	.port_vid_unmap		= mlxsw_sp_fid_8021d_port_vid_unmap,
106162306a36Sopenharmony_ci	.vni_set		= mlxsw_sp_fid_8021d_vni_set,
106262306a36Sopenharmony_ci	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,
106362306a36Sopenharmony_ci	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,
106462306a36Sopenharmony_ci	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,
106562306a36Sopenharmony_ci	.fdb_clear_offload	= mlxsw_sp_fid_8021d_fdb_clear_offload,
106662306a36Sopenharmony_ci	.vid_to_fid_rif_update  = mlxsw_sp_fid_8021d_vid_to_fid_rif_update,
106762306a36Sopenharmony_ci};
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci#define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2)
107062306a36Sopenharmony_ci#define MLXSW_SP_FID_RFID_MAX (11 * 1024)
107162306a36Sopenharmony_ci#define MLXSW_SP_FID_8021Q_PGT_BASE 0
107262306a36Sopenharmony_ci#define MLXSW_SP_FID_8021D_PGT_BASE (3 * MLXSW_SP_FID_8021Q_MAX)
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_cistatic const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
107562306a36Sopenharmony_ci	{
107662306a36Sopenharmony_ci		.packet_type	= MLXSW_SP_FLOOD_TYPE_UC,
107762306a36Sopenharmony_ci		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
107862306a36Sopenharmony_ci		.table_index	= 0,
107962306a36Sopenharmony_ci	},
108062306a36Sopenharmony_ci	{
108162306a36Sopenharmony_ci		.packet_type	= MLXSW_SP_FLOOD_TYPE_MC,
108262306a36Sopenharmony_ci		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
108362306a36Sopenharmony_ci		.table_index	= 1,
108462306a36Sopenharmony_ci	},
108562306a36Sopenharmony_ci	{
108662306a36Sopenharmony_ci		.packet_type	= MLXSW_SP_FLOOD_TYPE_BC,
108762306a36Sopenharmony_ci		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
108862306a36Sopenharmony_ci		.table_index	= 2,
108962306a36Sopenharmony_ci	},
109062306a36Sopenharmony_ci};
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_cistatic bool
109362306a36Sopenharmony_cimlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
109462306a36Sopenharmony_ci{
109562306a36Sopenharmony_ci	u16 vid = *(u16 *) arg;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_cistatic void
110162306a36Sopenharmony_cimlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
110262306a36Sopenharmony_ci				     const struct net_device *nve_dev)
110362306a36Sopenharmony_ci{
110462306a36Sopenharmony_ci	br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid));
110562306a36Sopenharmony_ci}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_cistatic void mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid *fid, const void *arg)
110862306a36Sopenharmony_ci{
110962306a36Sopenharmony_ci	fid->fid_offset = 0;
111062306a36Sopenharmony_ci}
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_cistatic int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
111362306a36Sopenharmony_ci{
111462306a36Sopenharmony_ci	return mlxsw_sp_fid_op(fid, true);
111562306a36Sopenharmony_ci}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_cistatic void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
111862306a36Sopenharmony_ci{
111962306a36Sopenharmony_ci	mlxsw_sp_fid_op(fid, false);
112062306a36Sopenharmony_ci}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_cistatic int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
112362306a36Sopenharmony_ci					 const void *arg, u16 *p_fid_index)
112462306a36Sopenharmony_ci{
112562306a36Sopenharmony_ci	u16 rif_index = *(u16 *) arg;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	*p_fid_index = fid->fid_family->start_index + rif_index;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	return 0;
113062306a36Sopenharmony_ci}
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_cistatic bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
113362306a36Sopenharmony_ci				      const void *arg)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	u16 rif_index = *(u16 *) arg;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	return fid->fid_index == rif_index + fid->fid_family->start_index;
113862306a36Sopenharmony_ci}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_cistatic int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
114162306a36Sopenharmony_ci					  struct mlxsw_sp_port *mlxsw_sp_port,
114262306a36Sopenharmony_ci					  u16 vid)
114362306a36Sopenharmony_ci{
114462306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
114562306a36Sopenharmony_ci	u16 local_port = mlxsw_sp_port->local_port;
114662306a36Sopenharmony_ci	int err;
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
114962306a36Sopenharmony_ci					     vid);
115062306a36Sopenharmony_ci	if (err)
115162306a36Sopenharmony_ci		return err;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	/* Using legacy bridge model, we only need to transition the port to
115462306a36Sopenharmony_ci	 * virtual mode since {Port, VID} => FID is done by the firmware upon
115562306a36Sopenharmony_ci	 * RIF creation. Using unified bridge model, we need to map
115662306a36Sopenharmony_ci	 * {Port, VID} => FID and map egress VID.
115762306a36Sopenharmony_ci	 */
115862306a36Sopenharmony_ci	err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
115962306a36Sopenharmony_ci					  true);
116062306a36Sopenharmony_ci	if (err)
116162306a36Sopenharmony_ci		goto err_port_vid_map;
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	if (fid->rif) {
116462306a36Sopenharmony_ci		err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port,
116562306a36Sopenharmony_ci							     vid, true);
116662306a36Sopenharmony_ci		if (err)
116762306a36Sopenharmony_ci			goto err_erif_eport_to_vid_map_one;
116862306a36Sopenharmony_ci	}
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
117162306a36Sopenharmony_ci		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
117262306a36Sopenharmony_ci		if (err)
117362306a36Sopenharmony_ci			goto err_port_vp_mode_trans;
117462306a36Sopenharmony_ci	}
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	return 0;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_cierr_port_vp_mode_trans:
117962306a36Sopenharmony_ci	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
118062306a36Sopenharmony_ci	if (fid->rif)
118162306a36Sopenharmony_ci		mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
118262306a36Sopenharmony_ci						       false);
118362306a36Sopenharmony_cierr_erif_eport_to_vid_map_one:
118462306a36Sopenharmony_ci	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
118562306a36Sopenharmony_cierr_port_vid_map:
118662306a36Sopenharmony_ci	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
118762306a36Sopenharmony_ci	return err;
118862306a36Sopenharmony_ci}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_cistatic void
119162306a36Sopenharmony_cimlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
119262306a36Sopenharmony_ci				 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
119362306a36Sopenharmony_ci{
119462306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
119562306a36Sopenharmony_ci	u16 local_port = mlxsw_sp_port->local_port;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
119862306a36Sopenharmony_ci		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
119962306a36Sopenharmony_ci	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	if (fid->rif)
120262306a36Sopenharmony_ci		mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
120362306a36Sopenharmony_ci						       false);
120462306a36Sopenharmony_ci	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
120562306a36Sopenharmony_ci	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
120662306a36Sopenharmony_ci}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_cistatic int mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid *fid)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci	return -EOPNOTSUPP;
121162306a36Sopenharmony_ci}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_cistatic void mlxsw_sp_fid_rfid_vni_clear(struct mlxsw_sp_fid *fid)
121462306a36Sopenharmony_ci{
121562306a36Sopenharmony_ci	WARN_ON_ONCE(1);
121662306a36Sopenharmony_ci}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_cistatic int mlxsw_sp_fid_rfid_nve_flood_index_set(struct mlxsw_sp_fid *fid)
121962306a36Sopenharmony_ci{
122062306a36Sopenharmony_ci	return -EOPNOTSUPP;
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_cistatic void mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
122462306a36Sopenharmony_ci{
122562306a36Sopenharmony_ci	WARN_ON_ONCE(1);
122662306a36Sopenharmony_ci}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_cistatic int
122962306a36Sopenharmony_cimlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
123062306a36Sopenharmony_ci					const struct mlxsw_sp_rif *rif)
123162306a36Sopenharmony_ci{
123262306a36Sopenharmony_ci	return 0;
123362306a36Sopenharmony_ci}
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
123662306a36Sopenharmony_ci	.setup			= mlxsw_sp_fid_rfid_setup,
123762306a36Sopenharmony_ci	.configure		= mlxsw_sp_fid_rfid_configure,
123862306a36Sopenharmony_ci	.deconfigure		= mlxsw_sp_fid_rfid_deconfigure,
123962306a36Sopenharmony_ci	.index_alloc		= mlxsw_sp_fid_rfid_index_alloc,
124062306a36Sopenharmony_ci	.compare		= mlxsw_sp_fid_rfid_compare,
124162306a36Sopenharmony_ci	.port_vid_map		= mlxsw_sp_fid_rfid_port_vid_map,
124262306a36Sopenharmony_ci	.port_vid_unmap		= mlxsw_sp_fid_rfid_port_vid_unmap,
124362306a36Sopenharmony_ci	.vni_set                = mlxsw_sp_fid_rfid_vni_set,
124462306a36Sopenharmony_ci	.vni_clear		= mlxsw_sp_fid_rfid_vni_clear,
124562306a36Sopenharmony_ci	.nve_flood_index_set	= mlxsw_sp_fid_rfid_nve_flood_index_set,
124662306a36Sopenharmony_ci	.nve_flood_index_clear	= mlxsw_sp_fid_rfid_nve_flood_index_clear,
124762306a36Sopenharmony_ci	.vid_to_fid_rif_update  = mlxsw_sp_fid_rfid_vid_to_fid_rif_update,
124862306a36Sopenharmony_ci};
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_cistatic void mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg)
125162306a36Sopenharmony_ci{
125262306a36Sopenharmony_ci	fid->fid_offset = 0;
125362306a36Sopenharmony_ci}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_cistatic int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
125662306a36Sopenharmony_ci{
125762306a36Sopenharmony_ci	return mlxsw_sp_fid_op(fid, true);
125862306a36Sopenharmony_ci}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_cistatic void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
126162306a36Sopenharmony_ci{
126262306a36Sopenharmony_ci	mlxsw_sp_fid_op(fid, false);
126362306a36Sopenharmony_ci}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_cistatic int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
126662306a36Sopenharmony_ci					  const void *arg, u16 *p_fid_index)
126762306a36Sopenharmony_ci{
126862306a36Sopenharmony_ci	*p_fid_index = fid->fid_family->start_index;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci	return 0;
127162306a36Sopenharmony_ci}
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_cistatic bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
127462306a36Sopenharmony_ci				       const void *arg)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	return true;
127762306a36Sopenharmony_ci}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_cistatic int mlxsw_sp_fid_dummy_vni_set(struct mlxsw_sp_fid *fid)
128062306a36Sopenharmony_ci{
128162306a36Sopenharmony_ci	return -EOPNOTSUPP;
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_cistatic void mlxsw_sp_fid_dummy_vni_clear(struct mlxsw_sp_fid *fid)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	WARN_ON_ONCE(1);
128762306a36Sopenharmony_ci}
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_cistatic int mlxsw_sp_fid_dummy_nve_flood_index_set(struct mlxsw_sp_fid *fid)
129062306a36Sopenharmony_ci{
129162306a36Sopenharmony_ci	return -EOPNOTSUPP;
129262306a36Sopenharmony_ci}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_cistatic void mlxsw_sp_fid_dummy_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
129562306a36Sopenharmony_ci{
129662306a36Sopenharmony_ci	WARN_ON_ONCE(1);
129762306a36Sopenharmony_ci}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
130062306a36Sopenharmony_ci	.setup			= mlxsw_sp_fid_dummy_setup,
130162306a36Sopenharmony_ci	.configure		= mlxsw_sp_fid_dummy_configure,
130262306a36Sopenharmony_ci	.deconfigure		= mlxsw_sp_fid_dummy_deconfigure,
130362306a36Sopenharmony_ci	.index_alloc		= mlxsw_sp_fid_dummy_index_alloc,
130462306a36Sopenharmony_ci	.compare		= mlxsw_sp_fid_dummy_compare,
130562306a36Sopenharmony_ci	.vni_set                = mlxsw_sp_fid_dummy_vni_set,
130662306a36Sopenharmony_ci	.vni_clear		= mlxsw_sp_fid_dummy_vni_clear,
130762306a36Sopenharmony_ci	.nve_flood_index_set	= mlxsw_sp_fid_dummy_nve_flood_index_set,
130862306a36Sopenharmony_ci	.nve_flood_index_clear	= mlxsw_sp_fid_dummy_nve_flood_index_clear,
130962306a36Sopenharmony_ci};
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
131262306a36Sopenharmony_ci{
131362306a36Sopenharmony_ci	struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
131462306a36Sopenharmony_ci	int err;
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	err = mlxsw_sp_fid_op(fid, true);
131762306a36Sopenharmony_ci	if (err)
131862306a36Sopenharmony_ci		return err;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	err = mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, fid->rif);
132162306a36Sopenharmony_ci	if (err)
132262306a36Sopenharmony_ci		goto err_vid_to_fid_map;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	return 0;
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_cierr_vid_to_fid_map:
132762306a36Sopenharmony_ci	mlxsw_sp_fid_op(fid, false);
132862306a36Sopenharmony_ci	return err;
132962306a36Sopenharmony_ci}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_cistatic void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)
133262306a36Sopenharmony_ci{
133362306a36Sopenharmony_ci	struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	if (fid->vni_valid)
133662306a36Sopenharmony_ci		mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, false, NULL);
133962306a36Sopenharmony_ci	mlxsw_sp_fid_op(fid, false);
134062306a36Sopenharmony_ci}
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,
134362306a36Sopenharmony_ci					   struct mlxsw_sp_port *mlxsw_sp_port,
134462306a36Sopenharmony_ci					   u16 vid)
134562306a36Sopenharmony_ci{
134662306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
134762306a36Sopenharmony_ci	u16 local_port = mlxsw_sp_port->local_port;
134862306a36Sopenharmony_ci	int err;
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	/* In case there are no {Port, VID} => FID mappings on the port,
135162306a36Sopenharmony_ci	 * we can use the global VID => FID mapping we created when the
135262306a36Sopenharmony_ci	 * FID was configured, otherwise, configure new mapping.
135362306a36Sopenharmony_ci	 */
135462306a36Sopenharmony_ci	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]) {
135562306a36Sopenharmony_ci		err =  __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, true);
135662306a36Sopenharmony_ci		if (err)
135762306a36Sopenharmony_ci			return err;
135862306a36Sopenharmony_ci	}
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);
136162306a36Sopenharmony_ci	if (err)
136262306a36Sopenharmony_ci		goto err_fid_evid_map;
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
136562306a36Sopenharmony_ci					     vid);
136662306a36Sopenharmony_ci	if (err)
136762306a36Sopenharmony_ci		goto err_port_vid_list_add;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	return 0;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_cierr_port_vid_list_add:
137262306a36Sopenharmony_ci	 mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
137362306a36Sopenharmony_cierr_fid_evid_map:
137462306a36Sopenharmony_ci	if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
137562306a36Sopenharmony_ci		__mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
137662306a36Sopenharmony_ci	return err;
137762306a36Sopenharmony_ci}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_cistatic void
138062306a36Sopenharmony_cimlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
138162306a36Sopenharmony_ci				  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
138262306a36Sopenharmony_ci{
138362306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
138462306a36Sopenharmony_ci	u16 local_port = mlxsw_sp_port->local_port;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
138762306a36Sopenharmony_ci	mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
138862306a36Sopenharmony_ci	if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
138962306a36Sopenharmony_ci		__mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
139062306a36Sopenharmony_ci}
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
139362306a36Sopenharmony_ci	.setup			= mlxsw_sp_fid_8021q_setup,
139462306a36Sopenharmony_ci	.configure		= mlxsw_sp_fid_8021q_configure,
139562306a36Sopenharmony_ci	.deconfigure		= mlxsw_sp_fid_8021q_deconfigure,
139662306a36Sopenharmony_ci	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,
139762306a36Sopenharmony_ci	.compare		= mlxsw_sp_fid_8021q_compare,
139862306a36Sopenharmony_ci	.port_vid_map		= mlxsw_sp_fid_8021q_port_vid_map,
139962306a36Sopenharmony_ci	.port_vid_unmap		= mlxsw_sp_fid_8021q_port_vid_unmap,
140062306a36Sopenharmony_ci	.vni_set		= mlxsw_sp_fid_8021d_vni_set,
140162306a36Sopenharmony_ci	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,
140262306a36Sopenharmony_ci	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,
140362306a36Sopenharmony_ci	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,
140462306a36Sopenharmony_ci	.fdb_clear_offload	= mlxsw_sp_fid_8021q_fdb_clear_offload,
140562306a36Sopenharmony_ci	.vid_to_fid_rif_update  = mlxsw_sp_fid_8021q_vid_to_fid_rif_update,
140662306a36Sopenharmony_ci};
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci/* There are 4K-2 802.1Q FIDs */
140962306a36Sopenharmony_ci#define MLXSW_SP_FID_8021Q_START	1 /* FID 0 is reserved. */
141062306a36Sopenharmony_ci#define MLXSW_SP_FID_8021Q_END		(MLXSW_SP_FID_8021Q_START + \
141162306a36Sopenharmony_ci					 MLXSW_SP_FID_8021Q_MAX - 1)
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci/* There are 1K 802.1D FIDs */
141462306a36Sopenharmony_ci#define MLXSW_SP_FID_8021D_START	(MLXSW_SP_FID_8021Q_END + 1)
141562306a36Sopenharmony_ci#define MLXSW_SP_FID_8021D_END		(MLXSW_SP_FID_8021D_START + \
141662306a36Sopenharmony_ci					 MLXSW_SP_FID_8021D_MAX - 1)
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci/* There is one dummy FID */
141962306a36Sopenharmony_ci#define MLXSW_SP_FID_DUMMY		(MLXSW_SP_FID_8021D_END + 1)
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci/* There are 11K rFIDs */
142262306a36Sopenharmony_ci#define MLXSW_SP_RFID_START		(MLXSW_SP_FID_DUMMY + 1)
142362306a36Sopenharmony_ci#define MLXSW_SP_RFID_END		(MLXSW_SP_RFID_START + \
142462306a36Sopenharmony_ci					 MLXSW_SP_FID_RFID_MAX - 1)
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_family = {
142762306a36Sopenharmony_ci	.type			= MLXSW_SP_FID_TYPE_8021Q,
142862306a36Sopenharmony_ci	.fid_size		= sizeof(struct mlxsw_sp_fid_8021q),
142962306a36Sopenharmony_ci	.start_index		= MLXSW_SP_FID_8021Q_START,
143062306a36Sopenharmony_ci	.end_index		= MLXSW_SP_FID_8021Q_END,
143162306a36Sopenharmony_ci	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
143262306a36Sopenharmony_ci	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
143362306a36Sopenharmony_ci	.rif_type		= MLXSW_SP_RIF_TYPE_VLAN,
143462306a36Sopenharmony_ci	.ops			= &mlxsw_sp_fid_8021q_ops,
143562306a36Sopenharmony_ci	.flood_rsp              = false,
143662306a36Sopenharmony_ci	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_0,
143762306a36Sopenharmony_ci	.pgt_base		= MLXSW_SP_FID_8021Q_PGT_BASE,
143862306a36Sopenharmony_ci	.smpe_index_valid	= false,
143962306a36Sopenharmony_ci};
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_family = {
144262306a36Sopenharmony_ci	.type			= MLXSW_SP_FID_TYPE_8021D,
144362306a36Sopenharmony_ci	.fid_size		= sizeof(struct mlxsw_sp_fid_8021d),
144462306a36Sopenharmony_ci	.start_index		= MLXSW_SP_FID_8021D_START,
144562306a36Sopenharmony_ci	.end_index		= MLXSW_SP_FID_8021D_END,
144662306a36Sopenharmony_ci	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
144762306a36Sopenharmony_ci	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
144862306a36Sopenharmony_ci	.rif_type		= MLXSW_SP_RIF_TYPE_FID,
144962306a36Sopenharmony_ci	.ops			= &mlxsw_sp_fid_8021d_ops,
145062306a36Sopenharmony_ci	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_1,
145162306a36Sopenharmony_ci	.pgt_base		= MLXSW_SP_FID_8021D_PGT_BASE,
145262306a36Sopenharmony_ci	.smpe_index_valid       = false,
145362306a36Sopenharmony_ci};
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp1_fid_dummy_family = {
145662306a36Sopenharmony_ci	.type			= MLXSW_SP_FID_TYPE_DUMMY,
145762306a36Sopenharmony_ci	.fid_size		= sizeof(struct mlxsw_sp_fid),
145862306a36Sopenharmony_ci	.start_index		= MLXSW_SP_FID_DUMMY,
145962306a36Sopenharmony_ci	.end_index		= MLXSW_SP_FID_DUMMY,
146062306a36Sopenharmony_ci	.ops			= &mlxsw_sp_fid_dummy_ops,
146162306a36Sopenharmony_ci	.smpe_index_valid       = false,
146262306a36Sopenharmony_ci};
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
146562306a36Sopenharmony_ci	.type			= MLXSW_SP_FID_TYPE_RFID,
146662306a36Sopenharmony_ci	.fid_size		= sizeof(struct mlxsw_sp_fid),
146762306a36Sopenharmony_ci	.start_index		= MLXSW_SP_RFID_START,
146862306a36Sopenharmony_ci	.end_index		= MLXSW_SP_RFID_END,
146962306a36Sopenharmony_ci	.rif_type		= MLXSW_SP_RIF_TYPE_SUBPORT,
147062306a36Sopenharmony_ci	.ops			= &mlxsw_sp_fid_rfid_ops,
147162306a36Sopenharmony_ci	.flood_rsp              = true,
147262306a36Sopenharmony_ci	.smpe_index_valid       = false,
147362306a36Sopenharmony_ci};
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ciconst struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = {
147662306a36Sopenharmony_ci	[MLXSW_SP_FID_TYPE_8021Q]	= &mlxsw_sp1_fid_8021q_family,
147762306a36Sopenharmony_ci	[MLXSW_SP_FID_TYPE_8021D]	= &mlxsw_sp1_fid_8021d_family,
147862306a36Sopenharmony_ci	[MLXSW_SP_FID_TYPE_DUMMY]	= &mlxsw_sp1_fid_dummy_family,
147962306a36Sopenharmony_ci	[MLXSW_SP_FID_TYPE_RFID]	= &mlxsw_sp_fid_rfid_family,
148062306a36Sopenharmony_ci};
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family = {
148362306a36Sopenharmony_ci	.type			= MLXSW_SP_FID_TYPE_8021Q,
148462306a36Sopenharmony_ci	.fid_size		= sizeof(struct mlxsw_sp_fid_8021q),
148562306a36Sopenharmony_ci	.start_index		= MLXSW_SP_FID_8021Q_START,
148662306a36Sopenharmony_ci	.end_index		= MLXSW_SP_FID_8021Q_END,
148762306a36Sopenharmony_ci	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
148862306a36Sopenharmony_ci	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
148962306a36Sopenharmony_ci	.rif_type		= MLXSW_SP_RIF_TYPE_VLAN,
149062306a36Sopenharmony_ci	.ops			= &mlxsw_sp_fid_8021q_ops,
149162306a36Sopenharmony_ci	.flood_rsp              = false,
149262306a36Sopenharmony_ci	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_0,
149362306a36Sopenharmony_ci	.pgt_base		= MLXSW_SP_FID_8021Q_PGT_BASE,
149462306a36Sopenharmony_ci	.smpe_index_valid	= true,
149562306a36Sopenharmony_ci};
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family = {
149862306a36Sopenharmony_ci	.type			= MLXSW_SP_FID_TYPE_8021D,
149962306a36Sopenharmony_ci	.fid_size		= sizeof(struct mlxsw_sp_fid_8021d),
150062306a36Sopenharmony_ci	.start_index		= MLXSW_SP_FID_8021D_START,
150162306a36Sopenharmony_ci	.end_index		= MLXSW_SP_FID_8021D_END,
150262306a36Sopenharmony_ci	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
150362306a36Sopenharmony_ci	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
150462306a36Sopenharmony_ci	.rif_type		= MLXSW_SP_RIF_TYPE_FID,
150562306a36Sopenharmony_ci	.ops			= &mlxsw_sp_fid_8021d_ops,
150662306a36Sopenharmony_ci	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_1,
150762306a36Sopenharmony_ci	.pgt_base		= MLXSW_SP_FID_8021D_PGT_BASE,
150862306a36Sopenharmony_ci	.smpe_index_valid       = true,
150962306a36Sopenharmony_ci};
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp2_fid_dummy_family = {
151262306a36Sopenharmony_ci	.type			= MLXSW_SP_FID_TYPE_DUMMY,
151362306a36Sopenharmony_ci	.fid_size		= sizeof(struct mlxsw_sp_fid),
151462306a36Sopenharmony_ci	.start_index		= MLXSW_SP_FID_DUMMY,
151562306a36Sopenharmony_ci	.end_index		= MLXSW_SP_FID_DUMMY,
151662306a36Sopenharmony_ci	.ops			= &mlxsw_sp_fid_dummy_ops,
151762306a36Sopenharmony_ci	.smpe_index_valid       = false,
151862306a36Sopenharmony_ci};
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ciconst struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[] = {
152162306a36Sopenharmony_ci	[MLXSW_SP_FID_TYPE_8021Q]	= &mlxsw_sp2_fid_8021q_family,
152262306a36Sopenharmony_ci	[MLXSW_SP_FID_TYPE_8021D]	= &mlxsw_sp2_fid_8021d_family,
152362306a36Sopenharmony_ci	[MLXSW_SP_FID_TYPE_DUMMY]	= &mlxsw_sp2_fid_dummy_family,
152462306a36Sopenharmony_ci	[MLXSW_SP_FID_TYPE_RFID]	= &mlxsw_sp_fid_rfid_family,
152562306a36Sopenharmony_ci};
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_cistatic struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,
152862306a36Sopenharmony_ci						enum mlxsw_sp_fid_type type,
152962306a36Sopenharmony_ci						const void *arg)
153062306a36Sopenharmony_ci{
153162306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family;
153262306a36Sopenharmony_ci	struct mlxsw_sp_fid *fid;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
153562306a36Sopenharmony_ci	list_for_each_entry(fid, &fid_family->fids_list, list) {
153662306a36Sopenharmony_ci		if (!fid->fid_family->ops->compare(fid, arg))
153762306a36Sopenharmony_ci			continue;
153862306a36Sopenharmony_ci		refcount_inc(&fid->ref_count);
153962306a36Sopenharmony_ci		return fid;
154062306a36Sopenharmony_ci	}
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	return NULL;
154362306a36Sopenharmony_ci}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_cistatic struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
154662306a36Sopenharmony_ci					     enum mlxsw_sp_fid_type type,
154762306a36Sopenharmony_ci					     const void *arg)
154862306a36Sopenharmony_ci{
154962306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family;
155062306a36Sopenharmony_ci	struct mlxsw_sp_fid *fid;
155162306a36Sopenharmony_ci	u16 fid_index;
155262306a36Sopenharmony_ci	int err;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg);
155562306a36Sopenharmony_ci	if (fid)
155662306a36Sopenharmony_ci		return fid;
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
155962306a36Sopenharmony_ci	fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
156062306a36Sopenharmony_ci	if (!fid)
156162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	INIT_LIST_HEAD(&fid->port_vid_list);
156462306a36Sopenharmony_ci	fid->fid_family = fid_family;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
156762306a36Sopenharmony_ci	if (err)
156862306a36Sopenharmony_ci		goto err_index_alloc;
156962306a36Sopenharmony_ci	fid->fid_index = fid_index;
157062306a36Sopenharmony_ci	__set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	fid->fid_family->ops->setup(fid, arg);
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci	err = fid->fid_family->ops->configure(fid);
157562306a36Sopenharmony_ci	if (err)
157662306a36Sopenharmony_ci		goto err_configure;
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci	err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node,
157962306a36Sopenharmony_ci				     mlxsw_sp_fid_ht_params);
158062306a36Sopenharmony_ci	if (err)
158162306a36Sopenharmony_ci		goto err_rhashtable_insert;
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	list_add(&fid->list, &fid_family->fids_list);
158462306a36Sopenharmony_ci	refcount_set(&fid->ref_count, 1);
158562306a36Sopenharmony_ci	return fid;
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_cierr_rhashtable_insert:
158862306a36Sopenharmony_ci	fid->fid_family->ops->deconfigure(fid);
158962306a36Sopenharmony_cierr_configure:
159062306a36Sopenharmony_ci	__clear_bit(fid_index - fid_family->start_index,
159162306a36Sopenharmony_ci		    fid_family->fids_bitmap);
159262306a36Sopenharmony_cierr_index_alloc:
159362306a36Sopenharmony_ci	kfree(fid);
159462306a36Sopenharmony_ci	return ERR_PTR(err);
159562306a36Sopenharmony_ci}
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_civoid mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
159862306a36Sopenharmony_ci{
159962306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
160062306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	if (!refcount_dec_and_test(&fid->ref_count))
160362306a36Sopenharmony_ci		return;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	list_del(&fid->list);
160662306a36Sopenharmony_ci	rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht,
160762306a36Sopenharmony_ci			       &fid->ht_node, mlxsw_sp_fid_ht_params);
160862306a36Sopenharmony_ci	fid->fid_family->ops->deconfigure(fid);
160962306a36Sopenharmony_ci	__clear_bit(fid->fid_index - fid_family->start_index,
161062306a36Sopenharmony_ci		    fid_family->fids_bitmap);
161162306a36Sopenharmony_ci	WARN_ON_ONCE(!list_empty(&fid->port_vid_list));
161262306a36Sopenharmony_ci	kfree(fid);
161362306a36Sopenharmony_ci}
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
161662306a36Sopenharmony_ci{
161762306a36Sopenharmony_ci	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
161862306a36Sopenharmony_ci}
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
162162306a36Sopenharmony_ci					    int br_ifindex)
162262306a36Sopenharmony_ci{
162362306a36Sopenharmony_ci	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
162462306a36Sopenharmony_ci}
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp,
162762306a36Sopenharmony_ci					       u16 vid)
162862306a36Sopenharmony_ci{
162962306a36Sopenharmony_ci	return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
163062306a36Sopenharmony_ci}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
163362306a36Sopenharmony_ci					       int br_ifindex)
163462306a36Sopenharmony_ci{
163562306a36Sopenharmony_ci	return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D,
163662306a36Sopenharmony_ci				   &br_ifindex);
163762306a36Sopenharmony_ci}
163862306a36Sopenharmony_ci
163962306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
164062306a36Sopenharmony_ci					   u16 rif_index)
164162306a36Sopenharmony_ci{
164262306a36Sopenharmony_ci	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);
164362306a36Sopenharmony_ci}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
164662306a36Sopenharmony_ci{
164762306a36Sopenharmony_ci	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);
164862306a36Sopenharmony_ci}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_cistatic int
165162306a36Sopenharmony_cimlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
165262306a36Sopenharmony_ci			      const struct mlxsw_sp_flood_table *flood_table)
165362306a36Sopenharmony_ci{
165462306a36Sopenharmony_ci	enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
165562306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
165662306a36Sopenharmony_ci	const int *sfgc_packet_types;
165762306a36Sopenharmony_ci	u16 num_fids, mid_base;
165862306a36Sopenharmony_ci	int err, i;
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci	mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0);
166162306a36Sopenharmony_ci	num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
166262306a36Sopenharmony_ci	err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, mid_base, num_fids);
166362306a36Sopenharmony_ci	if (err)
166462306a36Sopenharmony_ci		return err;
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
166762306a36Sopenharmony_ci	for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
166862306a36Sopenharmony_ci		char sfgc_pl[MLXSW_REG_SFGC_LEN];
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci		if (!sfgc_packet_types[i])
167162306a36Sopenharmony_ci			continue;
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci		mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type,
167462306a36Sopenharmony_ci				    flood_table->table_type, 0, mid_base);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
167762306a36Sopenharmony_ci		if (err)
167862306a36Sopenharmony_ci			goto err_reg_write;
167962306a36Sopenharmony_ci	}
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	return 0;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_cierr_reg_write:
168462306a36Sopenharmony_ci	mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids);
168562306a36Sopenharmony_ci	return err;
168662306a36Sopenharmony_ci}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_cistatic void
168962306a36Sopenharmony_cimlxsw_sp_fid_flood_table_fini(struct mlxsw_sp_fid_family *fid_family,
169062306a36Sopenharmony_ci			      const struct mlxsw_sp_flood_table *flood_table)
169162306a36Sopenharmony_ci{
169262306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
169362306a36Sopenharmony_ci	u16 num_fids, mid_base;
169462306a36Sopenharmony_ci
169562306a36Sopenharmony_ci	mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0);
169662306a36Sopenharmony_ci	num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
169762306a36Sopenharmony_ci	mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids);
169862306a36Sopenharmony_ci}
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_cistatic int
170162306a36Sopenharmony_cimlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
170262306a36Sopenharmony_ci{
170362306a36Sopenharmony_ci	int i;
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci	for (i = 0; i < fid_family->nr_flood_tables; i++) {
170662306a36Sopenharmony_ci		const struct mlxsw_sp_flood_table *flood_table;
170762306a36Sopenharmony_ci		int err;
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci		flood_table = &fid_family->flood_tables[i];
171062306a36Sopenharmony_ci		err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
171162306a36Sopenharmony_ci		if (err)
171262306a36Sopenharmony_ci			return err;
171362306a36Sopenharmony_ci	}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	return 0;
171662306a36Sopenharmony_ci}
171762306a36Sopenharmony_ci
171862306a36Sopenharmony_cistatic void
171962306a36Sopenharmony_cimlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family)
172062306a36Sopenharmony_ci{
172162306a36Sopenharmony_ci	int i;
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_ci	for (i = 0; i < fid_family->nr_flood_tables; i++) {
172462306a36Sopenharmony_ci		const struct mlxsw_sp_flood_table *flood_table;
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci		flood_table = &fid_family->flood_tables[i];
172762306a36Sopenharmony_ci		mlxsw_sp_fid_flood_table_fini(fid_family, flood_table);
172862306a36Sopenharmony_ci	}
172962306a36Sopenharmony_ci}
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_cistatic int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
173262306a36Sopenharmony_ci					const struct mlxsw_sp_fid_family *tmpl)
173362306a36Sopenharmony_ci{
173462306a36Sopenharmony_ci	u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
173562306a36Sopenharmony_ci	struct mlxsw_sp_fid_family *fid_family;
173662306a36Sopenharmony_ci	int err;
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);
173962306a36Sopenharmony_ci	if (!fid_family)
174062306a36Sopenharmony_ci		return -ENOMEM;
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	fid_family->mlxsw_sp = mlxsw_sp;
174362306a36Sopenharmony_ci	INIT_LIST_HEAD(&fid_family->fids_list);
174462306a36Sopenharmony_ci	fid_family->fids_bitmap = bitmap_zalloc(nr_fids, GFP_KERNEL);
174562306a36Sopenharmony_ci	if (!fid_family->fids_bitmap) {
174662306a36Sopenharmony_ci		err = -ENOMEM;
174762306a36Sopenharmony_ci		goto err_alloc_fids_bitmap;
174862306a36Sopenharmony_ci	}
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	if (fid_family->flood_tables) {
175162306a36Sopenharmony_ci		err = mlxsw_sp_fid_flood_tables_init(fid_family);
175262306a36Sopenharmony_ci		if (err)
175362306a36Sopenharmony_ci			goto err_fid_flood_tables_init;
175462306a36Sopenharmony_ci	}
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	return 0;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_cierr_fid_flood_tables_init:
176162306a36Sopenharmony_ci	bitmap_free(fid_family->fids_bitmap);
176262306a36Sopenharmony_cierr_alloc_fids_bitmap:
176362306a36Sopenharmony_ci	kfree(fid_family);
176462306a36Sopenharmony_ci	return err;
176562306a36Sopenharmony_ci}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_cistatic void
176862306a36Sopenharmony_cimlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
176962306a36Sopenharmony_ci			       struct mlxsw_sp_fid_family *fid_family)
177062306a36Sopenharmony_ci{
177162306a36Sopenharmony_ci	mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	if (fid_family->flood_tables)
177462306a36Sopenharmony_ci		mlxsw_sp_fid_flood_tables_fini(fid_family);
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	bitmap_free(fid_family->fids_bitmap);
177762306a36Sopenharmony_ci	WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
177862306a36Sopenharmony_ci	kfree(fid_family);
177962306a36Sopenharmony_ci}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_ciint mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
178262306a36Sopenharmony_ci{
178362306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
178462306a36Sopenharmony_ci
178562306a36Sopenharmony_ci	/* Track number of FIDs configured on the port with mapping type
178662306a36Sopenharmony_ci	 * PORT_VID_TO_FID, so that we know when to transition the port
178762306a36Sopenharmony_ci	 * back to non-virtual (VLAN) mode.
178862306a36Sopenharmony_ci	 */
178962306a36Sopenharmony_ci	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
179262306a36Sopenharmony_ci}
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_civoid mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
179562306a36Sopenharmony_ci{
179662306a36Sopenharmony_ci	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
179962306a36Sopenharmony_ci}
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ciint mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
180262306a36Sopenharmony_ci{
180362306a36Sopenharmony_ci	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
180462306a36Sopenharmony_ci	struct mlxsw_sp_fid_core *fid_core;
180562306a36Sopenharmony_ci	int err, i;
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
180862306a36Sopenharmony_ci	if (!fid_core)
180962306a36Sopenharmony_ci		return -ENOMEM;
181062306a36Sopenharmony_ci	mlxsw_sp->fid_core = fid_core;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params);
181362306a36Sopenharmony_ci	if (err)
181462306a36Sopenharmony_ci		goto err_rhashtable_fid_init;
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params);
181762306a36Sopenharmony_ci	if (err)
181862306a36Sopenharmony_ci		goto err_rhashtable_vni_init;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
182162306a36Sopenharmony_ci					      GFP_KERNEL);
182262306a36Sopenharmony_ci	if (!fid_core->port_fid_mappings) {
182362306a36Sopenharmony_ci		err = -ENOMEM;
182462306a36Sopenharmony_ci		goto err_alloc_port_fid_mappings;
182562306a36Sopenharmony_ci	}
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
182862306a36Sopenharmony_ci		err = mlxsw_sp_fid_family_register(mlxsw_sp,
182962306a36Sopenharmony_ci						   mlxsw_sp->fid_family_arr[i]);
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci		if (err)
183262306a36Sopenharmony_ci			goto err_fid_ops_register;
183362306a36Sopenharmony_ci	}
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	return 0;
183662306a36Sopenharmony_ci
183762306a36Sopenharmony_cierr_fid_ops_register:
183862306a36Sopenharmony_ci	for (i--; i >= 0; i--) {
183962306a36Sopenharmony_ci		struct mlxsw_sp_fid_family *fid_family;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci		fid_family = fid_core->fid_family_arr[i];
184262306a36Sopenharmony_ci		mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
184362306a36Sopenharmony_ci	}
184462306a36Sopenharmony_ci	kfree(fid_core->port_fid_mappings);
184562306a36Sopenharmony_cierr_alloc_port_fid_mappings:
184662306a36Sopenharmony_ci	rhashtable_destroy(&fid_core->vni_ht);
184762306a36Sopenharmony_cierr_rhashtable_vni_init:
184862306a36Sopenharmony_ci	rhashtable_destroy(&fid_core->fid_ht);
184962306a36Sopenharmony_cierr_rhashtable_fid_init:
185062306a36Sopenharmony_ci	kfree(fid_core);
185162306a36Sopenharmony_ci	return err;
185262306a36Sopenharmony_ci}
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_civoid mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
185562306a36Sopenharmony_ci{
185662306a36Sopenharmony_ci	struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
185762306a36Sopenharmony_ci	int i;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
186062306a36Sopenharmony_ci		mlxsw_sp_fid_family_unregister(mlxsw_sp,
186162306a36Sopenharmony_ci					       fid_core->fid_family_arr[i]);
186262306a36Sopenharmony_ci	kfree(fid_core->port_fid_mappings);
186362306a36Sopenharmony_ci	rhashtable_destroy(&fid_core->vni_ht);
186462306a36Sopenharmony_ci	rhashtable_destroy(&fid_core->fid_ht);
186562306a36Sopenharmony_ci	kfree(fid_core);
186662306a36Sopenharmony_ci}
1867