xref: /linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c (revision 26fbb4c8c7c3ee9a4c3b4de555a8587b5a19154e)
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_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
442 				       u8 local_port, u16 vid, bool valid)
443 {
444 	enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
445 	char svfa_pl[MLXSW_REG_SVFA_LEN];
446 
447 	mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid);
448 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
449 }
450 
451 static struct mlxsw_sp_fid_8021d *
452 mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
453 {
454 	return container_of(fid, struct mlxsw_sp_fid_8021d, common);
455 }
456 
457 static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
458 {
459 	int br_ifindex = *(int *) arg;
460 
461 	mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
462 }
463 
464 static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
465 {
466 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
467 
468 	return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true);
469 }
470 
471 static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
472 {
473 	if (fid->vni_valid)
474 		mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
475 	mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
476 }
477 
478 static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
479 					  const void *arg, u16 *p_fid_index)
480 {
481 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
482 	u16 nr_fids, fid_index;
483 
484 	nr_fids = fid_family->end_index - fid_family->start_index + 1;
485 	fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);
486 	if (fid_index == nr_fids)
487 		return -ENOBUFS;
488 	*p_fid_index = fid_family->start_index + fid_index;
489 
490 	return 0;
491 }
492 
493 static bool
494 mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
495 {
496 	int br_ifindex = *(int *) arg;
497 
498 	return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
499 }
500 
501 static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid)
502 {
503 	return fid->fid_index - VLAN_N_VID;
504 }
505 
506 static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
507 {
508 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
509 	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
510 	int err;
511 
512 	list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
513 			    list) {
514 		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
515 		u16 vid = mlxsw_sp_port_vlan->vid;
516 
517 		if (!fid)
518 			continue;
519 
520 		err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
521 						  mlxsw_sp_port->local_port,
522 						  vid, true);
523 		if (err)
524 			goto err_fid_port_vid_map;
525 	}
526 
527 	err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
528 	if (err)
529 		goto err_port_vp_mode_set;
530 
531 	return 0;
532 
533 err_port_vp_mode_set:
534 err_fid_port_vid_map:
535 	list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
536 					     &mlxsw_sp_port->vlans_list, list) {
537 		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
538 		u16 vid = mlxsw_sp_port_vlan->vid;
539 
540 		if (!fid)
541 			continue;
542 
543 		__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
544 					    mlxsw_sp_port->local_port, vid,
545 					    false);
546 	}
547 	return err;
548 }
549 
550 static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
551 {
552 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
553 	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
554 
555 	mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
556 
557 	list_for_each_entry_reverse(mlxsw_sp_port_vlan,
558 				    &mlxsw_sp_port->vlans_list, list) {
559 		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
560 		u16 vid = mlxsw_sp_port_vlan->vid;
561 
562 		if (!fid)
563 			continue;
564 
565 		__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
566 					    mlxsw_sp_port->local_port, vid,
567 					    false);
568 	}
569 }
570 
571 static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
572 					   struct mlxsw_sp_port *mlxsw_sp_port,
573 					   u16 vid)
574 {
575 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
576 	u8 local_port = mlxsw_sp_port->local_port;
577 	int err;
578 
579 	err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
580 					  mlxsw_sp_port->local_port, vid, true);
581 	if (err)
582 		return err;
583 
584 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
585 		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
586 		if (err)
587 			goto err_port_vp_mode_trans;
588 	}
589 
590 	return 0;
591 
592 err_port_vp_mode_trans:
593 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
594 	__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
595 				    mlxsw_sp_port->local_port, vid, false);
596 	return err;
597 }
598 
599 static void
600 mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
601 				  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
602 {
603 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
604 	u8 local_port = mlxsw_sp_port->local_port;
605 
606 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
607 		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
608 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
609 	__mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
610 				    mlxsw_sp_port->local_port, vid, false);
611 }
612 
613 static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid, __be32 vni)
614 {
615 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
616 
617 	return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, vni,
618 				   true, fid->nve_flood_index,
619 				   fid->nve_flood_index_valid);
620 }
621 
622 static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
623 {
624 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
625 
626 	mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, 0, false,
627 			    fid->nve_flood_index, fid->nve_flood_index_valid);
628 }
629 
630 static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid,
631 						  u32 nve_flood_index)
632 {
633 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
634 
635 	return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index,
636 				   fid->vni, fid->vni_valid, nve_flood_index,
637 				   true);
638 }
639 
640 static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
641 {
642 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
643 
644 	mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, fid->vni,
645 			    fid->vni_valid, 0, false);
646 }
647 
648 static void
649 mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
650 				     const struct net_device *nve_dev)
651 {
652 	br_fdb_clear_offload(nve_dev, 0);
653 }
654 
655 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
656 	.setup			= mlxsw_sp_fid_8021d_setup,
657 	.configure		= mlxsw_sp_fid_8021d_configure,
658 	.deconfigure		= mlxsw_sp_fid_8021d_deconfigure,
659 	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,
660 	.compare		= mlxsw_sp_fid_8021d_compare,
661 	.flood_index		= mlxsw_sp_fid_8021d_flood_index,
662 	.port_vid_map		= mlxsw_sp_fid_8021d_port_vid_map,
663 	.port_vid_unmap		= mlxsw_sp_fid_8021d_port_vid_unmap,
664 	.vni_set		= mlxsw_sp_fid_8021d_vni_set,
665 	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,
666 	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,
667 	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,
668 	.fdb_clear_offload	= mlxsw_sp_fid_8021d_fdb_clear_offload,
669 };
670 
671 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
672 	{
673 		.packet_type	= MLXSW_SP_FLOOD_TYPE_UC,
674 		.bridge_type	= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
675 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID,
676 		.table_index	= 0,
677 	},
678 	{
679 		.packet_type	= MLXSW_SP_FLOOD_TYPE_MC,
680 		.bridge_type	= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
681 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID,
682 		.table_index	= 1,
683 	},
684 	{
685 		.packet_type	= MLXSW_SP_FLOOD_TYPE_BC,
686 		.bridge_type	= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
687 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID,
688 		.table_index	= 2,
689 	},
690 };
691 
692 /* Range and flood configuration must match mlxsw_config_profile */
693 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = {
694 	.type			= MLXSW_SP_FID_TYPE_8021D,
695 	.fid_size		= sizeof(struct mlxsw_sp_fid_8021d),
696 	.start_index		= VLAN_N_VID,
697 	.end_index		= VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1,
698 	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
699 	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
700 	.rif_type		= MLXSW_SP_RIF_TYPE_FID,
701 	.ops			= &mlxsw_sp_fid_8021d_ops,
702 	.lag_vid_valid		= 1,
703 };
704 
705 static bool
706 mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
707 {
708 	u16 vid = *(u16 *) arg;
709 
710 	return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
711 }
712 
713 static void
714 mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
715 				     const struct net_device *nve_dev)
716 {
717 	br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid));
718 }
719 
720 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_emu_ops = {
721 	.setup			= mlxsw_sp_fid_8021q_setup,
722 	.configure		= mlxsw_sp_fid_8021d_configure,
723 	.deconfigure		= mlxsw_sp_fid_8021d_deconfigure,
724 	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,
725 	.compare		= mlxsw_sp_fid_8021q_compare,
726 	.flood_index		= mlxsw_sp_fid_8021d_flood_index,
727 	.port_vid_map		= mlxsw_sp_fid_8021d_port_vid_map,
728 	.port_vid_unmap		= mlxsw_sp_fid_8021d_port_vid_unmap,
729 	.vni_set		= mlxsw_sp_fid_8021d_vni_set,
730 	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,
731 	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,
732 	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,
733 	.fdb_clear_offload	= mlxsw_sp_fid_8021q_fdb_clear_offload,
734 };
735 
736 /* There are 4K-2 emulated 802.1Q FIDs, starting right after the 802.1D FIDs */
737 #define MLXSW_SP_FID_8021Q_EMU_START	(VLAN_N_VID + MLXSW_SP_FID_8021D_MAX)
738 #define MLXSW_SP_FID_8021Q_EMU_END	(MLXSW_SP_FID_8021Q_EMU_START + \
739 					 VLAN_VID_MASK - 2)
740 
741 /* Range and flood configuration must match mlxsw_config_profile */
742 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_emu_family = {
743 	.type			= MLXSW_SP_FID_TYPE_8021Q,
744 	.fid_size		= sizeof(struct mlxsw_sp_fid_8021q),
745 	.start_index		= MLXSW_SP_FID_8021Q_EMU_START,
746 	.end_index		= MLXSW_SP_FID_8021Q_EMU_END,
747 	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
748 	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
749 	.rif_type		= MLXSW_SP_RIF_TYPE_VLAN,
750 	.ops			= &mlxsw_sp_fid_8021q_emu_ops,
751 	.lag_vid_valid		= 1,
752 };
753 
754 static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
755 {
756 	/* rFIDs are allocated by the device during init */
757 	return 0;
758 }
759 
760 static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
761 {
762 }
763 
764 static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
765 					 const void *arg, u16 *p_fid_index)
766 {
767 	u16 rif_index = *(u16 *) arg;
768 
769 	*p_fid_index = fid->fid_family->start_index + rif_index;
770 
771 	return 0;
772 }
773 
774 static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
775 				      const void *arg)
776 {
777 	u16 rif_index = *(u16 *) arg;
778 
779 	return fid->fid_index == rif_index + fid->fid_family->start_index;
780 }
781 
782 static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
783 					  struct mlxsw_sp_port *mlxsw_sp_port,
784 					  u16 vid)
785 {
786 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
787 	u8 local_port = mlxsw_sp_port->local_port;
788 	int err;
789 
790 	/* We only need to transition the port to virtual mode since
791 	 * {Port, VID} => FID is done by the firmware upon RIF creation.
792 	 */
793 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
794 		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
795 		if (err)
796 			goto err_port_vp_mode_trans;
797 	}
798 
799 	return 0;
800 
801 err_port_vp_mode_trans:
802 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
803 	return err;
804 }
805 
806 static void
807 mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
808 				 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
809 {
810 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
811 	u8 local_port = mlxsw_sp_port->local_port;
812 
813 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
814 		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
815 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
816 }
817 
818 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
819 	.configure		= mlxsw_sp_fid_rfid_configure,
820 	.deconfigure		= mlxsw_sp_fid_rfid_deconfigure,
821 	.index_alloc		= mlxsw_sp_fid_rfid_index_alloc,
822 	.compare		= mlxsw_sp_fid_rfid_compare,
823 	.port_vid_map		= mlxsw_sp_fid_rfid_port_vid_map,
824 	.port_vid_unmap		= mlxsw_sp_fid_rfid_port_vid_unmap,
825 };
826 
827 #define MLXSW_SP_RFID_BASE	(15 * 1024)
828 #define MLXSW_SP_RFID_MAX	1024
829 
830 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
831 	.type			= MLXSW_SP_FID_TYPE_RFID,
832 	.fid_size		= sizeof(struct mlxsw_sp_fid),
833 	.start_index		= MLXSW_SP_RFID_BASE,
834 	.end_index		= MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1,
835 	.rif_type		= MLXSW_SP_RIF_TYPE_SUBPORT,
836 	.ops			= &mlxsw_sp_fid_rfid_ops,
837 };
838 
839 static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
840 {
841 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
842 
843 	return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true);
844 }
845 
846 static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
847 {
848 	mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
849 }
850 
851 static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
852 					  const void *arg, u16 *p_fid_index)
853 {
854 	*p_fid_index = fid->fid_family->start_index;
855 
856 	return 0;
857 }
858 
859 static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
860 				       const void *arg)
861 {
862 	return true;
863 }
864 
865 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
866 	.configure		= mlxsw_sp_fid_dummy_configure,
867 	.deconfigure		= mlxsw_sp_fid_dummy_deconfigure,
868 	.index_alloc		= mlxsw_sp_fid_dummy_index_alloc,
869 	.compare		= mlxsw_sp_fid_dummy_compare,
870 };
871 
872 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = {
873 	.type			= MLXSW_SP_FID_TYPE_DUMMY,
874 	.fid_size		= sizeof(struct mlxsw_sp_fid),
875 	.start_index		= VLAN_N_VID - 1,
876 	.end_index		= VLAN_N_VID - 1,
877 	.ops			= &mlxsw_sp_fid_dummy_ops,
878 };
879 
880 static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = {
881 	[MLXSW_SP_FID_TYPE_8021Q]	= &mlxsw_sp_fid_8021q_emu_family,
882 	[MLXSW_SP_FID_TYPE_8021D]	= &mlxsw_sp_fid_8021d_family,
883 	[MLXSW_SP_FID_TYPE_RFID]	= &mlxsw_sp_fid_rfid_family,
884 	[MLXSW_SP_FID_TYPE_DUMMY]	= &mlxsw_sp_fid_dummy_family,
885 };
886 
887 static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,
888 						enum mlxsw_sp_fid_type type,
889 						const void *arg)
890 {
891 	struct mlxsw_sp_fid_family *fid_family;
892 	struct mlxsw_sp_fid *fid;
893 
894 	fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
895 	list_for_each_entry(fid, &fid_family->fids_list, list) {
896 		if (!fid->fid_family->ops->compare(fid, arg))
897 			continue;
898 		refcount_inc(&fid->ref_count);
899 		return fid;
900 	}
901 
902 	return NULL;
903 }
904 
905 static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
906 					     enum mlxsw_sp_fid_type type,
907 					     const void *arg)
908 {
909 	struct mlxsw_sp_fid_family *fid_family;
910 	struct mlxsw_sp_fid *fid;
911 	u16 fid_index;
912 	int err;
913 
914 	fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg);
915 	if (fid)
916 		return fid;
917 
918 	fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
919 	fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
920 	if (!fid)
921 		return ERR_PTR(-ENOMEM);
922 	fid->fid_family = fid_family;
923 
924 	err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
925 	if (err)
926 		goto err_index_alloc;
927 	fid->fid_index = fid_index;
928 	__set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
929 
930 	if (fid->fid_family->ops->setup)
931 		fid->fid_family->ops->setup(fid, arg);
932 
933 	err = fid->fid_family->ops->configure(fid);
934 	if (err)
935 		goto err_configure;
936 
937 	err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node,
938 				     mlxsw_sp_fid_ht_params);
939 	if (err)
940 		goto err_rhashtable_insert;
941 
942 	list_add(&fid->list, &fid_family->fids_list);
943 	refcount_set(&fid->ref_count, 1);
944 	return fid;
945 
946 err_rhashtable_insert:
947 	fid->fid_family->ops->deconfigure(fid);
948 err_configure:
949 	__clear_bit(fid_index - fid_family->start_index,
950 		    fid_family->fids_bitmap);
951 err_index_alloc:
952 	kfree(fid);
953 	return ERR_PTR(err);
954 }
955 
956 void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
957 {
958 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
959 	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
960 
961 	if (!refcount_dec_and_test(&fid->ref_count))
962 		return;
963 
964 	list_del(&fid->list);
965 	rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht,
966 			       &fid->ht_node, mlxsw_sp_fid_ht_params);
967 	fid->fid_family->ops->deconfigure(fid);
968 	__clear_bit(fid->fid_index - fid_family->start_index,
969 		    fid_family->fids_bitmap);
970 	kfree(fid);
971 }
972 
973 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
974 {
975 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
976 }
977 
978 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
979 					    int br_ifindex)
980 {
981 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
982 }
983 
984 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp,
985 					       u16 vid)
986 {
987 	return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
988 }
989 
990 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
991 					       int br_ifindex)
992 {
993 	return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D,
994 				   &br_ifindex);
995 }
996 
997 struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
998 					   u16 rif_index)
999 {
1000 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);
1001 }
1002 
1003 struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
1004 {
1005 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);
1006 }
1007 
1008 static int
1009 mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
1010 			      const struct mlxsw_sp_flood_table *flood_table)
1011 {
1012 	enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
1013 	const int *sfgc_packet_types;
1014 	int i;
1015 
1016 	sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
1017 	for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
1018 		struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1019 		char sfgc_pl[MLXSW_REG_SFGC_LEN];
1020 		int err;
1021 
1022 		if (!sfgc_packet_types[i])
1023 			continue;
1024 		mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type,
1025 				    flood_table->table_type,
1026 				    flood_table->table_index);
1027 		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
1028 		if (err)
1029 			return err;
1030 	}
1031 
1032 	return 0;
1033 }
1034 
1035 static int
1036 mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
1037 {
1038 	int i;
1039 
1040 	for (i = 0; i < fid_family->nr_flood_tables; i++) {
1041 		const struct mlxsw_sp_flood_table *flood_table;
1042 		int err;
1043 
1044 		flood_table = &fid_family->flood_tables[i];
1045 		err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
1046 		if (err)
1047 			return err;
1048 	}
1049 
1050 	return 0;
1051 }
1052 
1053 static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
1054 					const struct mlxsw_sp_fid_family *tmpl)
1055 {
1056 	u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
1057 	struct mlxsw_sp_fid_family *fid_family;
1058 	int err;
1059 
1060 	fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);
1061 	if (!fid_family)
1062 		return -ENOMEM;
1063 
1064 	fid_family->mlxsw_sp = mlxsw_sp;
1065 	INIT_LIST_HEAD(&fid_family->fids_list);
1066 	fid_family->fids_bitmap = bitmap_zalloc(nr_fids, GFP_KERNEL);
1067 	if (!fid_family->fids_bitmap) {
1068 		err = -ENOMEM;
1069 		goto err_alloc_fids_bitmap;
1070 	}
1071 
1072 	if (fid_family->flood_tables) {
1073 		err = mlxsw_sp_fid_flood_tables_init(fid_family);
1074 		if (err)
1075 			goto err_fid_flood_tables_init;
1076 	}
1077 
1078 	mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
1079 
1080 	return 0;
1081 
1082 err_fid_flood_tables_init:
1083 	bitmap_free(fid_family->fids_bitmap);
1084 err_alloc_fids_bitmap:
1085 	kfree(fid_family);
1086 	return err;
1087 }
1088 
1089 static void
1090 mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
1091 			       struct mlxsw_sp_fid_family *fid_family)
1092 {
1093 	mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
1094 	bitmap_free(fid_family->fids_bitmap);
1095 	WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
1096 	kfree(fid_family);
1097 }
1098 
1099 int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
1100 {
1101 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1102 
1103 	/* Track number of FIDs configured on the port with mapping type
1104 	 * PORT_VID_TO_FID, so that we know when to transition the port
1105 	 * back to non-virtual (VLAN) mode.
1106 	 */
1107 	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1108 
1109 	return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
1110 }
1111 
1112 void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
1113 {
1114 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1115 
1116 	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1117 }
1118 
1119 int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
1120 {
1121 	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
1122 	struct mlxsw_sp_fid_core *fid_core;
1123 	int err, i;
1124 
1125 	fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
1126 	if (!fid_core)
1127 		return -ENOMEM;
1128 	mlxsw_sp->fid_core = fid_core;
1129 
1130 	err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params);
1131 	if (err)
1132 		goto err_rhashtable_fid_init;
1133 
1134 	err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params);
1135 	if (err)
1136 		goto err_rhashtable_vni_init;
1137 
1138 	fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
1139 					      GFP_KERNEL);
1140 	if (!fid_core->port_fid_mappings) {
1141 		err = -ENOMEM;
1142 		goto err_alloc_port_fid_mappings;
1143 	}
1144 
1145 	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
1146 		err = mlxsw_sp_fid_family_register(mlxsw_sp,
1147 						   mlxsw_sp_fid_family_arr[i]);
1148 
1149 		if (err)
1150 			goto err_fid_ops_register;
1151 	}
1152 
1153 	return 0;
1154 
1155 err_fid_ops_register:
1156 	for (i--; i >= 0; i--) {
1157 		struct mlxsw_sp_fid_family *fid_family;
1158 
1159 		fid_family = fid_core->fid_family_arr[i];
1160 		mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
1161 	}
1162 	kfree(fid_core->port_fid_mappings);
1163 err_alloc_port_fid_mappings:
1164 	rhashtable_destroy(&fid_core->vni_ht);
1165 err_rhashtable_vni_init:
1166 	rhashtable_destroy(&fid_core->fid_ht);
1167 err_rhashtable_fid_init:
1168 	kfree(fid_core);
1169 	return err;
1170 }
1171 
1172 void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
1173 {
1174 	struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
1175 	int i;
1176 
1177 	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
1178 		mlxsw_sp_fid_family_unregister(mlxsw_sp,
1179 					       fid_core->fid_family_arr[i]);
1180 	kfree(fid_core->port_fid_mappings);
1181 	rhashtable_destroy(&fid_core->vni_ht);
1182 	rhashtable_destroy(&fid_core->fid_ht);
1183 	kfree(fid_core);
1184 }
1185