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
16struct mlxsw_sp_fid_family;
17
18struct 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
25struct 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
42struct mlxsw_sp_fid_8021q {
43	struct mlxsw_sp_fid common;
44	u16 vid;
45};
46
47struct mlxsw_sp_fid_8021d {
48	struct mlxsw_sp_fid common;
49	int br_ifindex;
50};
51
52static 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
58static 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
64struct 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
71struct 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
93struct 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
108static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
109	[MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST]			= 1,
110};
111
112static 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
120static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
121	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4]	= 1,
122};
123
124static 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
130bool 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
140bool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid)
141{
142	return fid->fid_family->lag_vid_valid;
143}
144
145struct 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
158int 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
168int 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
179struct 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
192int 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
202int 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
222void 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
234bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
235{
236	return fid->nve_flood_index_valid;
237}
238
239int 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
267err_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
273void 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
288bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
289{
290	return fid->vni_valid;
291}
292
293void 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
303static const struct mlxsw_sp_flood_table *
304mlxsw_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
319int 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
349int 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
357void 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
363u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
364{
365	return fid->fid_index;
366}
367
368enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
369{
370	return fid->fid_family->type;
371}
372
373void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
374{
375	fid->rif = rif;
376}
377
378struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
379{
380	return fid->rif;
381}
382
383enum mlxsw_sp_rif_type
384mlxsw_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
392static struct mlxsw_sp_fid_8021q *
393mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
394{
395	return container_of(fid, struct mlxsw_sp_fid_8021q, common);
396}
397
398u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
399{
400	return mlxsw_sp_fid_8021q_fid(fid)->vid;
401}
402
403static 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
410static 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
416static 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
426static 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
441static 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
451static struct mlxsw_sp_fid_8021d *
452mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
453{
454	return container_of(fid, struct mlxsw_sp_fid_8021d, common);
455}
456
457static 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
464static 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
471static 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
478static 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
493static bool
494mlxsw_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
501static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid)
502{
503	return fid->fid_index - VLAN_N_VID;
504}
505
506static 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
533err_port_vp_mode_set:
534err_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
550static 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
571static 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
592err_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
599static void
600mlxsw_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
613static 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
622static 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
630static 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
640static 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
648static void
649mlxsw_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
655static 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
671static 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 */
693static 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
705static bool
706mlxsw_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
713static void
714mlxsw_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
720static 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 */
742static 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
754static 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
760static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
761{
762}
763
764static 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
774static 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
782static 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
801err_port_vp_mode_trans:
802	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
803	return err;
804}
805
806static void
807mlxsw_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
818static 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
830static 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
839static 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
846static 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
851static 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
859static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
860				       const void *arg)
861{
862	return true;
863}
864
865static 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
872static 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
880static 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
887static 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
905static 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
946err_rhashtable_insert:
947	fid->fid_family->ops->deconfigure(fid);
948err_configure:
949	__clear_bit(fid_index - fid_family->start_index,
950		    fid_family->fids_bitmap);
951err_index_alloc:
952	kfree(fid);
953	return ERR_PTR(err);
954}
955
956void 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
973struct 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
978struct 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
984struct 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
990struct 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
997struct 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
1003struct 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
1008static int
1009mlxsw_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
1035static int
1036mlxsw_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
1053static 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
1082err_fid_flood_tables_init:
1083	bitmap_free(fid_family->fids_bitmap);
1084err_alloc_fids_bitmap:
1085	kfree(fid_family);
1086	return err;
1087}
1088
1089static void
1090mlxsw_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
1099int 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
1112void 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
1119int 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
1155err_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);
1163err_alloc_port_fid_mappings:
1164	rhashtable_destroy(&fid_core->vni_ht);
1165err_rhashtable_vni_init:
1166	rhashtable_destroy(&fid_core->fid_ht);
1167err_rhashtable_fid_init:
1168	kfree(fid_core);
1169	return err;
1170}
1171
1172void 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