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