xref: /openbmc/linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
19948a064SJiri Pirko // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
29948a064SJiri Pirko /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
3a1107487SIdo Schimmel 
4a1107487SIdo Schimmel #include <linux/kernel.h>
5a1107487SIdo Schimmel #include <linux/bitops.h>
6a1107487SIdo Schimmel #include <linux/if_vlan.h>
7a1107487SIdo Schimmel #include <linux/if_bridge.h>
8a1107487SIdo Schimmel #include <linux/netdevice.h>
9d3d19d4bSIdo Schimmel #include <linux/rhashtable.h>
10a1107487SIdo Schimmel #include <linux/rtnetlink.h>
11b96f5469SIdo Schimmel #include <linux/refcount.h>
12a1107487SIdo Schimmel 
13a1107487SIdo Schimmel #include "spectrum.h"
14a1107487SIdo Schimmel #include "reg.h"
15a1107487SIdo Schimmel 
16a1107487SIdo Schimmel struct mlxsw_sp_fid_family;
17a1107487SIdo Schimmel 
18a1107487SIdo Schimmel struct mlxsw_sp_fid_core {
195d44a712SIdo Schimmel 	struct rhashtable fid_ht;
20d3d19d4bSIdo Schimmel 	struct rhashtable vni_ht;
21a1107487SIdo Schimmel 	struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
22a1107487SIdo Schimmel 	unsigned int *port_fid_mappings;
23a1107487SIdo Schimmel };
24a1107487SIdo Schimmel 
25fddf42c3SAmit Cohen struct mlxsw_sp_fid_port_vid {
26fddf42c3SAmit Cohen 	struct list_head list;
27fddf42c3SAmit Cohen 	u16 local_port;
28fddf42c3SAmit Cohen 	u16 vid;
29fddf42c3SAmit Cohen };
30fddf42c3SAmit Cohen 
31a1107487SIdo Schimmel struct mlxsw_sp_fid {
32a1107487SIdo Schimmel 	struct list_head list;
33a1107487SIdo Schimmel 	struct mlxsw_sp_rif *rif;
34b96f5469SIdo Schimmel 	refcount_t ref_count;
35a1107487SIdo Schimmel 	u16 fid_index;
36736bf371SAmit Cohen 	u16 fid_offset;
37a1107487SIdo Schimmel 	struct mlxsw_sp_fid_family *fid_family;
385d44a712SIdo Schimmel 	struct rhash_head ht_node;
39d3d19d4bSIdo Schimmel 
40d3d19d4bSIdo Schimmel 	struct rhash_head vni_ht_node;
412a36c125SPetr Machata 	enum mlxsw_sp_nve_type nve_type;
42d3d19d4bSIdo Schimmel 	__be32 vni;
43d3d19d4bSIdo Schimmel 	u32 nve_flood_index;
445bae63d9SIdo Schimmel 	int nve_ifindex;
45d3d19d4bSIdo Schimmel 	u8 vni_valid:1,
46d3d19d4bSIdo Schimmel 	   nve_flood_index_valid:1;
47fddf42c3SAmit Cohen 	struct list_head port_vid_list; /* Ordered by local port. */
48a1107487SIdo Schimmel };
49a1107487SIdo Schimmel 
50a1107487SIdo Schimmel struct mlxsw_sp_fid_8021q {
51a1107487SIdo Schimmel 	struct mlxsw_sp_fid common;
52a1107487SIdo Schimmel 	u16 vid;
53a1107487SIdo Schimmel };
54a1107487SIdo Schimmel 
55a1107487SIdo Schimmel struct mlxsw_sp_fid_8021d {
56a1107487SIdo Schimmel 	struct mlxsw_sp_fid common;
57a1107487SIdo Schimmel 	int br_ifindex;
58a1107487SIdo Schimmel };
59a1107487SIdo Schimmel 
605d44a712SIdo Schimmel static const struct rhashtable_params mlxsw_sp_fid_ht_params = {
615d44a712SIdo Schimmel 	.key_len = sizeof_field(struct mlxsw_sp_fid, fid_index),
625d44a712SIdo Schimmel 	.key_offset = offsetof(struct mlxsw_sp_fid, fid_index),
635d44a712SIdo Schimmel 	.head_offset = offsetof(struct mlxsw_sp_fid, ht_node),
645d44a712SIdo Schimmel };
655d44a712SIdo Schimmel 
66d3d19d4bSIdo Schimmel static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = {
67d3d19d4bSIdo Schimmel 	.key_len = sizeof_field(struct mlxsw_sp_fid, vni),
68d3d19d4bSIdo Schimmel 	.key_offset = offsetof(struct mlxsw_sp_fid, vni),
69d3d19d4bSIdo Schimmel 	.head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node),
70d3d19d4bSIdo Schimmel };
71d3d19d4bSIdo Schimmel 
72a1107487SIdo Schimmel struct mlxsw_sp_flood_table {
73a1107487SIdo Schimmel 	enum mlxsw_sp_flood_type packet_type;
74a1107487SIdo Schimmel 	enum mlxsw_flood_table_type table_type;
75a1107487SIdo Schimmel 	int table_index;
76a1107487SIdo Schimmel };
77a1107487SIdo Schimmel 
78a1107487SIdo Schimmel struct mlxsw_sp_fid_ops {
79a1107487SIdo Schimmel 	void (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
80a1107487SIdo Schimmel 	int (*configure)(struct mlxsw_sp_fid *fid);
81a1107487SIdo Schimmel 	void (*deconfigure)(struct mlxsw_sp_fid *fid);
82a1107487SIdo Schimmel 	int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
83a1107487SIdo Schimmel 			   u16 *p_fid_index);
84a1107487SIdo Schimmel 	bool (*compare)(const struct mlxsw_sp_fid *fid,
85a1107487SIdo Schimmel 			const void *arg);
86a1107487SIdo Schimmel 	int (*port_vid_map)(struct mlxsw_sp_fid *fid,
87a1107487SIdo Schimmel 			    struct mlxsw_sp_port *port, u16 vid);
88a1107487SIdo Schimmel 	void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
89a1107487SIdo Schimmel 			       struct mlxsw_sp_port *port, u16 vid);
90d97da68eSAmit Cohen 	int (*vni_set)(struct mlxsw_sp_fid *fid);
91d3d19d4bSIdo Schimmel 	void (*vni_clear)(struct mlxsw_sp_fid *fid);
92d97da68eSAmit Cohen 	int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid);
93d3d19d4bSIdo Schimmel 	void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);
9483de7883SPetr Machata 	void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid,
9583de7883SPetr Machata 				  const struct net_device *nve_dev);
96bf73904fSAmit Cohen 	int (*vid_to_fid_rif_update)(const struct mlxsw_sp_fid *fid,
97bf73904fSAmit Cohen 				     const struct mlxsw_sp_rif *rif);
98a1107487SIdo Schimmel };
99a1107487SIdo Schimmel 
100a1107487SIdo Schimmel struct mlxsw_sp_fid_family {
101a1107487SIdo Schimmel 	enum mlxsw_sp_fid_type type;
102a1107487SIdo Schimmel 	size_t fid_size;
103a1107487SIdo Schimmel 	u16 start_index;
104a1107487SIdo Schimmel 	u16 end_index;
105a1107487SIdo Schimmel 	struct list_head fids_list;
106a1107487SIdo Schimmel 	unsigned long *fids_bitmap;
107a1107487SIdo Schimmel 	const struct mlxsw_sp_flood_table *flood_tables;
108a1107487SIdo Schimmel 	int nr_flood_tables;
109a1107487SIdo Schimmel 	enum mlxsw_sp_rif_type rif_type;
110a1107487SIdo Schimmel 	const struct mlxsw_sp_fid_ops *ops;
111a1107487SIdo Schimmel 	struct mlxsw_sp *mlxsw_sp;
11293303ff8SAmit Cohen 	bool flood_rsp;
113dd8c77d5SAmit Cohen 	enum mlxsw_reg_bridge_type bridge_type;
1149f6f467aSAmit Cohen 	u16 pgt_base;
115d4324e31SAmit Cohen 	bool smpe_index_valid;
116a1107487SIdo Schimmel };
117a1107487SIdo Schimmel 
118a1107487SIdo Schimmel static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
119a1107487SIdo Schimmel 	[MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST]			= 1,
120a1107487SIdo Schimmel };
121a1107487SIdo Schimmel 
122a1107487SIdo Schimmel static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
123a1107487SIdo Schimmel 	[MLXSW_REG_SFGC_TYPE_BROADCAST]				= 1,
124a1107487SIdo Schimmel 	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP]	= 1,
125a1107487SIdo Schimmel 	[MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL]			= 1,
126a1107487SIdo Schimmel 	[MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST]			= 1,
1279d45deb0SIdo Schimmel 	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6]	= 1,
128a1107487SIdo Schimmel };
129a1107487SIdo Schimmel 
130a1107487SIdo Schimmel static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
131a1107487SIdo Schimmel 	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4]	= 1,
132a1107487SIdo Schimmel };
133a1107487SIdo Schimmel 
134a1107487SIdo Schimmel static const int *mlxsw_sp_packet_type_sfgc_types[] = {
135a1107487SIdo Schimmel 	[MLXSW_SP_FLOOD_TYPE_UC]	= mlxsw_sp_sfgc_uc_packet_types,
136a1107487SIdo Schimmel 	[MLXSW_SP_FLOOD_TYPE_BC]	= mlxsw_sp_sfgc_bc_packet_types,
137a1107487SIdo Schimmel 	[MLXSW_SP_FLOOD_TYPE_MC]	= mlxsw_sp_sfgc_mc_packet_types,
138a1107487SIdo Schimmel };
139a1107487SIdo Schimmel 
mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp * mlxsw_sp,u16 fid_index)1405d44a712SIdo Schimmel struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
1415d44a712SIdo Schimmel 						  u16 fid_index)
1425d44a712SIdo Schimmel {
1435d44a712SIdo Schimmel 	struct mlxsw_sp_fid *fid;
1445d44a712SIdo Schimmel 
1455d44a712SIdo Schimmel 	fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index,
1465d44a712SIdo Schimmel 				     mlxsw_sp_fid_ht_params);
1475d44a712SIdo Schimmel 	if (fid)
148b96f5469SIdo Schimmel 		refcount_inc(&fid->ref_count);
1495d44a712SIdo Schimmel 
1505d44a712SIdo Schimmel 	return fid;
1515d44a712SIdo Schimmel }
1525d44a712SIdo Schimmel 
mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid * fid,int * nve_ifindex)1535bae63d9SIdo Schimmel int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex)
1545bae63d9SIdo Schimmel {
1555bae63d9SIdo Schimmel 	if (!fid->vni_valid)
1565bae63d9SIdo Schimmel 		return -EINVAL;
1575bae63d9SIdo Schimmel 
1585bae63d9SIdo Schimmel 	*nve_ifindex = fid->nve_ifindex;
1595bae63d9SIdo Schimmel 
1605bae63d9SIdo Schimmel 	return 0;
1615bae63d9SIdo Schimmel }
1625bae63d9SIdo Schimmel 
mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid * fid,enum mlxsw_sp_nve_type * p_type)1632a36c125SPetr Machata int mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid,
1642a36c125SPetr Machata 			  enum mlxsw_sp_nve_type *p_type)
1652a36c125SPetr Machata {
1662a36c125SPetr Machata 	if (!fid->vni_valid)
1672a36c125SPetr Machata 		return -EINVAL;
1682a36c125SPetr Machata 
1692a36c125SPetr Machata 	*p_type = fid->nve_type;
1702a36c125SPetr Machata 
1712a36c125SPetr Machata 	return 0;
1722a36c125SPetr Machata }
1732a36c125SPetr Machata 
mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp * mlxsw_sp,__be32 vni)174564c6d72SIdo Schimmel struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,
175564c6d72SIdo Schimmel 						__be32 vni)
176564c6d72SIdo Schimmel {
177564c6d72SIdo Schimmel 	struct mlxsw_sp_fid *fid;
178564c6d72SIdo Schimmel 
179564c6d72SIdo Schimmel 	fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni,
180564c6d72SIdo Schimmel 				     mlxsw_sp_fid_vni_ht_params);
181564c6d72SIdo Schimmel 	if (fid)
182b96f5469SIdo Schimmel 		refcount_inc(&fid->ref_count);
183564c6d72SIdo Schimmel 
184564c6d72SIdo Schimmel 	return fid;
185564c6d72SIdo Schimmel }
186564c6d72SIdo Schimmel 
mlxsw_sp_fid_vni(const struct mlxsw_sp_fid * fid,__be32 * vni)187d3d19d4bSIdo Schimmel int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni)
188d3d19d4bSIdo Schimmel {
189d3d19d4bSIdo Schimmel 	if (!fid->vni_valid)
190d3d19d4bSIdo Schimmel 		return -EINVAL;
191d3d19d4bSIdo Schimmel 
192d3d19d4bSIdo Schimmel 	*vni = fid->vni;
193d3d19d4bSIdo Schimmel 
194d3d19d4bSIdo Schimmel 	return 0;
195d3d19d4bSIdo Schimmel }
196d3d19d4bSIdo Schimmel 
mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid * fid,u32 nve_flood_index)197d3d19d4bSIdo Schimmel int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
198d3d19d4bSIdo Schimmel 				     u32 nve_flood_index)
199d3d19d4bSIdo Schimmel {
200d3d19d4bSIdo Schimmel 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
201d3d19d4bSIdo Schimmel 	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
202d3d19d4bSIdo Schimmel 	int err;
203d3d19d4bSIdo Schimmel 
204048fcbb7SAmit Cohen 	if (WARN_ON(fid->nve_flood_index_valid))
205d3d19d4bSIdo Schimmel 		return -EINVAL;
206d3d19d4bSIdo Schimmel 
207d3d19d4bSIdo Schimmel 	fid->nve_flood_index = nve_flood_index;
208d3d19d4bSIdo Schimmel 	fid->nve_flood_index_valid = true;
209d97da68eSAmit Cohen 	err = ops->nve_flood_index_set(fid);
210d97da68eSAmit Cohen 	if (err)
211d97da68eSAmit Cohen 		goto err_nve_flood_index_set;
212d3d19d4bSIdo Schimmel 
213d3d19d4bSIdo Schimmel 	return 0;
214d97da68eSAmit Cohen 
215d97da68eSAmit Cohen err_nve_flood_index_set:
216d97da68eSAmit Cohen 	fid->nve_flood_index_valid = false;
217d97da68eSAmit Cohen 	return err;
218d3d19d4bSIdo Schimmel }
219d3d19d4bSIdo Schimmel 
mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid * fid)220d3d19d4bSIdo Schimmel void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
221d3d19d4bSIdo Schimmel {
222d3d19d4bSIdo Schimmel 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
223d3d19d4bSIdo Schimmel 	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
224d3d19d4bSIdo Schimmel 
225048fcbb7SAmit Cohen 	if (WARN_ON(!fid->nve_flood_index_valid))
226d3d19d4bSIdo Schimmel 		return;
227d3d19d4bSIdo Schimmel 
228d3d19d4bSIdo Schimmel 	fid->nve_flood_index_valid = false;
229d3d19d4bSIdo Schimmel 	ops->nve_flood_index_clear(fid);
230d3d19d4bSIdo Schimmel }
231d3d19d4bSIdo Schimmel 
mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid * fid)232d3d19d4bSIdo Schimmel bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
233d3d19d4bSIdo Schimmel {
234d3d19d4bSIdo Schimmel 	return fid->nve_flood_index_valid;
235d3d19d4bSIdo Schimmel }
236d3d19d4bSIdo Schimmel 
mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid * fid,enum mlxsw_sp_nve_type type,__be32 vni,int nve_ifindex)2372a36c125SPetr Machata int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type,
2382a36c125SPetr Machata 			 __be32 vni, int nve_ifindex)
239d3d19d4bSIdo Schimmel {
240d3d19d4bSIdo Schimmel 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
241d3d19d4bSIdo Schimmel 	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
242d3d19d4bSIdo Schimmel 	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
243d3d19d4bSIdo Schimmel 	int err;
244d3d19d4bSIdo Schimmel 
245048fcbb7SAmit Cohen 	if (WARN_ON(fid->vni_valid))
246d3d19d4bSIdo Schimmel 		return -EINVAL;
247d3d19d4bSIdo Schimmel 
2482a36c125SPetr Machata 	fid->nve_type = type;
2495bae63d9SIdo Schimmel 	fid->nve_ifindex = nve_ifindex;
250d3d19d4bSIdo Schimmel 	fid->vni = vni;
251d3d19d4bSIdo Schimmel 	err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht,
252d3d19d4bSIdo Schimmel 					    &fid->vni_ht_node,
253d3d19d4bSIdo Schimmel 					    mlxsw_sp_fid_vni_ht_params);
254d3d19d4bSIdo Schimmel 	if (err)
255d3d19d4bSIdo Schimmel 		return err;
256d3d19d4bSIdo Schimmel 
257d97da68eSAmit Cohen 	fid->vni_valid = true;
258d97da68eSAmit Cohen 	err = ops->vni_set(fid);
259d3d19d4bSIdo Schimmel 	if (err)
260d3d19d4bSIdo Schimmel 		goto err_vni_set;
261d3d19d4bSIdo Schimmel 
262d3d19d4bSIdo Schimmel 	return 0;
263d3d19d4bSIdo Schimmel 
264d3d19d4bSIdo Schimmel err_vni_set:
265d97da68eSAmit Cohen 	fid->vni_valid = false;
266d3d19d4bSIdo Schimmel 	rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
267d3d19d4bSIdo Schimmel 			       mlxsw_sp_fid_vni_ht_params);
268d3d19d4bSIdo Schimmel 	return err;
269d3d19d4bSIdo Schimmel }
270d3d19d4bSIdo Schimmel 
mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid * fid)271d3d19d4bSIdo Schimmel void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid)
272d3d19d4bSIdo Schimmel {
273d3d19d4bSIdo Schimmel 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
274d3d19d4bSIdo Schimmel 	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
275d3d19d4bSIdo Schimmel 	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
276d3d19d4bSIdo Schimmel 
277048fcbb7SAmit Cohen 	if (WARN_ON(!fid->vni_valid))
278d3d19d4bSIdo Schimmel 		return;
279d3d19d4bSIdo Schimmel 
280d3d19d4bSIdo Schimmel 	fid->vni_valid = false;
281d3d19d4bSIdo Schimmel 	ops->vni_clear(fid);
282d3d19d4bSIdo Schimmel 	rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
283d3d19d4bSIdo Schimmel 			       mlxsw_sp_fid_vni_ht_params);
284d3d19d4bSIdo Schimmel }
285d3d19d4bSIdo Schimmel 
mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid * fid)286d3d19d4bSIdo Schimmel bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
287d3d19d4bSIdo Schimmel {
288d3d19d4bSIdo Schimmel 	return fid->vni_valid;
289d3d19d4bSIdo Schimmel }
290d3d19d4bSIdo Schimmel 
mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid * fid,const struct net_device * nve_dev)29183de7883SPetr Machata void mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
29283de7883SPetr Machata 				    const struct net_device *nve_dev)
29383de7883SPetr Machata {
29483de7883SPetr Machata 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
29583de7883SPetr Machata 	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
29683de7883SPetr Machata 
29783de7883SPetr Machata 	if (ops->fdb_clear_offload)
29883de7883SPetr Machata 		ops->fdb_clear_offload(fid, nve_dev);
29983de7883SPetr Machata }
30083de7883SPetr Machata 
301a1107487SIdo Schimmel static const struct mlxsw_sp_flood_table *
mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid * fid,enum mlxsw_sp_flood_type packet_type)302a1107487SIdo Schimmel mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
303a1107487SIdo Schimmel 				enum mlxsw_sp_flood_type packet_type)
304a1107487SIdo Schimmel {
305a1107487SIdo Schimmel 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
306a1107487SIdo Schimmel 	int i;
307a1107487SIdo Schimmel 
308a1107487SIdo Schimmel 	for (i = 0; i < fid_family->nr_flood_tables; i++) {
309a1107487SIdo Schimmel 		if (fid_family->flood_tables[i].packet_type != packet_type)
310a1107487SIdo Schimmel 			continue;
311a1107487SIdo Schimmel 		return &fid_family->flood_tables[i];
312a1107487SIdo Schimmel 	}
313a1107487SIdo Schimmel 
314a1107487SIdo Schimmel 	return NULL;
315a1107487SIdo Schimmel }
316a1107487SIdo Schimmel 
3179f6f467aSAmit Cohen static u16
mlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family * fid_family)318fe94df6dSAmit Cohen mlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family *fid_family)
319fe94df6dSAmit Cohen {
320fe94df6dSAmit Cohen 	return fid_family->end_index - fid_family->start_index + 1;
321fe94df6dSAmit Cohen }
322fe94df6dSAmit Cohen 
323fe94df6dSAmit Cohen static u16
mlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family * fid_family,const struct mlxsw_sp_flood_table * flood_table,u16 fid_offset)3249f6f467aSAmit Cohen mlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family *fid_family,
3259f6f467aSAmit Cohen 			     const struct mlxsw_sp_flood_table *flood_table,
3269f6f467aSAmit Cohen 			     u16 fid_offset)
3279f6f467aSAmit Cohen {
3289f6f467aSAmit Cohen 	u16 num_fids;
3299f6f467aSAmit Cohen 
330fe94df6dSAmit Cohen 	num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
3319f6f467aSAmit Cohen 	return fid_family->pgt_base + num_fids * flood_table->table_index +
3329f6f467aSAmit Cohen 	       fid_offset;
3339f6f467aSAmit Cohen }
3349f6f467aSAmit Cohen 
mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid * fid,enum mlxsw_sp_flood_type packet_type,u16 local_port,bool member)335a1107487SIdo Schimmel int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
336c934757dSAmit Cohen 			   enum mlxsw_sp_flood_type packet_type, u16 local_port,
337a1107487SIdo Schimmel 			   bool member)
338a1107487SIdo Schimmel {
339a1107487SIdo Schimmel 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
340a1107487SIdo Schimmel 	const struct mlxsw_sp_flood_table *flood_table;
341fe94df6dSAmit Cohen 	u16 mid_index;
342a1107487SIdo Schimmel 
3438928fd47SAmit Cohen 	if (WARN_ON(!fid_family->flood_tables))
344a1107487SIdo Schimmel 		return -EINVAL;
345a1107487SIdo Schimmel 
346a1107487SIdo Schimmel 	flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
347a1107487SIdo Schimmel 	if (!flood_table)
348a1107487SIdo Schimmel 		return -ESRCH;
349a1107487SIdo Schimmel 
35077b7f83dSAmit Cohen 	mid_index = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table,
351fe94df6dSAmit Cohen 						 fid->fid_offset);
35277b7f83dSAmit Cohen 	return mlxsw_sp_pgt_entry_port_set(fid_family->mlxsw_sp, mid_index,
35377b7f83dSAmit Cohen 					   fid->fid_index, local_port, member);
354a1107487SIdo Schimmel }
355a1107487SIdo Schimmel 
mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)356a1107487SIdo Schimmel int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
357a1107487SIdo Schimmel 			      struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
358a1107487SIdo Schimmel {
359a1107487SIdo Schimmel 	if (WARN_ON(!fid->fid_family->ops->port_vid_map))
360a1107487SIdo Schimmel 		return -EINVAL;
361a1107487SIdo Schimmel 	return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);
362a1107487SIdo Schimmel }
363a1107487SIdo Schimmel 
mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)364a1107487SIdo Schimmel void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
365a1107487SIdo Schimmel 				 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
366a1107487SIdo Schimmel {
367a1107487SIdo Schimmel 	fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
368a1107487SIdo Schimmel }
369a1107487SIdo Schimmel 
mlxsw_sp_fid_index(const struct mlxsw_sp_fid * fid)370a1107487SIdo Schimmel u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
371a1107487SIdo Schimmel {
372a1107487SIdo Schimmel 	return fid->fid_index;
373a1107487SIdo Schimmel }
374a1107487SIdo Schimmel 
mlxsw_sp_fid_type(const struct mlxsw_sp_fid * fid)375a1107487SIdo Schimmel enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
376a1107487SIdo Schimmel {
377a1107487SIdo Schimmel 	return fid->fid_family->type;
378a1107487SIdo Schimmel }
379a1107487SIdo Schimmel 
mlxsw_sp_fid_rif(const struct mlxsw_sp_fid * fid)38032fd4b49SIdo Schimmel struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
38132fd4b49SIdo Schimmel {
38232fd4b49SIdo Schimmel 	return fid->rif;
38332fd4b49SIdo Schimmel }
38432fd4b49SIdo Schimmel 
385e4f3c1c1SIdo Schimmel enum mlxsw_sp_rif_type
mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_fid_type type)386e4f3c1c1SIdo Schimmel mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
387e4f3c1c1SIdo Schimmel 			   enum mlxsw_sp_fid_type type)
388e4f3c1c1SIdo Schimmel {
389e4f3c1c1SIdo Schimmel 	struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
390e4f3c1c1SIdo Schimmel 
391e4f3c1c1SIdo Schimmel 	return fid_core->fid_family_arr[type]->rif_type;
392e4f3c1c1SIdo Schimmel }
393e4f3c1c1SIdo Schimmel 
394a1107487SIdo Schimmel static struct mlxsw_sp_fid_8021q *
mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid * fid)395a1107487SIdo Schimmel mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
396a1107487SIdo Schimmel {
397a1107487SIdo Schimmel 	return container_of(fid, struct mlxsw_sp_fid_8021q, common);
398a1107487SIdo Schimmel }
399a1107487SIdo Schimmel 
mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid * fid)400e4f3c1c1SIdo Schimmel u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
401e4f3c1c1SIdo Schimmel {
402e4f3c1c1SIdo Schimmel 	return mlxsw_sp_fid_8021q_fid(fid)->vid;
403e4f3c1c1SIdo Schimmel }
404e4f3c1c1SIdo Schimmel 
mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid * fid,const void * arg)405a1107487SIdo Schimmel static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
406a1107487SIdo Schimmel {
407a1107487SIdo Schimmel 	u16 vid = *(u16 *) arg;
408a1107487SIdo Schimmel 
409a1107487SIdo Schimmel 	mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
410bf73904fSAmit Cohen 	fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
411a1107487SIdo Schimmel }
412a1107487SIdo Schimmel 
mlxsw_sp_sfmr_op(bool valid)413a1107487SIdo Schimmel static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
414a1107487SIdo Schimmel {
415a1107487SIdo Schimmel 	return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
416a1107487SIdo Schimmel 		       MLXSW_REG_SFMR_OP_DESTROY_FID;
417a1107487SIdo Schimmel }
418a1107487SIdo Schimmel 
mlxsw_sp_fid_op(const struct mlxsw_sp_fid * fid,bool valid)41997a2ae0fSAmit Cohen static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid)
420a1107487SIdo Schimmel {
42197a2ae0fSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
422a1107487SIdo Schimmel 	char sfmr_pl[MLXSW_REG_SFMR_LEN];
42377b7f83dSAmit Cohen 	u16 smpe;
42493303ff8SAmit Cohen 
42577b7f83dSAmit Cohen 	smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;
426a1107487SIdo Schimmel 
42797a2ae0fSAmit Cohen 	mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid->fid_index,
42877b7f83dSAmit Cohen 			    fid->fid_offset, fid->fid_family->flood_rsp,
42977b7f83dSAmit Cohen 			    fid->fid_family->bridge_type,
43077b7f83dSAmit Cohen 			    fid->fid_family->smpe_index_valid, smpe);
431a1107487SIdo Schimmel 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
432a1107487SIdo Schimmel }
433a1107487SIdo Schimmel 
mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)434fea20547SAmit Cohen static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid,
435fea20547SAmit Cohen 				const struct mlxsw_sp_rif *rif)
436d3d19d4bSIdo Schimmel {
437893b5c30SAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
438d3d19d4bSIdo Schimmel 	char sfmr_pl[MLXSW_REG_SFMR_LEN];
43977b7f83dSAmit Cohen 	u16 smpe;
44093303ff8SAmit Cohen 
44177b7f83dSAmit Cohen 	smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;
442d3d19d4bSIdo Schimmel 
443893b5c30SAmit Cohen 	mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID,
44477b7f83dSAmit Cohen 			    fid->fid_index, fid->fid_offset,
44577b7f83dSAmit Cohen 			    fid->fid_family->flood_rsp,
44677b7f83dSAmit Cohen 			    fid->fid_family->bridge_type,
44777b7f83dSAmit Cohen 			    fid->fid_family->smpe_index_valid, smpe);
448893b5c30SAmit Cohen 	mlxsw_reg_sfmr_vv_set(sfmr_pl, fid->vni_valid);
449893b5c30SAmit Cohen 	mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(fid->vni));
450893b5c30SAmit Cohen 	mlxsw_reg_sfmr_vtfp_set(sfmr_pl, fid->nve_flood_index_valid);
451893b5c30SAmit Cohen 	mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, fid->nve_flood_index);
452fea20547SAmit Cohen 
45377b7f83dSAmit Cohen 	if (rif) {
454fea20547SAmit Cohen 		mlxsw_reg_sfmr_irif_v_set(sfmr_pl, true);
455fea20547SAmit Cohen 		mlxsw_reg_sfmr_irif_set(sfmr_pl, mlxsw_sp_rif_index(rif));
456fea20547SAmit Cohen 	}
457fea20547SAmit Cohen 
458d3d19d4bSIdo Schimmel 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
459d3d19d4bSIdo Schimmel }
460d3d19d4bSIdo Schimmel 
mlxsw_sp_fid_vni_to_fid_map(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif,bool valid)4618cfc7f77SAmit Cohen static int mlxsw_sp_fid_vni_to_fid_map(const struct mlxsw_sp_fid *fid,
462fea20547SAmit Cohen 				       const struct mlxsw_sp_rif *rif,
4638cfc7f77SAmit Cohen 				       bool valid)
4648cfc7f77SAmit Cohen {
4658cfc7f77SAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
4668cfc7f77SAmit Cohen 	char svfa_pl[MLXSW_REG_SVFA_LEN];
467fea20547SAmit Cohen 	bool irif_valid;
468fea20547SAmit Cohen 	u16 irif_index;
469fea20547SAmit Cohen 
470fea20547SAmit Cohen 	irif_valid = !!rif;
471fea20547SAmit Cohen 	irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
4728cfc7f77SAmit Cohen 
4738cfc7f77SAmit Cohen 	mlxsw_reg_svfa_vni_pack(svfa_pl, valid, fid->fid_index,
474fea20547SAmit Cohen 				be32_to_cpu(fid->vni), irif_valid, irif_index);
4758cfc7f77SAmit Cohen 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
4768cfc7f77SAmit Cohen }
4778cfc7f77SAmit Cohen 
mlxsw_sp_fid_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)478fea20547SAmit Cohen static int mlxsw_sp_fid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
479fea20547SAmit Cohen 					  const struct mlxsw_sp_rif *rif)
480fea20547SAmit Cohen {
481fea20547SAmit Cohen 	return mlxsw_sp_fid_edit_op(fid, rif);
482fea20547SAmit Cohen }
483fea20547SAmit Cohen 
mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)484fea20547SAmit Cohen static int mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
485fea20547SAmit Cohen 					      const struct mlxsw_sp_rif *rif)
486fea20547SAmit Cohen {
487fea20547SAmit Cohen 	if (!fid->vni_valid)
488fea20547SAmit Cohen 		return 0;
489fea20547SAmit Cohen 
490fea20547SAmit Cohen 	return mlxsw_sp_fid_vni_to_fid_map(fid, rif, fid->vni_valid);
491fea20547SAmit Cohen }
492fea20547SAmit Cohen 
493fea20547SAmit Cohen static int
mlxsw_sp_fid_vid_to_fid_map(const struct mlxsw_sp_fid * fid,u16 vid,bool valid,const struct mlxsw_sp_rif * rif)494bf73904fSAmit Cohen mlxsw_sp_fid_vid_to_fid_map(const struct mlxsw_sp_fid *fid, u16 vid, bool valid,
495bf73904fSAmit Cohen 			    const struct mlxsw_sp_rif *rif)
496bf73904fSAmit Cohen {
497bf73904fSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
498bf73904fSAmit Cohen 	char svfa_pl[MLXSW_REG_SVFA_LEN];
499bf73904fSAmit Cohen 	bool irif_valid;
500bf73904fSAmit Cohen 	u16 irif_index;
501bf73904fSAmit Cohen 
502bf73904fSAmit Cohen 	irif_valid = !!rif;
503bf73904fSAmit Cohen 	irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
504bf73904fSAmit Cohen 
505bf73904fSAmit Cohen 	mlxsw_reg_svfa_vid_pack(svfa_pl, valid, fid->fid_index, vid, irif_valid,
506bf73904fSAmit Cohen 				irif_index);
507bf73904fSAmit Cohen 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
508bf73904fSAmit Cohen }
509bf73904fSAmit Cohen 
510bf73904fSAmit Cohen static int
mlxsw_sp_fid_8021q_vid_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)511bf73904fSAmit Cohen mlxsw_sp_fid_8021q_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
512bf73904fSAmit Cohen 					 const struct mlxsw_sp_rif *rif)
513bf73904fSAmit Cohen {
514bf73904fSAmit Cohen 	struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
515bf73904fSAmit Cohen 
516bf73904fSAmit Cohen 	/* Update the global VID => FID mapping we created when the FID was
517bf73904fSAmit Cohen 	 * configured.
518bf73904fSAmit Cohen 	 */
519bf73904fSAmit Cohen 	return mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, rif);
520bf73904fSAmit Cohen }
521bf73904fSAmit Cohen 
522bf73904fSAmit Cohen static int
mlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid * fid,struct mlxsw_sp_fid_port_vid * pv,bool irif_valid,u16 irif_index)523fea20547SAmit Cohen mlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid *fid,
524fea20547SAmit Cohen 					    struct mlxsw_sp_fid_port_vid *pv,
525fea20547SAmit Cohen 					    bool irif_valid, u16 irif_index)
526fea20547SAmit Cohen {
527fea20547SAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
528fea20547SAmit Cohen 	char svfa_pl[MLXSW_REG_SVFA_LEN];
529fea20547SAmit Cohen 
530fea20547SAmit Cohen 	mlxsw_reg_svfa_port_vid_pack(svfa_pl, pv->local_port, true,
531fea20547SAmit Cohen 				     fid->fid_index, pv->vid, irif_valid,
532fea20547SAmit Cohen 				     irif_index);
533fea20547SAmit Cohen 
534fea20547SAmit Cohen 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
535fea20547SAmit Cohen }
536fea20547SAmit Cohen 
mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)537fea20547SAmit Cohen static int mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid *fid,
538fea20547SAmit Cohen 					   const struct mlxsw_sp_rif *rif)
539fea20547SAmit Cohen {
540fea20547SAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
541fea20547SAmit Cohen 	struct mlxsw_sp_fid_port_vid *pv;
542fea20547SAmit Cohen 	u16 irif_index;
543fea20547SAmit Cohen 	int err;
544fea20547SAmit Cohen 
545bf73904fSAmit Cohen 	err = fid->fid_family->ops->vid_to_fid_rif_update(fid, rif);
546bf73904fSAmit Cohen 	if (err)
547bf73904fSAmit Cohen 		return err;
548bf73904fSAmit Cohen 
549fea20547SAmit Cohen 	irif_index = mlxsw_sp_rif_index(rif);
550fea20547SAmit Cohen 
551fea20547SAmit Cohen 	list_for_each_entry(pv, &fid->port_vid_list, list) {
552fea20547SAmit Cohen 		/* If port is not in virtual mode, then it does not have any
553fea20547SAmit Cohen 		 * {Port, VID}->FID mappings that need to be updated with the
554fea20547SAmit Cohen 		 * ingress RIF.
555fea20547SAmit Cohen 		 */
556fea20547SAmit Cohen 		if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
557fea20547SAmit Cohen 			continue;
558fea20547SAmit Cohen 
559fea20547SAmit Cohen 		err = mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv,
560fea20547SAmit Cohen 								  true,
561fea20547SAmit Cohen 								  irif_index);
562fea20547SAmit Cohen 		if (err)
563fea20547SAmit Cohen 			goto err_port_vid_to_fid_rif_update_one;
564fea20547SAmit Cohen 	}
565fea20547SAmit Cohen 
566fea20547SAmit Cohen 	return 0;
567fea20547SAmit Cohen 
568fea20547SAmit Cohen err_port_vid_to_fid_rif_update_one:
569fea20547SAmit Cohen 	list_for_each_entry_continue_reverse(pv, &fid->port_vid_list, list) {
570fea20547SAmit Cohen 		if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
571fea20547SAmit Cohen 			continue;
572fea20547SAmit Cohen 
573fea20547SAmit Cohen 		mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
574fea20547SAmit Cohen 	}
575fea20547SAmit Cohen 
576bf73904fSAmit Cohen 	fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
577fea20547SAmit Cohen 	return err;
578fea20547SAmit Cohen }
579fea20547SAmit Cohen 
mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid * fid)580fea20547SAmit Cohen static void mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid *fid)
581fea20547SAmit Cohen {
582fea20547SAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
583fea20547SAmit Cohen 	struct mlxsw_sp_fid_port_vid *pv;
584fea20547SAmit Cohen 
585fea20547SAmit Cohen 	list_for_each_entry(pv, &fid->port_vid_list, list) {
586fea20547SAmit Cohen 		/* If port is not in virtual mode, then it does not have any
587fea20547SAmit Cohen 		 * {Port, VID}->FID mappings that need to be updated.
588fea20547SAmit Cohen 		 */
589fea20547SAmit Cohen 		if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
590fea20547SAmit Cohen 			continue;
591fea20547SAmit Cohen 
592fea20547SAmit Cohen 		mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
593fea20547SAmit Cohen 	}
594bf73904fSAmit Cohen 
595bf73904fSAmit Cohen 	fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
596fea20547SAmit Cohen }
597fea20547SAmit Cohen 
mlxsw_sp_fid_reiv_handle(struct mlxsw_sp_fid * fid,u16 rif_index,bool valid,u8 port_page)598d4b464d2SAmit Cohen static int mlxsw_sp_fid_reiv_handle(struct mlxsw_sp_fid *fid, u16 rif_index,
599d4b464d2SAmit Cohen 				    bool valid, u8 port_page)
600d4b464d2SAmit Cohen {
601d4b464d2SAmit Cohen 	u16 local_port_end = (port_page + 1) * MLXSW_REG_REIV_REC_MAX_COUNT - 1;
602d4b464d2SAmit Cohen 	u16 local_port_start = port_page * MLXSW_REG_REIV_REC_MAX_COUNT;
603d4b464d2SAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
604d4b464d2SAmit Cohen 	struct mlxsw_sp_fid_port_vid *port_vid;
605d4b464d2SAmit Cohen 	u8 rec_num, entries_num = 0;
606d4b464d2SAmit Cohen 	char *reiv_pl;
607d4b464d2SAmit Cohen 	int err;
608d4b464d2SAmit Cohen 
609d4b464d2SAmit Cohen 	reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
610d4b464d2SAmit Cohen 	if (!reiv_pl)
611d4b464d2SAmit Cohen 		return -ENOMEM;
612d4b464d2SAmit Cohen 
613d4b464d2SAmit Cohen 	mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);
614d4b464d2SAmit Cohen 
615d4b464d2SAmit Cohen 	list_for_each_entry(port_vid, &fid->port_vid_list, list) {
616d4b464d2SAmit Cohen 		/* port_vid_list is sorted by local_port. */
617d4b464d2SAmit Cohen 		if (port_vid->local_port < local_port_start)
618d4b464d2SAmit Cohen 			continue;
619d4b464d2SAmit Cohen 
620d4b464d2SAmit Cohen 		if (port_vid->local_port > local_port_end)
621d4b464d2SAmit Cohen 			break;
622d4b464d2SAmit Cohen 
623d4b464d2SAmit Cohen 		rec_num = port_vid->local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
624d4b464d2SAmit Cohen 		mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);
625d4b464d2SAmit Cohen 		mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num,
626d4b464d2SAmit Cohen 					    valid ? port_vid->vid : 0);
627d4b464d2SAmit Cohen 		entries_num++;
628d4b464d2SAmit Cohen 	}
629d4b464d2SAmit Cohen 
630d4b464d2SAmit Cohen 	if (!entries_num) {
631d4b464d2SAmit Cohen 		kfree(reiv_pl);
632d4b464d2SAmit Cohen 		return 0;
633d4b464d2SAmit Cohen 	}
634d4b464d2SAmit Cohen 
635d4b464d2SAmit Cohen 	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);
636d4b464d2SAmit Cohen 	if (err)
637d4b464d2SAmit Cohen 		goto err_reg_write;
638d4b464d2SAmit Cohen 
639d4b464d2SAmit Cohen 	kfree(reiv_pl);
640d4b464d2SAmit Cohen 	return 0;
641d4b464d2SAmit Cohen 
642d4b464d2SAmit Cohen err_reg_write:
643d4b464d2SAmit Cohen 	kfree(reiv_pl);
644d4b464d2SAmit Cohen 	return err;
645d4b464d2SAmit Cohen }
646d4b464d2SAmit Cohen 
mlxsw_sp_fid_erif_eport_to_vid_map(struct mlxsw_sp_fid * fid,u16 rif_index,bool valid)647d4b464d2SAmit Cohen static int mlxsw_sp_fid_erif_eport_to_vid_map(struct mlxsw_sp_fid *fid,
648d4b464d2SAmit Cohen 					      u16 rif_index, bool valid)
649d4b464d2SAmit Cohen {
650d4b464d2SAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
651d4b464d2SAmit Cohen 	u8 num_port_pages;
652d4b464d2SAmit Cohen 	int err, i;
653d4b464d2SAmit Cohen 
654d4b464d2SAmit Cohen 	num_port_pages = mlxsw_core_max_ports(mlxsw_sp->core) /
655d4b464d2SAmit Cohen 			 MLXSW_REG_REIV_REC_MAX_COUNT + 1;
656d4b464d2SAmit Cohen 
657d4b464d2SAmit Cohen 	for (i = 0; i < num_port_pages; i++) {
658d4b464d2SAmit Cohen 		err = mlxsw_sp_fid_reiv_handle(fid, rif_index, valid, i);
659d4b464d2SAmit Cohen 		if (err)
660d4b464d2SAmit Cohen 			goto err_reiv_handle;
661d4b464d2SAmit Cohen 	}
662d4b464d2SAmit Cohen 
663d4b464d2SAmit Cohen 	return 0;
664d4b464d2SAmit Cohen 
665d4b464d2SAmit Cohen err_reiv_handle:
666d4b464d2SAmit Cohen 	for (; i >= 0; i--)
667d4b464d2SAmit Cohen 		mlxsw_sp_fid_reiv_handle(fid, rif_index, !valid, i);
668d4b464d2SAmit Cohen 	return err;
669d4b464d2SAmit Cohen }
670d4b464d2SAmit Cohen 
mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid * fid,struct mlxsw_sp_rif * rif)671fea20547SAmit Cohen int mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
672fea20547SAmit Cohen {
673d4b464d2SAmit Cohen 	u16 rif_index = mlxsw_sp_rif_index(rif);
674fea20547SAmit Cohen 	int err;
675fea20547SAmit Cohen 
676fea20547SAmit Cohen 	err = mlxsw_sp_fid_to_fid_rif_update(fid, rif);
677fea20547SAmit Cohen 	if (err)
678fea20547SAmit Cohen 		return err;
679fea20547SAmit Cohen 
680fea20547SAmit Cohen 	err = mlxsw_sp_fid_vni_to_fid_rif_update(fid, rif);
681fea20547SAmit Cohen 	if (err)
682fea20547SAmit Cohen 		goto err_vni_to_fid_rif_update;
683fea20547SAmit Cohen 
684fea20547SAmit Cohen 	err = mlxsw_sp_fid_vid_to_fid_rif_set(fid, rif);
685fea20547SAmit Cohen 	if (err)
686fea20547SAmit Cohen 		goto err_vid_to_fid_rif_set;
687fea20547SAmit Cohen 
688d4b464d2SAmit Cohen 	err = mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, true);
689d4b464d2SAmit Cohen 	if (err)
690d4b464d2SAmit Cohen 		goto err_erif_eport_to_vid_map;
691d4b464d2SAmit Cohen 
692fea20547SAmit Cohen 	fid->rif = rif;
693fea20547SAmit Cohen 	return 0;
694fea20547SAmit Cohen 
695d4b464d2SAmit Cohen err_erif_eport_to_vid_map:
696d4b464d2SAmit Cohen 	mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
697fea20547SAmit Cohen err_vid_to_fid_rif_set:
698fea20547SAmit Cohen 	mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
699fea20547SAmit Cohen err_vni_to_fid_rif_update:
700fea20547SAmit Cohen 	mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
701fea20547SAmit Cohen 	return err;
702fea20547SAmit Cohen }
703fea20547SAmit Cohen 
mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid * fid)704fea20547SAmit Cohen void mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid *fid)
705fea20547SAmit Cohen {
706d4b464d2SAmit Cohen 	u16 rif_index;
707d4b464d2SAmit Cohen 
708fea20547SAmit Cohen 	if (!fid->rif)
709fea20547SAmit Cohen 		return;
710fea20547SAmit Cohen 
711d4b464d2SAmit Cohen 	rif_index = mlxsw_sp_rif_index(fid->rif);
712fea20547SAmit Cohen 	fid->rif = NULL;
713d4b464d2SAmit Cohen 
714d4b464d2SAmit Cohen 	mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, false);
715fea20547SAmit Cohen 	mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
716fea20547SAmit Cohen 	mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
717fea20547SAmit Cohen 	mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
718fea20547SAmit Cohen }
719fea20547SAmit Cohen 
mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid * fid)7208cfc7f77SAmit Cohen static int mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid *fid)
7218cfc7f77SAmit Cohen {
7228cfc7f77SAmit Cohen 	int err;
7238cfc7f77SAmit Cohen 
72477b7f83dSAmit Cohen 	err = mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, fid->vni_valid);
7258cfc7f77SAmit Cohen 	if (err)
7268cfc7f77SAmit Cohen 		return err;
7278cfc7f77SAmit Cohen 
728fea20547SAmit Cohen 	err = mlxsw_sp_fid_edit_op(fid, fid->rif);
7298cfc7f77SAmit Cohen 	if (err)
7308cfc7f77SAmit Cohen 		goto err_fid_edit_op;
7318cfc7f77SAmit Cohen 
7328cfc7f77SAmit Cohen 	return 0;
7338cfc7f77SAmit Cohen 
7348cfc7f77SAmit Cohen err_fid_edit_op:
735fea20547SAmit Cohen 	mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, !fid->vni_valid);
7368cfc7f77SAmit Cohen 	return err;
7378cfc7f77SAmit Cohen }
7388cfc7f77SAmit Cohen 
__mlxsw_sp_fid_port_vid_map(const struct mlxsw_sp_fid * fid,u16 local_port,u16 vid,bool valid)7392c091048SAmit Cohen static int __mlxsw_sp_fid_port_vid_map(const struct mlxsw_sp_fid *fid,
740c934757dSAmit Cohen 				       u16 local_port, u16 vid, bool valid)
741a1107487SIdo Schimmel {
7422c091048SAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
743a1107487SIdo Schimmel 	char svfa_pl[MLXSW_REG_SVFA_LEN];
744fea20547SAmit Cohen 	bool irif_valid = false;
745fea20547SAmit Cohen 	u16 irif_index = 0;
746fea20547SAmit Cohen 
74777b7f83dSAmit Cohen 	if (fid->rif) {
748fea20547SAmit Cohen 		irif_valid = true;
749fea20547SAmit Cohen 		irif_index = mlxsw_sp_rif_index(fid->rif);
750fea20547SAmit Cohen 	}
751a1107487SIdo Schimmel 
7522c091048SAmit Cohen 	mlxsw_reg_svfa_port_vid_pack(svfa_pl, local_port, valid, fid->fid_index,
753fea20547SAmit Cohen 				     vid, irif_valid, irif_index);
754a1107487SIdo Schimmel 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
755a1107487SIdo Schimmel }
756a1107487SIdo Schimmel 
757a1107487SIdo Schimmel static struct mlxsw_sp_fid_8021d *
mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid * fid)758a1107487SIdo Schimmel mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
759a1107487SIdo Schimmel {
760a1107487SIdo Schimmel 	return container_of(fid, struct mlxsw_sp_fid_8021d, common);
761a1107487SIdo Schimmel }
762a1107487SIdo Schimmel 
mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid * fid,const void * arg)763a1107487SIdo Schimmel static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
764a1107487SIdo Schimmel {
765a1107487SIdo Schimmel 	int br_ifindex = *(int *) arg;
766a1107487SIdo Schimmel 
767a1107487SIdo Schimmel 	mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
768d4324e31SAmit Cohen 	fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
769a1107487SIdo Schimmel }
770a1107487SIdo Schimmel 
mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid * fid)771a1107487SIdo Schimmel static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
772a1107487SIdo Schimmel {
77397a2ae0fSAmit Cohen 	return mlxsw_sp_fid_op(fid, true);
774a1107487SIdo Schimmel }
775a1107487SIdo Schimmel 
mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid * fid)776a1107487SIdo Schimmel static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
777a1107487SIdo Schimmel {
778498790beSIdo Schimmel 	if (fid->vni_valid)
779498790beSIdo Schimmel 		mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
78097a2ae0fSAmit Cohen 	mlxsw_sp_fid_op(fid, false);
781a1107487SIdo Schimmel }
782a1107487SIdo Schimmel 
mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid * fid,const void * arg,u16 * p_fid_index)783a1107487SIdo Schimmel static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
784a1107487SIdo Schimmel 					  const void *arg, u16 *p_fid_index)
785a1107487SIdo Schimmel {
786a1107487SIdo Schimmel 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
787a1107487SIdo Schimmel 	u16 nr_fids, fid_index;
788a1107487SIdo Schimmel 
789a1107487SIdo Schimmel 	nr_fids = fid_family->end_index - fid_family->start_index + 1;
790a1107487SIdo Schimmel 	fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);
791a1107487SIdo Schimmel 	if (fid_index == nr_fids)
792a1107487SIdo Schimmel 		return -ENOBUFS;
793a1107487SIdo Schimmel 	*p_fid_index = fid_family->start_index + fid_index;
794a1107487SIdo Schimmel 
795a1107487SIdo Schimmel 	return 0;
796a1107487SIdo Schimmel }
797a1107487SIdo Schimmel 
798a1107487SIdo Schimmel static bool
mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid * fid,const void * arg)799a1107487SIdo Schimmel mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
800a1107487SIdo Schimmel {
801a1107487SIdo Schimmel 	int br_ifindex = *(int *) arg;
802a1107487SIdo Schimmel 
803a1107487SIdo Schimmel 	return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
804a1107487SIdo Schimmel }
805a1107487SIdo Schimmel 
mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port * mlxsw_sp_port)806a1107487SIdo Schimmel static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
807a1107487SIdo Schimmel {
808a1107487SIdo Schimmel 	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
809a1107487SIdo Schimmel 	int err;
810a1107487SIdo Schimmel 
811a1107487SIdo Schimmel 	list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
812a1107487SIdo Schimmel 			    list) {
813a1107487SIdo Schimmel 		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
814a1107487SIdo Schimmel 		u16 vid = mlxsw_sp_port_vlan->vid;
815a1107487SIdo Schimmel 
816a1107487SIdo Schimmel 		if (!fid)
817a1107487SIdo Schimmel 			continue;
818a1107487SIdo Schimmel 
8192c091048SAmit Cohen 		err = __mlxsw_sp_fid_port_vid_map(fid,
820a1107487SIdo Schimmel 						  mlxsw_sp_port->local_port,
821a1107487SIdo Schimmel 						  vid, true);
822a1107487SIdo Schimmel 		if (err)
823a1107487SIdo Schimmel 			goto err_fid_port_vid_map;
824a1107487SIdo Schimmel 	}
825a1107487SIdo Schimmel 
826a1107487SIdo Schimmel 	err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
827a1107487SIdo Schimmel 	if (err)
828a1107487SIdo Schimmel 		goto err_port_vp_mode_set;
829a1107487SIdo Schimmel 
830a1107487SIdo Schimmel 	return 0;
831a1107487SIdo Schimmel 
832a1107487SIdo Schimmel err_port_vp_mode_set:
833a1107487SIdo Schimmel err_fid_port_vid_map:
834a1107487SIdo Schimmel 	list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
835a1107487SIdo Schimmel 					     &mlxsw_sp_port->vlans_list, list) {
836a1107487SIdo Schimmel 		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
837a1107487SIdo Schimmel 		u16 vid = mlxsw_sp_port_vlan->vid;
838a1107487SIdo Schimmel 
839a1107487SIdo Schimmel 		if (!fid)
840a1107487SIdo Schimmel 			continue;
841a1107487SIdo Schimmel 
8422c091048SAmit Cohen 		__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
843a1107487SIdo Schimmel 					    false);
844a1107487SIdo Schimmel 	}
845a1107487SIdo Schimmel 	return err;
846a1107487SIdo Schimmel }
847a1107487SIdo Schimmel 
mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port * mlxsw_sp_port)848a1107487SIdo Schimmel static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
849a1107487SIdo Schimmel {
850a1107487SIdo Schimmel 	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
851a1107487SIdo Schimmel 
852a1107487SIdo Schimmel 	mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
853a1107487SIdo Schimmel 
854a1107487SIdo Schimmel 	list_for_each_entry_reverse(mlxsw_sp_port_vlan,
855a1107487SIdo Schimmel 				    &mlxsw_sp_port->vlans_list, list) {
856a1107487SIdo Schimmel 		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
857a1107487SIdo Schimmel 		u16 vid = mlxsw_sp_port_vlan->vid;
858a1107487SIdo Schimmel 
859a1107487SIdo Schimmel 		if (!fid)
860a1107487SIdo Schimmel 			continue;
861a1107487SIdo Schimmel 
8622c091048SAmit Cohen 		__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
863a1107487SIdo Schimmel 					    false);
864a1107487SIdo Schimmel 	}
865a1107487SIdo Schimmel }
866a1107487SIdo Schimmel 
867fddf42c3SAmit Cohen static int
mlxsw_sp_fid_port_vid_list_add(struct mlxsw_sp_fid * fid,u16 local_port,u16 vid)868fddf42c3SAmit Cohen mlxsw_sp_fid_port_vid_list_add(struct mlxsw_sp_fid *fid, u16 local_port,
869fddf42c3SAmit Cohen 			       u16 vid)
870fddf42c3SAmit Cohen {
871fddf42c3SAmit Cohen 	struct mlxsw_sp_fid_port_vid *port_vid, *tmp_port_vid;
872fddf42c3SAmit Cohen 
873fddf42c3SAmit Cohen 	port_vid = kzalloc(sizeof(*port_vid), GFP_KERNEL);
874fddf42c3SAmit Cohen 	if (!port_vid)
875fddf42c3SAmit Cohen 		return -ENOMEM;
876fddf42c3SAmit Cohen 
877fddf42c3SAmit Cohen 	port_vid->local_port = local_port;
878fddf42c3SAmit Cohen 	port_vid->vid = vid;
879fddf42c3SAmit Cohen 
880fddf42c3SAmit Cohen 	list_for_each_entry(tmp_port_vid, &fid->port_vid_list, list) {
881fddf42c3SAmit Cohen 		if (tmp_port_vid->local_port > local_port)
882fddf42c3SAmit Cohen 			break;
883fddf42c3SAmit Cohen 	}
884fddf42c3SAmit Cohen 
885fddf42c3SAmit Cohen 	list_add_tail(&port_vid->list, &tmp_port_vid->list);
886fddf42c3SAmit Cohen 	return 0;
887fddf42c3SAmit Cohen }
888fddf42c3SAmit Cohen 
889fddf42c3SAmit Cohen static void
mlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid * fid,u16 local_port,u16 vid)890fddf42c3SAmit Cohen mlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid *fid, u16 local_port,
891fddf42c3SAmit Cohen 			       u16 vid)
892fddf42c3SAmit Cohen {
893fddf42c3SAmit Cohen 	struct mlxsw_sp_fid_port_vid *port_vid, *tmp;
894fddf42c3SAmit Cohen 
895fddf42c3SAmit Cohen 	list_for_each_entry_safe(port_vid, tmp, &fid->port_vid_list, list) {
896fddf42c3SAmit Cohen 		if (port_vid->local_port != local_port || port_vid->vid != vid)
897fddf42c3SAmit Cohen 			continue;
898fddf42c3SAmit Cohen 
899fddf42c3SAmit Cohen 		list_del(&port_vid->list);
900fddf42c3SAmit Cohen 		kfree(port_vid);
901fddf42c3SAmit Cohen 		return;
902fddf42c3SAmit Cohen 	}
903fddf42c3SAmit Cohen }
904fddf42c3SAmit Cohen 
9058c2da081SAmit Cohen static int
mlxsw_sp_fid_mpe_table_map(const struct mlxsw_sp_fid * fid,u16 local_port,u16 vid,bool valid)9068c2da081SAmit Cohen mlxsw_sp_fid_mpe_table_map(const struct mlxsw_sp_fid *fid, u16 local_port,
9078c2da081SAmit Cohen 			   u16 vid, bool valid)
9088c2da081SAmit Cohen {
9098c2da081SAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
9108c2da081SAmit Cohen 	char smpe_pl[MLXSW_REG_SMPE_LEN];
9118c2da081SAmit Cohen 
9128c2da081SAmit Cohen 	mlxsw_reg_smpe_pack(smpe_pl, local_port, fid->fid_index,
9138c2da081SAmit Cohen 			    valid ? vid : 0);
9148c2da081SAmit Cohen 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smpe), smpe_pl);
9158c2da081SAmit Cohen }
9168c2da081SAmit Cohen 
917d4b464d2SAmit Cohen static int
mlxsw_sp_fid_erif_eport_to_vid_map_one(const struct mlxsw_sp_fid * fid,u16 local_port,u16 vid,bool valid)918d4b464d2SAmit Cohen mlxsw_sp_fid_erif_eport_to_vid_map_one(const struct mlxsw_sp_fid *fid,
919d4b464d2SAmit Cohen 				       u16 local_port, u16 vid, bool valid)
920d4b464d2SAmit Cohen {
921d4b464d2SAmit Cohen 	u8 port_page = local_port / MLXSW_REG_REIV_REC_MAX_COUNT;
922d4b464d2SAmit Cohen 	u8 rec_num = local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
923d4b464d2SAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
924d4b464d2SAmit Cohen 	u16 rif_index = mlxsw_sp_rif_index(fid->rif);
925d4b464d2SAmit Cohen 	char *reiv_pl;
926d4b464d2SAmit Cohen 	int err;
927d4b464d2SAmit Cohen 
928d4b464d2SAmit Cohen 	reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
929d4b464d2SAmit Cohen 	if (!reiv_pl)
930d4b464d2SAmit Cohen 		return -ENOMEM;
931d4b464d2SAmit Cohen 
932d4b464d2SAmit Cohen 	mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);
933d4b464d2SAmit Cohen 	mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);
934d4b464d2SAmit Cohen 	mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num, valid ? vid : 0);
935d4b464d2SAmit Cohen 	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);
936d4b464d2SAmit Cohen 	kfree(reiv_pl);
937d4b464d2SAmit Cohen 	return err;
938d4b464d2SAmit Cohen }
939d4b464d2SAmit Cohen 
mlxsw_sp_fid_evid_map(const struct mlxsw_sp_fid * fid,u16 local_port,u16 vid,bool valid)940d4b464d2SAmit Cohen static int mlxsw_sp_fid_evid_map(const struct mlxsw_sp_fid *fid, u16 local_port,
941d4b464d2SAmit Cohen 				 u16 vid, bool valid)
942d4b464d2SAmit Cohen {
943d4b464d2SAmit Cohen 	int err;
944d4b464d2SAmit Cohen 
945d4b464d2SAmit Cohen 	err = mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, valid);
946d4b464d2SAmit Cohen 	if (err)
947d4b464d2SAmit Cohen 		return err;
948d4b464d2SAmit Cohen 
949d4b464d2SAmit Cohen 	if (!fid->rif)
950d4b464d2SAmit Cohen 		return 0;
951d4b464d2SAmit Cohen 
952d4b464d2SAmit Cohen 	err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
953d4b464d2SAmit Cohen 						     valid);
954d4b464d2SAmit Cohen 	if (err)
955d4b464d2SAmit Cohen 		goto err_erif_eport_to_vid_map_one;
956d4b464d2SAmit Cohen 
957d4b464d2SAmit Cohen 	return 0;
958d4b464d2SAmit Cohen 
959d4b464d2SAmit Cohen err_erif_eport_to_vid_map_one:
960d4b464d2SAmit Cohen 	mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, !valid);
961d4b464d2SAmit Cohen 	return err;
962d4b464d2SAmit Cohen }
963d4b464d2SAmit Cohen 
mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)964a1107487SIdo Schimmel static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
965a1107487SIdo Schimmel 					   struct mlxsw_sp_port *mlxsw_sp_port,
966a1107487SIdo Schimmel 					   u16 vid)
967a1107487SIdo Schimmel {
968a1107487SIdo Schimmel 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
969c934757dSAmit Cohen 	u16 local_port = mlxsw_sp_port->local_port;
970a1107487SIdo Schimmel 	int err;
971a1107487SIdo Schimmel 
9722c091048SAmit Cohen 	err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
9732c091048SAmit Cohen 					  true);
974a1107487SIdo Schimmel 	if (err)
975a1107487SIdo Schimmel 		return err;
976a1107487SIdo Schimmel 
977d4b464d2SAmit Cohen 	err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);
9788c2da081SAmit Cohen 	if (err)
979d4b464d2SAmit Cohen 		goto err_fid_evid_map;
9808c2da081SAmit Cohen 
981fddf42c3SAmit Cohen 	err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
982fddf42c3SAmit Cohen 					     vid);
983fddf42c3SAmit Cohen 	if (err)
984fddf42c3SAmit Cohen 		goto err_port_vid_list_add;
985fddf42c3SAmit Cohen 
986a1107487SIdo Schimmel 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
987a1107487SIdo Schimmel 		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
988a1107487SIdo Schimmel 		if (err)
989a1107487SIdo Schimmel 			goto err_port_vp_mode_trans;
990a1107487SIdo Schimmel 	}
991a1107487SIdo Schimmel 
992a1107487SIdo Schimmel 	return 0;
993a1107487SIdo Schimmel 
994a1107487SIdo Schimmel err_port_vp_mode_trans:
995a1107487SIdo Schimmel 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
996fddf42c3SAmit Cohen 	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
997fddf42c3SAmit Cohen err_port_vid_list_add:
998d4b464d2SAmit Cohen 	mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
999d4b464d2SAmit Cohen err_fid_evid_map:
10002c091048SAmit Cohen 	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1001a1107487SIdo Schimmel 	return err;
1002a1107487SIdo Schimmel }
1003a1107487SIdo Schimmel 
1004a1107487SIdo Schimmel static void
mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1005a1107487SIdo Schimmel mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
1006a1107487SIdo Schimmel 				  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
1007a1107487SIdo Schimmel {
1008a1107487SIdo Schimmel 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1009c934757dSAmit Cohen 	u16 local_port = mlxsw_sp_port->local_port;
1010a1107487SIdo Schimmel 
1011a1107487SIdo Schimmel 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
1012a1107487SIdo Schimmel 		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
1013a1107487SIdo Schimmel 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
1014fddf42c3SAmit Cohen 	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1015d4b464d2SAmit Cohen 	mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
10162c091048SAmit Cohen 	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1017a1107487SIdo Schimmel }
1018a1107487SIdo Schimmel 
mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid * fid)1019d97da68eSAmit Cohen static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid)
1020d3d19d4bSIdo Schimmel {
10218cfc7f77SAmit Cohen 	return mlxsw_sp_fid_vni_op(fid);
1022d3d19d4bSIdo Schimmel }
1023d3d19d4bSIdo Schimmel 
mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid * fid)1024d3d19d4bSIdo Schimmel static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
1025d3d19d4bSIdo Schimmel {
10268cfc7f77SAmit Cohen 	mlxsw_sp_fid_vni_op(fid);
1027d3d19d4bSIdo Schimmel }
1028d3d19d4bSIdo Schimmel 
mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid * fid)1029d97da68eSAmit Cohen static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1030d3d19d4bSIdo Schimmel {
1031fea20547SAmit Cohen 	return mlxsw_sp_fid_edit_op(fid, fid->rif);
1032d3d19d4bSIdo Schimmel }
1033d3d19d4bSIdo Schimmel 
mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid * fid)1034d3d19d4bSIdo Schimmel static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1035d3d19d4bSIdo Schimmel {
1036fea20547SAmit Cohen 	mlxsw_sp_fid_edit_op(fid, fid->rif);
1037d3d19d4bSIdo Schimmel }
1038d3d19d4bSIdo Schimmel 
103983de7883SPetr Machata static void
mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid * fid,const struct net_device * nve_dev)104083de7883SPetr Machata mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
104183de7883SPetr Machata 				     const struct net_device *nve_dev)
104283de7883SPetr Machata {
104383de7883SPetr Machata 	br_fdb_clear_offload(nve_dev, 0);
104483de7883SPetr Machata }
104583de7883SPetr Machata 
1046bf73904fSAmit Cohen static int
mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)1047bf73904fSAmit Cohen mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
1048bf73904fSAmit Cohen 					 const struct mlxsw_sp_rif *rif)
1049bf73904fSAmit Cohen {
1050bf73904fSAmit Cohen 	return 0;
1051bf73904fSAmit Cohen }
1052bf73904fSAmit Cohen 
1053a1107487SIdo Schimmel static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
1054a1107487SIdo Schimmel 	.setup			= mlxsw_sp_fid_8021d_setup,
1055a1107487SIdo Schimmel 	.configure		= mlxsw_sp_fid_8021d_configure,
1056a1107487SIdo Schimmel 	.deconfigure		= mlxsw_sp_fid_8021d_deconfigure,
1057a1107487SIdo Schimmel 	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,
1058a1107487SIdo Schimmel 	.compare		= mlxsw_sp_fid_8021d_compare,
1059a1107487SIdo Schimmel 	.port_vid_map		= mlxsw_sp_fid_8021d_port_vid_map,
1060a1107487SIdo Schimmel 	.port_vid_unmap		= mlxsw_sp_fid_8021d_port_vid_unmap,
1061d3d19d4bSIdo Schimmel 	.vni_set		= mlxsw_sp_fid_8021d_vni_set,
1062d3d19d4bSIdo Schimmel 	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,
1063d3d19d4bSIdo Schimmel 	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,
1064d3d19d4bSIdo Schimmel 	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,
106583de7883SPetr Machata 	.fdb_clear_offload	= mlxsw_sp_fid_8021d_fdb_clear_offload,
1066bf73904fSAmit Cohen 	.vid_to_fid_rif_update  = mlxsw_sp_fid_8021d_vid_to_fid_rif_update,
1067a1107487SIdo Schimmel };
1068a1107487SIdo Schimmel 
10699f6f467aSAmit Cohen #define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2)
107088840d69SAmit Cohen #define MLXSW_SP_FID_RFID_MAX (11 * 1024)
10719f6f467aSAmit Cohen #define MLXSW_SP_FID_8021Q_PGT_BASE 0
10729f6f467aSAmit Cohen #define MLXSW_SP_FID_8021D_PGT_BASE (3 * MLXSW_SP_FID_8021Q_MAX)
10739f6f467aSAmit Cohen 
107488840d69SAmit Cohen static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
1075d4324e31SAmit Cohen 	{
1076d4324e31SAmit Cohen 		.packet_type	= MLXSW_SP_FLOOD_TYPE_UC,
1077d4324e31SAmit Cohen 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
1078d4324e31SAmit Cohen 		.table_index	= 0,
1079d4324e31SAmit Cohen 	},
1080d4324e31SAmit Cohen 	{
1081d4324e31SAmit Cohen 		.packet_type	= MLXSW_SP_FLOOD_TYPE_MC,
1082d4324e31SAmit Cohen 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
1083d4324e31SAmit Cohen 		.table_index	= 1,
1084d4324e31SAmit Cohen 	},
1085d4324e31SAmit Cohen 	{
1086d4324e31SAmit Cohen 		.packet_type	= MLXSW_SP_FLOOD_TYPE_BC,
1087d4324e31SAmit Cohen 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
1088d4324e31SAmit Cohen 		.table_index	= 2,
1089d4324e31SAmit Cohen 	},
1090d4324e31SAmit Cohen };
1091d4324e31SAmit Cohen 
1092bdb373cfSIdo Schimmel static bool
mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid * fid,const void * arg)1093bdb373cfSIdo Schimmel mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
1094bdb373cfSIdo Schimmel {
1095bdb373cfSIdo Schimmel 	u16 vid = *(u16 *) arg;
1096bdb373cfSIdo Schimmel 
1097bdb373cfSIdo Schimmel 	return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
1098bdb373cfSIdo Schimmel }
1099bdb373cfSIdo Schimmel 
110083de7883SPetr Machata static void
mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid * fid,const struct net_device * nve_dev)110183de7883SPetr Machata mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
110283de7883SPetr Machata 				     const struct net_device *nve_dev)
110383de7883SPetr Machata {
110483de7883SPetr Machata 	br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid));
110583de7883SPetr Machata }
110683de7883SPetr Machata 
mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid * fid,const void * arg)1107736bf371SAmit Cohen static void mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid *fid, const void *arg)
1108736bf371SAmit Cohen {
1109736bf371SAmit Cohen 	fid->fid_offset = 0;
1110736bf371SAmit Cohen }
1111736bf371SAmit Cohen 
mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid * fid)1112a1107487SIdo Schimmel static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
1113a1107487SIdo Schimmel {
1114d4324e31SAmit Cohen 	return mlxsw_sp_fid_op(fid, true);
1115a1107487SIdo Schimmel }
1116a1107487SIdo Schimmel 
mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid * fid)1117a1107487SIdo Schimmel static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
1118a1107487SIdo Schimmel {
1119d4324e31SAmit Cohen 	mlxsw_sp_fid_op(fid, false);
1120a1107487SIdo Schimmel }
1121a1107487SIdo Schimmel 
mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid * fid,const void * arg,u16 * p_fid_index)1122a1107487SIdo Schimmel static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
1123a1107487SIdo Schimmel 					 const void *arg, u16 *p_fid_index)
1124a1107487SIdo Schimmel {
1125a1107487SIdo Schimmel 	u16 rif_index = *(u16 *) arg;
1126a1107487SIdo Schimmel 
1127a1107487SIdo Schimmel 	*p_fid_index = fid->fid_family->start_index + rif_index;
1128a1107487SIdo Schimmel 
1129a1107487SIdo Schimmel 	return 0;
1130a1107487SIdo Schimmel }
1131a1107487SIdo Schimmel 
mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid * fid,const void * arg)1132a1107487SIdo Schimmel static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
1133a1107487SIdo Schimmel 				      const void *arg)
1134a1107487SIdo Schimmel {
1135a1107487SIdo Schimmel 	u16 rif_index = *(u16 *) arg;
1136a1107487SIdo Schimmel 
1137a1107487SIdo Schimmel 	return fid->fid_index == rif_index + fid->fid_family->start_index;
1138a1107487SIdo Schimmel }
1139a1107487SIdo Schimmel 
mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1140a1107487SIdo Schimmel static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
1141a1107487SIdo Schimmel 					  struct mlxsw_sp_port *mlxsw_sp_port,
1142a1107487SIdo Schimmel 					  u16 vid)
1143a1107487SIdo Schimmel {
1144a1107487SIdo Schimmel 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1145c934757dSAmit Cohen 	u16 local_port = mlxsw_sp_port->local_port;
1146a1107487SIdo Schimmel 	int err;
1147a1107487SIdo Schimmel 
1148fddf42c3SAmit Cohen 	err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
1149fddf42c3SAmit Cohen 					     vid);
1150fddf42c3SAmit Cohen 	if (err)
1151fddf42c3SAmit Cohen 		return err;
1152fddf42c3SAmit Cohen 
1153d4324e31SAmit Cohen 	/* Using legacy bridge model, we only need to transition the port to
1154d4324e31SAmit Cohen 	 * virtual mode since {Port, VID} => FID is done by the firmware upon
1155d4324e31SAmit Cohen 	 * RIF creation. Using unified bridge model, we need to map
1156d4324e31SAmit Cohen 	 * {Port, VID} => FID and map egress VID.
1157a1107487SIdo Schimmel 	 */
115877b7f83dSAmit Cohen 	err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
115977b7f83dSAmit Cohen 					  true);
1160d4324e31SAmit Cohen 	if (err)
1161d4324e31SAmit Cohen 		goto err_port_vid_map;
1162d4324e31SAmit Cohen 
1163d4324e31SAmit Cohen 	if (fid->rif) {
116477b7f83dSAmit Cohen 		err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port,
1165d4324e31SAmit Cohen 							     vid, true);
1166d4324e31SAmit Cohen 		if (err)
1167d4324e31SAmit Cohen 			goto err_erif_eport_to_vid_map_one;
1168d4324e31SAmit Cohen 	}
1169d4324e31SAmit Cohen 
1170a1107487SIdo Schimmel 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
1171a1107487SIdo Schimmel 		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
1172a1107487SIdo Schimmel 		if (err)
1173a1107487SIdo Schimmel 			goto err_port_vp_mode_trans;
1174a1107487SIdo Schimmel 	}
1175a1107487SIdo Schimmel 
1176a1107487SIdo Schimmel 	return 0;
1177a1107487SIdo Schimmel 
1178a1107487SIdo Schimmel err_port_vp_mode_trans:
1179a1107487SIdo Schimmel 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
118077b7f83dSAmit Cohen 	if (fid->rif)
1181d4324e31SAmit Cohen 		mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
1182d4324e31SAmit Cohen 						       false);
1183d4324e31SAmit Cohen err_erif_eport_to_vid_map_one:
118477b7f83dSAmit Cohen 	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1185d4324e31SAmit Cohen err_port_vid_map:
1186fddf42c3SAmit Cohen 	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1187a1107487SIdo Schimmel 	return err;
1188a1107487SIdo Schimmel }
1189a1107487SIdo Schimmel 
1190a1107487SIdo Schimmel static void
mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1191a1107487SIdo Schimmel mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
1192a1107487SIdo Schimmel 				 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
1193a1107487SIdo Schimmel {
1194a1107487SIdo Schimmel 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1195c934757dSAmit Cohen 	u16 local_port = mlxsw_sp_port->local_port;
1196a1107487SIdo Schimmel 
1197a1107487SIdo Schimmel 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
1198a1107487SIdo Schimmel 		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
1199a1107487SIdo Schimmel 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
1200d4324e31SAmit Cohen 
1201d4324e31SAmit Cohen 	if (fid->rif)
120277b7f83dSAmit Cohen 		mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
1203d4324e31SAmit Cohen 						       false);
120477b7f83dSAmit Cohen 	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1205fddf42c3SAmit Cohen 	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1206a1107487SIdo Schimmel }
1207a1107487SIdo Schimmel 
mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid * fid)1208d97da68eSAmit Cohen static int mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid *fid)
1209048fcbb7SAmit Cohen {
1210048fcbb7SAmit Cohen 	return -EOPNOTSUPP;
1211048fcbb7SAmit Cohen }
1212048fcbb7SAmit Cohen 
mlxsw_sp_fid_rfid_vni_clear(struct mlxsw_sp_fid * fid)1213048fcbb7SAmit Cohen static void mlxsw_sp_fid_rfid_vni_clear(struct mlxsw_sp_fid *fid)
1214048fcbb7SAmit Cohen {
1215048fcbb7SAmit Cohen 	WARN_ON_ONCE(1);
1216048fcbb7SAmit Cohen }
1217048fcbb7SAmit Cohen 
mlxsw_sp_fid_rfid_nve_flood_index_set(struct mlxsw_sp_fid * fid)1218d97da68eSAmit Cohen static int mlxsw_sp_fid_rfid_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1219048fcbb7SAmit Cohen {
1220048fcbb7SAmit Cohen 	return -EOPNOTSUPP;
1221048fcbb7SAmit Cohen }
1222048fcbb7SAmit Cohen 
mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid * fid)1223048fcbb7SAmit Cohen static void mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1224048fcbb7SAmit Cohen {
1225048fcbb7SAmit Cohen 	WARN_ON_ONCE(1);
1226048fcbb7SAmit Cohen }
1227048fcbb7SAmit Cohen 
1228bf73904fSAmit Cohen static int
mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)1229bf73904fSAmit Cohen mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
1230bf73904fSAmit Cohen 					const struct mlxsw_sp_rif *rif)
1231bf73904fSAmit Cohen {
1232bf73904fSAmit Cohen 	return 0;
1233bf73904fSAmit Cohen }
1234bf73904fSAmit Cohen 
1235a1107487SIdo Schimmel static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
1236736bf371SAmit Cohen 	.setup			= mlxsw_sp_fid_rfid_setup,
1237a1107487SIdo Schimmel 	.configure		= mlxsw_sp_fid_rfid_configure,
1238a1107487SIdo Schimmel 	.deconfigure		= mlxsw_sp_fid_rfid_deconfigure,
1239a1107487SIdo Schimmel 	.index_alloc		= mlxsw_sp_fid_rfid_index_alloc,
1240a1107487SIdo Schimmel 	.compare		= mlxsw_sp_fid_rfid_compare,
1241a1107487SIdo Schimmel 	.port_vid_map		= mlxsw_sp_fid_rfid_port_vid_map,
1242a1107487SIdo Schimmel 	.port_vid_unmap		= mlxsw_sp_fid_rfid_port_vid_unmap,
1243048fcbb7SAmit Cohen 	.vni_set                = mlxsw_sp_fid_rfid_vni_set,
1244048fcbb7SAmit Cohen 	.vni_clear		= mlxsw_sp_fid_rfid_vni_clear,
1245048fcbb7SAmit Cohen 	.nve_flood_index_set	= mlxsw_sp_fid_rfid_nve_flood_index_set,
1246048fcbb7SAmit Cohen 	.nve_flood_index_clear	= mlxsw_sp_fid_rfid_nve_flood_index_clear,
1247bf73904fSAmit Cohen 	.vid_to_fid_rif_update  = mlxsw_sp_fid_rfid_vid_to_fid_rif_update,
1248a1107487SIdo Schimmel };
1249a1107487SIdo Schimmel 
mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid * fid,const void * arg)1250736bf371SAmit Cohen static void mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg)
1251736bf371SAmit Cohen {
1252736bf371SAmit Cohen 	fid->fid_offset = 0;
1253736bf371SAmit Cohen }
1254736bf371SAmit Cohen 
mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid * fid)1255a1107487SIdo Schimmel static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
1256a1107487SIdo Schimmel {
125797a2ae0fSAmit Cohen 	return mlxsw_sp_fid_op(fid, true);
1258a1107487SIdo Schimmel }
1259a1107487SIdo Schimmel 
mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid * fid)1260a1107487SIdo Schimmel static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
1261a1107487SIdo Schimmel {
126297a2ae0fSAmit Cohen 	mlxsw_sp_fid_op(fid, false);
1263a1107487SIdo Schimmel }
1264a1107487SIdo Schimmel 
mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid * fid,const void * arg,u16 * p_fid_index)1265a1107487SIdo Schimmel static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
1266a1107487SIdo Schimmel 					  const void *arg, u16 *p_fid_index)
1267a1107487SIdo Schimmel {
1268a1107487SIdo Schimmel 	*p_fid_index = fid->fid_family->start_index;
1269a1107487SIdo Schimmel 
1270a1107487SIdo Schimmel 	return 0;
1271a1107487SIdo Schimmel }
1272a1107487SIdo Schimmel 
mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid * fid,const void * arg)1273a1107487SIdo Schimmel static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
1274a1107487SIdo Schimmel 				       const void *arg)
1275a1107487SIdo Schimmel {
1276a1107487SIdo Schimmel 	return true;
1277a1107487SIdo Schimmel }
1278a1107487SIdo Schimmel 
mlxsw_sp_fid_dummy_vni_set(struct mlxsw_sp_fid * fid)1279d97da68eSAmit Cohen static int mlxsw_sp_fid_dummy_vni_set(struct mlxsw_sp_fid *fid)
1280048fcbb7SAmit Cohen {
1281048fcbb7SAmit Cohen 	return -EOPNOTSUPP;
1282048fcbb7SAmit Cohen }
1283048fcbb7SAmit Cohen 
mlxsw_sp_fid_dummy_vni_clear(struct mlxsw_sp_fid * fid)1284048fcbb7SAmit Cohen static void mlxsw_sp_fid_dummy_vni_clear(struct mlxsw_sp_fid *fid)
1285048fcbb7SAmit Cohen {
1286048fcbb7SAmit Cohen 	WARN_ON_ONCE(1);
1287048fcbb7SAmit Cohen }
1288048fcbb7SAmit Cohen 
mlxsw_sp_fid_dummy_nve_flood_index_set(struct mlxsw_sp_fid * fid)1289d97da68eSAmit Cohen static int mlxsw_sp_fid_dummy_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1290048fcbb7SAmit Cohen {
1291048fcbb7SAmit Cohen 	return -EOPNOTSUPP;
1292048fcbb7SAmit Cohen }
1293048fcbb7SAmit Cohen 
mlxsw_sp_fid_dummy_nve_flood_index_clear(struct mlxsw_sp_fid * fid)1294048fcbb7SAmit Cohen static void mlxsw_sp_fid_dummy_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1295048fcbb7SAmit Cohen {
1296048fcbb7SAmit Cohen 	WARN_ON_ONCE(1);
1297048fcbb7SAmit Cohen }
1298048fcbb7SAmit Cohen 
1299a1107487SIdo Schimmel static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
1300736bf371SAmit Cohen 	.setup			= mlxsw_sp_fid_dummy_setup,
1301a1107487SIdo Schimmel 	.configure		= mlxsw_sp_fid_dummy_configure,
1302a1107487SIdo Schimmel 	.deconfigure		= mlxsw_sp_fid_dummy_deconfigure,
1303a1107487SIdo Schimmel 	.index_alloc		= mlxsw_sp_fid_dummy_index_alloc,
1304a1107487SIdo Schimmel 	.compare		= mlxsw_sp_fid_dummy_compare,
1305048fcbb7SAmit Cohen 	.vni_set                = mlxsw_sp_fid_dummy_vni_set,
1306048fcbb7SAmit Cohen 	.vni_clear		= mlxsw_sp_fid_dummy_vni_clear,
1307048fcbb7SAmit Cohen 	.nve_flood_index_set	= mlxsw_sp_fid_dummy_nve_flood_index_set,
1308048fcbb7SAmit Cohen 	.nve_flood_index_clear	= mlxsw_sp_fid_dummy_nve_flood_index_clear,
1309a1107487SIdo Schimmel };
1310a1107487SIdo Schimmel 
mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid * fid)1311bf73904fSAmit Cohen static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
1312bf73904fSAmit Cohen {
1313bf73904fSAmit Cohen 	struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
1314bf73904fSAmit Cohen 	int err;
1315bf73904fSAmit Cohen 
1316bf73904fSAmit Cohen 	err = mlxsw_sp_fid_op(fid, true);
1317bf73904fSAmit Cohen 	if (err)
1318bf73904fSAmit Cohen 		return err;
1319bf73904fSAmit Cohen 
1320bf73904fSAmit Cohen 	err = mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, fid->rif);
1321bf73904fSAmit Cohen 	if (err)
1322bf73904fSAmit Cohen 		goto err_vid_to_fid_map;
1323bf73904fSAmit Cohen 
1324bf73904fSAmit Cohen 	return 0;
1325bf73904fSAmit Cohen 
1326bf73904fSAmit Cohen err_vid_to_fid_map:
1327bf73904fSAmit Cohen 	mlxsw_sp_fid_op(fid, false);
1328bf73904fSAmit Cohen 	return err;
1329bf73904fSAmit Cohen }
1330bf73904fSAmit Cohen 
mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid * fid)1331bf73904fSAmit Cohen static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)
1332bf73904fSAmit Cohen {
1333bf73904fSAmit Cohen 	struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
1334bf73904fSAmit Cohen 
1335bf73904fSAmit Cohen 	if (fid->vni_valid)
1336bf73904fSAmit Cohen 		mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
1337bf73904fSAmit Cohen 
1338bf73904fSAmit Cohen 	mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, false, NULL);
1339bf73904fSAmit Cohen 	mlxsw_sp_fid_op(fid, false);
1340bf73904fSAmit Cohen }
1341bf73904fSAmit Cohen 
mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1342bf73904fSAmit Cohen static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,
1343bf73904fSAmit Cohen 					   struct mlxsw_sp_port *mlxsw_sp_port,
1344bf73904fSAmit Cohen 					   u16 vid)
1345bf73904fSAmit Cohen {
1346bf73904fSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1347*bb765a74SIdo Schimmel 	u16 local_port = mlxsw_sp_port->local_port;
1348bf73904fSAmit Cohen 	int err;
1349bf73904fSAmit Cohen 
1350bf73904fSAmit Cohen 	/* In case there are no {Port, VID} => FID mappings on the port,
1351bf73904fSAmit Cohen 	 * we can use the global VID => FID mapping we created when the
1352bf73904fSAmit Cohen 	 * FID was configured, otherwise, configure new mapping.
1353bf73904fSAmit Cohen 	 */
1354bf73904fSAmit Cohen 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]) {
1355bf73904fSAmit Cohen 		err =  __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, true);
1356bf73904fSAmit Cohen 		if (err)
1357bf73904fSAmit Cohen 			return err;
1358bf73904fSAmit Cohen 	}
1359bf73904fSAmit Cohen 
1360bf73904fSAmit Cohen 	err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);
1361bf73904fSAmit Cohen 	if (err)
1362bf73904fSAmit Cohen 		goto err_fid_evid_map;
1363bf73904fSAmit Cohen 
1364bf73904fSAmit Cohen 	err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
1365bf73904fSAmit Cohen 					     vid);
1366bf73904fSAmit Cohen 	if (err)
1367bf73904fSAmit Cohen 		goto err_port_vid_list_add;
1368bf73904fSAmit Cohen 
1369bf73904fSAmit Cohen 	return 0;
1370bf73904fSAmit Cohen 
1371bf73904fSAmit Cohen err_port_vid_list_add:
1372bf73904fSAmit Cohen 	 mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
1373bf73904fSAmit Cohen err_fid_evid_map:
1374bf73904fSAmit Cohen 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
1375bf73904fSAmit Cohen 		__mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
1376bf73904fSAmit Cohen 	return err;
1377bf73904fSAmit Cohen }
1378bf73904fSAmit Cohen 
1379bf73904fSAmit Cohen static void
mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1380bf73904fSAmit Cohen mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
1381bf73904fSAmit Cohen 				  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
1382bf73904fSAmit Cohen {
1383bf73904fSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1384*bb765a74SIdo Schimmel 	u16 local_port = mlxsw_sp_port->local_port;
1385bf73904fSAmit Cohen 
1386bf73904fSAmit Cohen 	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1387bf73904fSAmit Cohen 	mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
1388bf73904fSAmit Cohen 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
1389bf73904fSAmit Cohen 		__mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
1390bf73904fSAmit Cohen }
1391bf73904fSAmit Cohen 
1392bf73904fSAmit Cohen static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
1393bf73904fSAmit Cohen 	.setup			= mlxsw_sp_fid_8021q_setup,
1394bf73904fSAmit Cohen 	.configure		= mlxsw_sp_fid_8021q_configure,
1395bf73904fSAmit Cohen 	.deconfigure		= mlxsw_sp_fid_8021q_deconfigure,
1396bf73904fSAmit Cohen 	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,
1397bf73904fSAmit Cohen 	.compare		= mlxsw_sp_fid_8021q_compare,
1398bf73904fSAmit Cohen 	.port_vid_map		= mlxsw_sp_fid_8021q_port_vid_map,
1399bf73904fSAmit Cohen 	.port_vid_unmap		= mlxsw_sp_fid_8021q_port_vid_unmap,
1400bf73904fSAmit Cohen 	.vni_set		= mlxsw_sp_fid_8021d_vni_set,
1401bf73904fSAmit Cohen 	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,
1402bf73904fSAmit Cohen 	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,
1403bf73904fSAmit Cohen 	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,
1404bf73904fSAmit Cohen 	.fdb_clear_offload	= mlxsw_sp_fid_8021q_fdb_clear_offload,
1405bf73904fSAmit Cohen 	.vid_to_fid_rif_update  = mlxsw_sp_fid_8021q_vid_to_fid_rif_update,
1406bf73904fSAmit Cohen };
1407bf73904fSAmit Cohen 
1408d4324e31SAmit Cohen /* There are 4K-2 802.1Q FIDs */
140988840d69SAmit Cohen #define MLXSW_SP_FID_8021Q_START	1 /* FID 0 is reserved. */
141088840d69SAmit Cohen #define MLXSW_SP_FID_8021Q_END		(MLXSW_SP_FID_8021Q_START + \
1411d4324e31SAmit Cohen 					 MLXSW_SP_FID_8021Q_MAX - 1)
1412d4324e31SAmit Cohen 
1413d4324e31SAmit Cohen /* There are 1K 802.1D FIDs */
141488840d69SAmit Cohen #define MLXSW_SP_FID_8021D_START	(MLXSW_SP_FID_8021Q_END + 1)
141588840d69SAmit Cohen #define MLXSW_SP_FID_8021D_END		(MLXSW_SP_FID_8021D_START + \
1416d4324e31SAmit Cohen 					 MLXSW_SP_FID_8021D_MAX - 1)
1417d4324e31SAmit Cohen 
1418d4324e31SAmit Cohen /* There is one dummy FID */
141988840d69SAmit Cohen #define MLXSW_SP_FID_DUMMY		(MLXSW_SP_FID_8021D_END + 1)
1420d4324e31SAmit Cohen 
1421d4324e31SAmit Cohen /* There are 11K rFIDs */
142288840d69SAmit Cohen #define MLXSW_SP_RFID_START		(MLXSW_SP_FID_DUMMY + 1)
142388840d69SAmit Cohen #define MLXSW_SP_RFID_END		(MLXSW_SP_RFID_START + \
142488840d69SAmit Cohen 					 MLXSW_SP_FID_RFID_MAX - 1)
1425d4324e31SAmit Cohen 
142688840d69SAmit Cohen static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_family = {
142777b7f83dSAmit Cohen 	.type			= MLXSW_SP_FID_TYPE_8021Q,
1428bf73904fSAmit Cohen 	.fid_size		= sizeof(struct mlxsw_sp_fid_8021q),
142988840d69SAmit Cohen 	.start_index		= MLXSW_SP_FID_8021Q_START,
143088840d69SAmit Cohen 	.end_index		= MLXSW_SP_FID_8021Q_END,
143188840d69SAmit Cohen 	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
143288840d69SAmit Cohen 	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1433bf73904fSAmit Cohen 	.rif_type		= MLXSW_SP_RIF_TYPE_VLAN,
1434bf73904fSAmit Cohen 	.ops			= &mlxsw_sp_fid_8021q_ops,
1435bf73904fSAmit Cohen 	.flood_rsp              = false,
1436bf73904fSAmit Cohen 	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_0,
1437bf73904fSAmit Cohen 	.pgt_base		= MLXSW_SP_FID_8021Q_PGT_BASE,
1438bf73904fSAmit Cohen 	.smpe_index_valid	= false,
1439bf73904fSAmit Cohen };
1440bf73904fSAmit Cohen 
144188840d69SAmit Cohen static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_family = {
144277b7f83dSAmit Cohen 	.type			= MLXSW_SP_FID_TYPE_8021D,
1443d4324e31SAmit Cohen 	.fid_size		= sizeof(struct mlxsw_sp_fid_8021d),
144488840d69SAmit Cohen 	.start_index		= MLXSW_SP_FID_8021D_START,
144588840d69SAmit Cohen 	.end_index		= MLXSW_SP_FID_8021D_END,
144688840d69SAmit Cohen 	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
144788840d69SAmit Cohen 	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1448d4324e31SAmit Cohen 	.rif_type		= MLXSW_SP_RIF_TYPE_FID,
1449d4324e31SAmit Cohen 	.ops			= &mlxsw_sp_fid_8021d_ops,
1450d4324e31SAmit Cohen 	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_1,
1451d4324e31SAmit Cohen 	.pgt_base		= MLXSW_SP_FID_8021D_PGT_BASE,
1452d4324e31SAmit Cohen 	.smpe_index_valid       = false,
1453d4324e31SAmit Cohen };
1454d4324e31SAmit Cohen 
145588840d69SAmit Cohen static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_dummy_family = {
145677b7f83dSAmit Cohen 	.type			= MLXSW_SP_FID_TYPE_DUMMY,
1457d4324e31SAmit Cohen 	.fid_size		= sizeof(struct mlxsw_sp_fid),
145888840d69SAmit Cohen 	.start_index		= MLXSW_SP_FID_DUMMY,
145988840d69SAmit Cohen 	.end_index		= MLXSW_SP_FID_DUMMY,
1460d4324e31SAmit Cohen 	.ops			= &mlxsw_sp_fid_dummy_ops,
1461d4324e31SAmit Cohen 	.smpe_index_valid       = false,
1462d4324e31SAmit Cohen };
1463d4324e31SAmit Cohen 
146488840d69SAmit Cohen static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
146577b7f83dSAmit Cohen 	.type			= MLXSW_SP_FID_TYPE_RFID,
1466d4324e31SAmit Cohen 	.fid_size		= sizeof(struct mlxsw_sp_fid),
146788840d69SAmit Cohen 	.start_index		= MLXSW_SP_RFID_START,
146888840d69SAmit Cohen 	.end_index		= MLXSW_SP_RFID_END,
1469d4324e31SAmit Cohen 	.rif_type		= MLXSW_SP_RIF_TYPE_SUBPORT,
1470d4324e31SAmit Cohen 	.ops			= &mlxsw_sp_fid_rfid_ops,
1471d4324e31SAmit Cohen 	.flood_rsp              = true,
1472d4324e31SAmit Cohen 	.smpe_index_valid       = false,
1473d4324e31SAmit Cohen };
1474d4324e31SAmit Cohen 
147504e85970SAmit Cohen const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = {
147688840d69SAmit Cohen 	[MLXSW_SP_FID_TYPE_8021Q]	= &mlxsw_sp1_fid_8021q_family,
147788840d69SAmit Cohen 	[MLXSW_SP_FID_TYPE_8021D]	= &mlxsw_sp1_fid_8021d_family,
147888840d69SAmit Cohen 	[MLXSW_SP_FID_TYPE_DUMMY]	= &mlxsw_sp1_fid_dummy_family,
147988840d69SAmit Cohen 	[MLXSW_SP_FID_TYPE_RFID]	= &mlxsw_sp_fid_rfid_family,
1480d4324e31SAmit Cohen };
1481d4324e31SAmit Cohen 
148288840d69SAmit Cohen static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family = {
148377b7f83dSAmit Cohen 	.type			= MLXSW_SP_FID_TYPE_8021Q,
1484bf73904fSAmit Cohen 	.fid_size		= sizeof(struct mlxsw_sp_fid_8021q),
148588840d69SAmit Cohen 	.start_index		= MLXSW_SP_FID_8021Q_START,
148688840d69SAmit Cohen 	.end_index		= MLXSW_SP_FID_8021Q_END,
148788840d69SAmit Cohen 	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
148888840d69SAmit Cohen 	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1489bf73904fSAmit Cohen 	.rif_type		= MLXSW_SP_RIF_TYPE_VLAN,
1490bf73904fSAmit Cohen 	.ops			= &mlxsw_sp_fid_8021q_ops,
1491bf73904fSAmit Cohen 	.flood_rsp              = false,
1492bf73904fSAmit Cohen 	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_0,
1493bf73904fSAmit Cohen 	.pgt_base		= MLXSW_SP_FID_8021Q_PGT_BASE,
1494bf73904fSAmit Cohen 	.smpe_index_valid	= true,
1495bf73904fSAmit Cohen };
1496bf73904fSAmit Cohen 
149788840d69SAmit Cohen static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family = {
149877b7f83dSAmit Cohen 	.type			= MLXSW_SP_FID_TYPE_8021D,
1499d4324e31SAmit Cohen 	.fid_size		= sizeof(struct mlxsw_sp_fid_8021d),
150088840d69SAmit Cohen 	.start_index		= MLXSW_SP_FID_8021D_START,
150188840d69SAmit Cohen 	.end_index		= MLXSW_SP_FID_8021D_END,
150288840d69SAmit Cohen 	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
150388840d69SAmit Cohen 	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1504d4324e31SAmit Cohen 	.rif_type		= MLXSW_SP_RIF_TYPE_FID,
1505d4324e31SAmit Cohen 	.ops			= &mlxsw_sp_fid_8021d_ops,
1506d4324e31SAmit Cohen 	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_1,
1507d4324e31SAmit Cohen 	.pgt_base		= MLXSW_SP_FID_8021D_PGT_BASE,
1508d4324e31SAmit Cohen 	.smpe_index_valid       = true,
1509d4324e31SAmit Cohen };
1510d4324e31SAmit Cohen 
151188840d69SAmit Cohen static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_dummy_family = {
151277b7f83dSAmit Cohen 	.type			= MLXSW_SP_FID_TYPE_DUMMY,
1513d4324e31SAmit Cohen 	.fid_size		= sizeof(struct mlxsw_sp_fid),
151488840d69SAmit Cohen 	.start_index		= MLXSW_SP_FID_DUMMY,
151588840d69SAmit Cohen 	.end_index		= MLXSW_SP_FID_DUMMY,
1516d4324e31SAmit Cohen 	.ops			= &mlxsw_sp_fid_dummy_ops,
1517d4324e31SAmit Cohen 	.smpe_index_valid       = false,
151804e85970SAmit Cohen };
151904e85970SAmit Cohen 
152004e85970SAmit Cohen const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[] = {
152188840d69SAmit Cohen 	[MLXSW_SP_FID_TYPE_8021Q]	= &mlxsw_sp2_fid_8021q_family,
152288840d69SAmit Cohen 	[MLXSW_SP_FID_TYPE_8021D]	= &mlxsw_sp2_fid_8021d_family,
152388840d69SAmit Cohen 	[MLXSW_SP_FID_TYPE_DUMMY]	= &mlxsw_sp2_fid_dummy_family,
152488840d69SAmit Cohen 	[MLXSW_SP_FID_TYPE_RFID]	= &mlxsw_sp_fid_rfid_family,
1525a1107487SIdo Schimmel };
1526a1107487SIdo Schimmel 
mlxsw_sp_fid_lookup(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_fid_type type,const void * arg)1527564c6d72SIdo Schimmel static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,
1528a1107487SIdo Schimmel 						enum mlxsw_sp_fid_type type,
1529a1107487SIdo Schimmel 						const void *arg)
1530a1107487SIdo Schimmel {
1531a1107487SIdo Schimmel 	struct mlxsw_sp_fid_family *fid_family;
1532a1107487SIdo Schimmel 	struct mlxsw_sp_fid *fid;
1533a1107487SIdo Schimmel 
1534a1107487SIdo Schimmel 	fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
1535a1107487SIdo Schimmel 	list_for_each_entry(fid, &fid_family->fids_list, list) {
1536a1107487SIdo Schimmel 		if (!fid->fid_family->ops->compare(fid, arg))
1537a1107487SIdo Schimmel 			continue;
1538b96f5469SIdo Schimmel 		refcount_inc(&fid->ref_count);
1539a1107487SIdo Schimmel 		return fid;
1540a1107487SIdo Schimmel 	}
1541a1107487SIdo Schimmel 
1542564c6d72SIdo Schimmel 	return NULL;
1543564c6d72SIdo Schimmel }
1544564c6d72SIdo Schimmel 
mlxsw_sp_fid_get(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_fid_type type,const void * arg)1545564c6d72SIdo Schimmel static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
1546564c6d72SIdo Schimmel 					     enum mlxsw_sp_fid_type type,
1547564c6d72SIdo Schimmel 					     const void *arg)
1548564c6d72SIdo Schimmel {
1549564c6d72SIdo Schimmel 	struct mlxsw_sp_fid_family *fid_family;
1550564c6d72SIdo Schimmel 	struct mlxsw_sp_fid *fid;
1551564c6d72SIdo Schimmel 	u16 fid_index;
1552564c6d72SIdo Schimmel 	int err;
1553564c6d72SIdo Schimmel 
1554564c6d72SIdo Schimmel 	fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg);
1555564c6d72SIdo Schimmel 	if (fid)
1556564c6d72SIdo Schimmel 		return fid;
1557564c6d72SIdo Schimmel 
1558564c6d72SIdo Schimmel 	fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
1559a1107487SIdo Schimmel 	fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
1560a1107487SIdo Schimmel 	if (!fid)
1561a1107487SIdo Schimmel 		return ERR_PTR(-ENOMEM);
1562fddf42c3SAmit Cohen 
1563fddf42c3SAmit Cohen 	INIT_LIST_HEAD(&fid->port_vid_list);
1564a1107487SIdo Schimmel 	fid->fid_family = fid_family;
1565a1107487SIdo Schimmel 
1566a1107487SIdo Schimmel 	err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
1567a1107487SIdo Schimmel 	if (err)
1568a1107487SIdo Schimmel 		goto err_index_alloc;
1569a1107487SIdo Schimmel 	fid->fid_index = fid_index;
1570a1107487SIdo Schimmel 	__set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
1571a1107487SIdo Schimmel 
1572a1107487SIdo Schimmel 	fid->fid_family->ops->setup(fid, arg);
1573a1107487SIdo Schimmel 
1574a1107487SIdo Schimmel 	err = fid->fid_family->ops->configure(fid);
1575a1107487SIdo Schimmel 	if (err)
1576a1107487SIdo Schimmel 		goto err_configure;
1577a1107487SIdo Schimmel 
15785d44a712SIdo Schimmel 	err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node,
15795d44a712SIdo Schimmel 				     mlxsw_sp_fid_ht_params);
15805d44a712SIdo Schimmel 	if (err)
15815d44a712SIdo Schimmel 		goto err_rhashtable_insert;
15825d44a712SIdo Schimmel 
1583a1107487SIdo Schimmel 	list_add(&fid->list, &fid_family->fids_list);
1584b96f5469SIdo Schimmel 	refcount_set(&fid->ref_count, 1);
1585a1107487SIdo Schimmel 	return fid;
1586a1107487SIdo Schimmel 
15875d44a712SIdo Schimmel err_rhashtable_insert:
15885d44a712SIdo Schimmel 	fid->fid_family->ops->deconfigure(fid);
1589a1107487SIdo Schimmel err_configure:
1590a1107487SIdo Schimmel 	__clear_bit(fid_index - fid_family->start_index,
1591a1107487SIdo Schimmel 		    fid_family->fids_bitmap);
1592a1107487SIdo Schimmel err_index_alloc:
1593a1107487SIdo Schimmel 	kfree(fid);
1594a1107487SIdo Schimmel 	return ERR_PTR(err);
1595a1107487SIdo Schimmel }
1596a1107487SIdo Schimmel 
mlxsw_sp_fid_put(struct mlxsw_sp_fid * fid)1597a1107487SIdo Schimmel void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
1598a1107487SIdo Schimmel {
1599a1107487SIdo Schimmel 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
16005d44a712SIdo Schimmel 	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1601a1107487SIdo Schimmel 
1602b96f5469SIdo Schimmel 	if (!refcount_dec_and_test(&fid->ref_count))
160332fd4b49SIdo Schimmel 		return;
160432fd4b49SIdo Schimmel 
1605a1107487SIdo Schimmel 	list_del(&fid->list);
16065d44a712SIdo Schimmel 	rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht,
16075d44a712SIdo Schimmel 			       &fid->ht_node, mlxsw_sp_fid_ht_params);
1608a1107487SIdo Schimmel 	fid->fid_family->ops->deconfigure(fid);
1609a1107487SIdo Schimmel 	__clear_bit(fid->fid_index - fid_family->start_index,
1610a1107487SIdo Schimmel 		    fid_family->fids_bitmap);
1611fddf42c3SAmit Cohen 	WARN_ON_ONCE(!list_empty(&fid->port_vid_list));
1612a1107487SIdo Schimmel 	kfree(fid);
1613a1107487SIdo Schimmel }
1614a1107487SIdo Schimmel 
mlxsw_sp_fid_8021q_get(struct mlxsw_sp * mlxsw_sp,u16 vid)1615a1107487SIdo Schimmel struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
1616a1107487SIdo Schimmel {
1617a1107487SIdo Schimmel 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
1618a1107487SIdo Schimmel }
1619a1107487SIdo Schimmel 
mlxsw_sp_fid_8021d_get(struct mlxsw_sp * mlxsw_sp,int br_ifindex)1620a1107487SIdo Schimmel struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
1621a1107487SIdo Schimmel 					    int br_ifindex)
1622a1107487SIdo Schimmel {
1623a1107487SIdo Schimmel 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
1624a1107487SIdo Schimmel }
1625a1107487SIdo Schimmel 
mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp * mlxsw_sp,u16 vid)16265a8fb370SIdo Schimmel struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp,
16275a8fb370SIdo Schimmel 					       u16 vid)
16285a8fb370SIdo Schimmel {
16295a8fb370SIdo Schimmel 	return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
16305a8fb370SIdo Schimmel }
16315a8fb370SIdo Schimmel 
mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp * mlxsw_sp,int br_ifindex)1632564c6d72SIdo Schimmel struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
1633564c6d72SIdo Schimmel 					       int br_ifindex)
1634564c6d72SIdo Schimmel {
1635564c6d72SIdo Schimmel 	return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D,
1636564c6d72SIdo Schimmel 				   &br_ifindex);
1637564c6d72SIdo Schimmel }
1638564c6d72SIdo Schimmel 
mlxsw_sp_fid_rfid_get(struct mlxsw_sp * mlxsw_sp,u16 rif_index)1639a1107487SIdo Schimmel struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
1640a1107487SIdo Schimmel 					   u16 rif_index)
1641a1107487SIdo Schimmel {
1642a1107487SIdo Schimmel 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);
1643a1107487SIdo Schimmel }
1644a1107487SIdo Schimmel 
mlxsw_sp_fid_dummy_get(struct mlxsw_sp * mlxsw_sp)1645a1107487SIdo Schimmel struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
1646a1107487SIdo Schimmel {
1647a1107487SIdo Schimmel 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);
1648a1107487SIdo Schimmel }
1649a1107487SIdo Schimmel 
1650a1107487SIdo Schimmel static int
mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family * fid_family,const struct mlxsw_sp_flood_table * flood_table)1651a1107487SIdo Schimmel mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
1652a1107487SIdo Schimmel 			      const struct mlxsw_sp_flood_table *flood_table)
1653a1107487SIdo Schimmel {
1654a1107487SIdo Schimmel 	enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
1655fe94df6dSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1656a1107487SIdo Schimmel 	const int *sfgc_packet_types;
165777b7f83dSAmit Cohen 	u16 num_fids, mid_base;
1658fe94df6dSAmit Cohen 	int err, i;
1659a1107487SIdo Schimmel 
16609f6f467aSAmit Cohen 	mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0);
1661fe94df6dSAmit Cohen 	num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
1662fe94df6dSAmit Cohen 	err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, mid_base, num_fids);
1663fe94df6dSAmit Cohen 	if (err)
1664fe94df6dSAmit Cohen 		return err;
16659f6f467aSAmit Cohen 
1666a1107487SIdo Schimmel 	sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
1667a1107487SIdo Schimmel 	for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
1668a1107487SIdo Schimmel 		char sfgc_pl[MLXSW_REG_SFGC_LEN];
1669a1107487SIdo Schimmel 
1670a1107487SIdo Schimmel 		if (!sfgc_packet_types[i])
1671a1107487SIdo Schimmel 			continue;
16729f6f467aSAmit Cohen 
1673dd8c77d5SAmit Cohen 		mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type,
167477b7f83dSAmit Cohen 				    flood_table->table_type, 0, mid_base);
16759f6f467aSAmit Cohen 
1676a1107487SIdo Schimmel 		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
1677a1107487SIdo Schimmel 		if (err)
1678fe94df6dSAmit Cohen 			goto err_reg_write;
1679a1107487SIdo Schimmel 	}
1680a1107487SIdo Schimmel 
1681a1107487SIdo Schimmel 	return 0;
1682fe94df6dSAmit Cohen 
1683fe94df6dSAmit Cohen err_reg_write:
1684fe94df6dSAmit Cohen 	mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids);
1685fe94df6dSAmit Cohen 	return err;
1686fe94df6dSAmit Cohen }
1687fe94df6dSAmit Cohen 
1688fe94df6dSAmit Cohen static void
mlxsw_sp_fid_flood_table_fini(struct mlxsw_sp_fid_family * fid_family,const struct mlxsw_sp_flood_table * flood_table)1689fe94df6dSAmit Cohen mlxsw_sp_fid_flood_table_fini(struct mlxsw_sp_fid_family *fid_family,
1690fe94df6dSAmit Cohen 			      const struct mlxsw_sp_flood_table *flood_table)
1691fe94df6dSAmit Cohen {
1692fe94df6dSAmit Cohen 	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1693fe94df6dSAmit Cohen 	u16 num_fids, mid_base;
1694fe94df6dSAmit Cohen 
1695fe94df6dSAmit Cohen 	mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0);
1696fe94df6dSAmit Cohen 	num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
1697fe94df6dSAmit Cohen 	mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids);
1698a1107487SIdo Schimmel }
1699a1107487SIdo Schimmel 
1700a1107487SIdo Schimmel static int
mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family * fid_family)1701a1107487SIdo Schimmel mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
1702a1107487SIdo Schimmel {
1703a1107487SIdo Schimmel 	int i;
1704a1107487SIdo Schimmel 
1705a1107487SIdo Schimmel 	for (i = 0; i < fid_family->nr_flood_tables; i++) {
1706a1107487SIdo Schimmel 		const struct mlxsw_sp_flood_table *flood_table;
1707a1107487SIdo Schimmel 		int err;
1708a1107487SIdo Schimmel 
1709a1107487SIdo Schimmel 		flood_table = &fid_family->flood_tables[i];
1710a1107487SIdo Schimmel 		err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
1711a1107487SIdo Schimmel 		if (err)
1712a1107487SIdo Schimmel 			return err;
1713a1107487SIdo Schimmel 	}
1714a1107487SIdo Schimmel 
1715a1107487SIdo Schimmel 	return 0;
1716a1107487SIdo Schimmel }
1717a1107487SIdo Schimmel 
1718fe94df6dSAmit Cohen static void
mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family * fid_family)1719fe94df6dSAmit Cohen mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family)
1720fe94df6dSAmit Cohen {
1721fe94df6dSAmit Cohen 	int i;
1722fe94df6dSAmit Cohen 
1723fe94df6dSAmit Cohen 	for (i = 0; i < fid_family->nr_flood_tables; i++) {
1724fe94df6dSAmit Cohen 		const struct mlxsw_sp_flood_table *flood_table;
1725fe94df6dSAmit Cohen 
1726fe94df6dSAmit Cohen 		flood_table = &fid_family->flood_tables[i];
1727fe94df6dSAmit Cohen 		mlxsw_sp_fid_flood_table_fini(fid_family, flood_table);
1728fe94df6dSAmit Cohen 	}
1729fe94df6dSAmit Cohen }
1730fe94df6dSAmit Cohen 
mlxsw_sp_fid_family_register(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_fid_family * tmpl)1731a1107487SIdo Schimmel static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
1732a1107487SIdo Schimmel 					const struct mlxsw_sp_fid_family *tmpl)
1733a1107487SIdo Schimmel {
1734a1107487SIdo Schimmel 	u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
1735a1107487SIdo Schimmel 	struct mlxsw_sp_fid_family *fid_family;
1736a1107487SIdo Schimmel 	int err;
1737a1107487SIdo Schimmel 
1738a1107487SIdo Schimmel 	fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);
1739a1107487SIdo Schimmel 	if (!fid_family)
1740a1107487SIdo Schimmel 		return -ENOMEM;
1741a1107487SIdo Schimmel 
1742a1107487SIdo Schimmel 	fid_family->mlxsw_sp = mlxsw_sp;
1743a1107487SIdo Schimmel 	INIT_LIST_HEAD(&fid_family->fids_list);
1744214fa1c4SAndy Shevchenko 	fid_family->fids_bitmap = bitmap_zalloc(nr_fids, GFP_KERNEL);
1745a1107487SIdo Schimmel 	if (!fid_family->fids_bitmap) {
1746a1107487SIdo Schimmel 		err = -ENOMEM;
1747a1107487SIdo Schimmel 		goto err_alloc_fids_bitmap;
1748a1107487SIdo Schimmel 	}
1749a1107487SIdo Schimmel 
1750a1107487SIdo Schimmel 	if (fid_family->flood_tables) {
1751a1107487SIdo Schimmel 		err = mlxsw_sp_fid_flood_tables_init(fid_family);
1752a1107487SIdo Schimmel 		if (err)
1753a1107487SIdo Schimmel 			goto err_fid_flood_tables_init;
1754a1107487SIdo Schimmel 	}
1755a1107487SIdo Schimmel 
1756a1107487SIdo Schimmel 	mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
1757a1107487SIdo Schimmel 
1758a1107487SIdo Schimmel 	return 0;
1759a1107487SIdo Schimmel 
1760a1107487SIdo Schimmel err_fid_flood_tables_init:
1761214fa1c4SAndy Shevchenko 	bitmap_free(fid_family->fids_bitmap);
1762a1107487SIdo Schimmel err_alloc_fids_bitmap:
1763a1107487SIdo Schimmel 	kfree(fid_family);
1764a1107487SIdo Schimmel 	return err;
1765a1107487SIdo Schimmel }
1766a1107487SIdo Schimmel 
1767a1107487SIdo Schimmel static void
mlxsw_sp_fid_family_unregister(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fid_family * fid_family)1768a1107487SIdo Schimmel mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
1769a1107487SIdo Schimmel 			       struct mlxsw_sp_fid_family *fid_family)
1770a1107487SIdo Schimmel {
1771a1107487SIdo Schimmel 	mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
1772fe94df6dSAmit Cohen 
1773fe94df6dSAmit Cohen 	if (fid_family->flood_tables)
1774fe94df6dSAmit Cohen 		mlxsw_sp_fid_flood_tables_fini(fid_family);
1775fe94df6dSAmit Cohen 
1776214fa1c4SAndy Shevchenko 	bitmap_free(fid_family->fids_bitmap);
1777a1107487SIdo Schimmel 	WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
1778a1107487SIdo Schimmel 	kfree(fid_family);
1779a1107487SIdo Schimmel }
1780a1107487SIdo Schimmel 
mlxsw_sp_port_fids_init(struct mlxsw_sp_port * mlxsw_sp_port)1781a1107487SIdo Schimmel int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
1782a1107487SIdo Schimmel {
1783a1107487SIdo Schimmel 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1784a1107487SIdo Schimmel 
1785a1107487SIdo Schimmel 	/* Track number of FIDs configured on the port with mapping type
1786a1107487SIdo Schimmel 	 * PORT_VID_TO_FID, so that we know when to transition the port
1787a1107487SIdo Schimmel 	 * back to non-virtual (VLAN) mode.
1788a1107487SIdo Schimmel 	 */
1789a1107487SIdo Schimmel 	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1790a1107487SIdo Schimmel 
1791a1107487SIdo Schimmel 	return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
1792a1107487SIdo Schimmel }
1793a1107487SIdo Schimmel 
mlxsw_sp_port_fids_fini(struct mlxsw_sp_port * mlxsw_sp_port)1794a1107487SIdo Schimmel void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
1795a1107487SIdo Schimmel {
1796a1107487SIdo Schimmel 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1797a1107487SIdo Schimmel 
1798a1107487SIdo Schimmel 	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1799a1107487SIdo Schimmel }
1800a1107487SIdo Schimmel 
mlxsw_sp_fids_init(struct mlxsw_sp * mlxsw_sp)1801a1107487SIdo Schimmel int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
1802a1107487SIdo Schimmel {
1803a1107487SIdo Schimmel 	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
1804a1107487SIdo Schimmel 	struct mlxsw_sp_fid_core *fid_core;
1805a1107487SIdo Schimmel 	int err, i;
1806a1107487SIdo Schimmel 
1807a1107487SIdo Schimmel 	fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
1808a1107487SIdo Schimmel 	if (!fid_core)
1809a1107487SIdo Schimmel 		return -ENOMEM;
1810a1107487SIdo Schimmel 	mlxsw_sp->fid_core = fid_core;
1811a1107487SIdo Schimmel 
18125d44a712SIdo Schimmel 	err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params);
18135d44a712SIdo Schimmel 	if (err)
18145d44a712SIdo Schimmel 		goto err_rhashtable_fid_init;
18155d44a712SIdo Schimmel 
1816d3d19d4bSIdo Schimmel 	err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params);
1817d3d19d4bSIdo Schimmel 	if (err)
18185d44a712SIdo Schimmel 		goto err_rhashtable_vni_init;
1819d3d19d4bSIdo Schimmel 
1820a1107487SIdo Schimmel 	fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
1821a1107487SIdo Schimmel 					      GFP_KERNEL);
1822a1107487SIdo Schimmel 	if (!fid_core->port_fid_mappings) {
1823a1107487SIdo Schimmel 		err = -ENOMEM;
1824a1107487SIdo Schimmel 		goto err_alloc_port_fid_mappings;
1825a1107487SIdo Schimmel 	}
1826a1107487SIdo Schimmel 
1827a1107487SIdo Schimmel 	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
1828a1107487SIdo Schimmel 		err = mlxsw_sp_fid_family_register(mlxsw_sp,
182904e85970SAmit Cohen 						   mlxsw_sp->fid_family_arr[i]);
1830a1107487SIdo Schimmel 
1831a1107487SIdo Schimmel 		if (err)
1832a1107487SIdo Schimmel 			goto err_fid_ops_register;
1833a1107487SIdo Schimmel 	}
1834a1107487SIdo Schimmel 
1835a1107487SIdo Schimmel 	return 0;
1836a1107487SIdo Schimmel 
1837a1107487SIdo Schimmel err_fid_ops_register:
1838a1107487SIdo Schimmel 	for (i--; i >= 0; i--) {
1839a1107487SIdo Schimmel 		struct mlxsw_sp_fid_family *fid_family;
1840a1107487SIdo Schimmel 
1841a1107487SIdo Schimmel 		fid_family = fid_core->fid_family_arr[i];
1842a1107487SIdo Schimmel 		mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
1843a1107487SIdo Schimmel 	}
1844a1107487SIdo Schimmel 	kfree(fid_core->port_fid_mappings);
1845a1107487SIdo Schimmel err_alloc_port_fid_mappings:
1846d3d19d4bSIdo Schimmel 	rhashtable_destroy(&fid_core->vni_ht);
18475d44a712SIdo Schimmel err_rhashtable_vni_init:
18485d44a712SIdo Schimmel 	rhashtable_destroy(&fid_core->fid_ht);
18495d44a712SIdo Schimmel err_rhashtable_fid_init:
1850a1107487SIdo Schimmel 	kfree(fid_core);
1851a1107487SIdo Schimmel 	return err;
1852a1107487SIdo Schimmel }
1853a1107487SIdo Schimmel 
mlxsw_sp_fids_fini(struct mlxsw_sp * mlxsw_sp)1854a1107487SIdo Schimmel void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
1855a1107487SIdo Schimmel {
1856a1107487SIdo Schimmel 	struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
1857a1107487SIdo Schimmel 	int i;
1858a1107487SIdo Schimmel 
1859a1107487SIdo Schimmel 	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
1860a1107487SIdo Schimmel 		mlxsw_sp_fid_family_unregister(mlxsw_sp,
1861a1107487SIdo Schimmel 					       fid_core->fid_family_arr[i]);
1862a1107487SIdo Schimmel 	kfree(fid_core->port_fid_mappings);
1863d3d19d4bSIdo Schimmel 	rhashtable_destroy(&fid_core->vni_ht);
18645d44a712SIdo Schimmel 	rhashtable_destroy(&fid_core->fid_ht);
1865a1107487SIdo Schimmel 	kfree(fid_core);
1866a1107487SIdo Schimmel }
1867