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