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