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