• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
3 
4 #include <linux/kernel.h>
5 #include <linux/bitops.h>
6 #include <linux/if_vlan.h>
7 #include <linux/if_bridge.h>
8 #include <linux/netdevice.h>
9 #include <linux/rhashtable.h>
10 #include <linux/rtnetlink.h>
11 #include <linux/refcount.h>
12 
13 #include "spectrum.h"
14 #include "reg.h"
15 
16 struct mlxsw_sp_fid_family;
17 
18 struct mlxsw_sp_fid_core {
19 	struct rhashtable fid_ht;
20 	struct rhashtable vni_ht;
21 	struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
22 	unsigned int *port_fid_mappings;
23 };
24 
25 struct mlxsw_sp_fid_port_vid {
26 	struct list_head list;
27 	u16 local_port;
28 	u16 vid;
29 };
30 
31 struct mlxsw_sp_fid {
32 	struct list_head list;
33 	struct mlxsw_sp_rif *rif;
34 	refcount_t ref_count;
35 	u16 fid_index;
36 	u16 fid_offset;
37 	struct mlxsw_sp_fid_family *fid_family;
38 	struct rhash_head ht_node;
39 
40 	struct rhash_head vni_ht_node;
41 	enum mlxsw_sp_nve_type nve_type;
42 	__be32 vni;
43 	u32 nve_flood_index;
44 	int nve_ifindex;
45 	u8 vni_valid:1,
46 	   nve_flood_index_valid:1;
47 	struct list_head port_vid_list; /* Ordered by local port. */
48 };
49 
50 struct mlxsw_sp_fid_8021q {
51 	struct mlxsw_sp_fid common;
52 	u16 vid;
53 };
54 
55 struct mlxsw_sp_fid_8021d {
56 	struct mlxsw_sp_fid common;
57 	int br_ifindex;
58 };
59 
60 static const struct rhashtable_params mlxsw_sp_fid_ht_params = {
61 	.key_len = sizeof_field(struct mlxsw_sp_fid, fid_index),
62 	.key_offset = offsetof(struct mlxsw_sp_fid, fid_index),
63 	.head_offset = offsetof(struct mlxsw_sp_fid, ht_node),
64 };
65 
66 static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = {
67 	.key_len = sizeof_field(struct mlxsw_sp_fid, vni),
68 	.key_offset = offsetof(struct mlxsw_sp_fid, vni),
69 	.head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node),
70 };
71 
72 struct mlxsw_sp_flood_table {
73 	enum mlxsw_sp_flood_type packet_type;
74 	enum mlxsw_flood_table_type table_type;
75 	int table_index;
76 };
77 
78 struct mlxsw_sp_fid_ops {
79 	void (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
80 	int (*configure)(struct mlxsw_sp_fid *fid);
81 	void (*deconfigure)(struct mlxsw_sp_fid *fid);
82 	int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
83 			   u16 *p_fid_index);
84 	bool (*compare)(const struct mlxsw_sp_fid *fid,
85 			const void *arg);
86 	int (*port_vid_map)(struct mlxsw_sp_fid *fid,
87 			    struct mlxsw_sp_port *port, u16 vid);
88 	void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
89 			       struct mlxsw_sp_port *port, u16 vid);
90 	int (*vni_set)(struct mlxsw_sp_fid *fid);
91 	void (*vni_clear)(struct mlxsw_sp_fid *fid);
92 	int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid);
93 	void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);
94 	void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid,
95 				  const struct net_device *nve_dev);
96 	int (*vid_to_fid_rif_update)(const struct mlxsw_sp_fid *fid,
97 				     const struct mlxsw_sp_rif *rif);
98 };
99 
100 struct mlxsw_sp_fid_family {
101 	enum mlxsw_sp_fid_type type;
102 	size_t fid_size;
103 	u16 start_index;
104 	u16 end_index;
105 	struct list_head fids_list;
106 	unsigned long *fids_bitmap;
107 	const struct mlxsw_sp_flood_table *flood_tables;
108 	int nr_flood_tables;
109 	enum mlxsw_sp_rif_type rif_type;
110 	const struct mlxsw_sp_fid_ops *ops;
111 	struct mlxsw_sp *mlxsw_sp;
112 	bool flood_rsp;
113 	enum mlxsw_reg_bridge_type bridge_type;
114 	u16 pgt_base;
115 	bool smpe_index_valid;
116 };
117 
118 static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
119 	[MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST]			= 1,
120 };
121 
122 static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
123 	[MLXSW_REG_SFGC_TYPE_BROADCAST]				= 1,
124 	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP]	= 1,
125 	[MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL]			= 1,
126 	[MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST]			= 1,
127 	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6]	= 1,
128 };
129 
130 static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
131 	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4]	= 1,
132 };
133 
134 static const int *mlxsw_sp_packet_type_sfgc_types[] = {
135 	[MLXSW_SP_FLOOD_TYPE_UC]	= mlxsw_sp_sfgc_uc_packet_types,
136 	[MLXSW_SP_FLOOD_TYPE_BC]	= mlxsw_sp_sfgc_bc_packet_types,
137 	[MLXSW_SP_FLOOD_TYPE_MC]	= mlxsw_sp_sfgc_mc_packet_types,
138 };
139 
mlxsw_sp_fid_is_dummy(struct mlxsw_sp * mlxsw_sp,u16 fid_index)140 bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index)
141 {
142 	enum mlxsw_sp_fid_type fid_type = MLXSW_SP_FID_TYPE_DUMMY;
143 	struct mlxsw_sp_fid_family *fid_family;
144 
145 	fid_family = mlxsw_sp->fid_core->fid_family_arr[fid_type];
146 
147 	return fid_family->start_index == fid_index;
148 }
149 
mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp * mlxsw_sp,u16 fid_index)150 struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
151 						  u16 fid_index)
152 {
153 	struct mlxsw_sp_fid *fid;
154 
155 	fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index,
156 				     mlxsw_sp_fid_ht_params);
157 	if (fid)
158 		refcount_inc(&fid->ref_count);
159 
160 	return fid;
161 }
162 
mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid * fid,int * nve_ifindex)163 int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex)
164 {
165 	if (!fid->vni_valid)
166 		return -EINVAL;
167 
168 	*nve_ifindex = fid->nve_ifindex;
169 
170 	return 0;
171 }
172 
mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid * fid,enum mlxsw_sp_nve_type * p_type)173 int mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid,
174 			  enum mlxsw_sp_nve_type *p_type)
175 {
176 	if (!fid->vni_valid)
177 		return -EINVAL;
178 
179 	*p_type = fid->nve_type;
180 
181 	return 0;
182 }
183 
mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp * mlxsw_sp,__be32 vni)184 struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,
185 						__be32 vni)
186 {
187 	struct mlxsw_sp_fid *fid;
188 
189 	fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni,
190 				     mlxsw_sp_fid_vni_ht_params);
191 	if (fid)
192 		refcount_inc(&fid->ref_count);
193 
194 	return fid;
195 }
196 
mlxsw_sp_fid_vni(const struct mlxsw_sp_fid * fid,__be32 * vni)197 int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni)
198 {
199 	if (!fid->vni_valid)
200 		return -EINVAL;
201 
202 	*vni = fid->vni;
203 
204 	return 0;
205 }
206 
mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid * fid,u32 nve_flood_index)207 int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
208 				     u32 nve_flood_index)
209 {
210 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
211 	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
212 	int err;
213 
214 	if (WARN_ON(fid->nve_flood_index_valid))
215 		return -EINVAL;
216 
217 	fid->nve_flood_index = nve_flood_index;
218 	fid->nve_flood_index_valid = true;
219 	err = ops->nve_flood_index_set(fid);
220 	if (err)
221 		goto err_nve_flood_index_set;
222 
223 	return 0;
224 
225 err_nve_flood_index_set:
226 	fid->nve_flood_index_valid = false;
227 	return err;
228 }
229 
mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid * fid)230 void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
231 {
232 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
233 	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
234 
235 	if (WARN_ON(!fid->nve_flood_index_valid))
236 		return;
237 
238 	fid->nve_flood_index_valid = false;
239 	ops->nve_flood_index_clear(fid);
240 }
241 
mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid * fid)242 bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
243 {
244 	return fid->nve_flood_index_valid;
245 }
246 
mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid * fid,enum mlxsw_sp_nve_type type,__be32 vni,int nve_ifindex)247 int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type,
248 			 __be32 vni, int nve_ifindex)
249 {
250 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
251 	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
252 	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
253 	int err;
254 
255 	if (WARN_ON(fid->vni_valid))
256 		return -EINVAL;
257 
258 	fid->nve_type = type;
259 	fid->nve_ifindex = nve_ifindex;
260 	fid->vni = vni;
261 	err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht,
262 					    &fid->vni_ht_node,
263 					    mlxsw_sp_fid_vni_ht_params);
264 	if (err)
265 		return err;
266 
267 	fid->vni_valid = true;
268 	err = ops->vni_set(fid);
269 	if (err)
270 		goto err_vni_set;
271 
272 	return 0;
273 
274 err_vni_set:
275 	fid->vni_valid = false;
276 	rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
277 			       mlxsw_sp_fid_vni_ht_params);
278 	return err;
279 }
280 
mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid * fid)281 void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid)
282 {
283 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
284 	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
285 	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
286 
287 	if (WARN_ON(!fid->vni_valid))
288 		return;
289 
290 	fid->vni_valid = false;
291 	ops->vni_clear(fid);
292 	rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
293 			       mlxsw_sp_fid_vni_ht_params);
294 }
295 
mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid * fid)296 bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
297 {
298 	return fid->vni_valid;
299 }
300 
mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid * fid,const struct net_device * nve_dev)301 void mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
302 				    const struct net_device *nve_dev)
303 {
304 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
305 	const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
306 
307 	if (ops->fdb_clear_offload)
308 		ops->fdb_clear_offload(fid, nve_dev);
309 }
310 
311 static const struct mlxsw_sp_flood_table *
mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid * fid,enum mlxsw_sp_flood_type packet_type)312 mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
313 				enum mlxsw_sp_flood_type packet_type)
314 {
315 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
316 	int i;
317 
318 	for (i = 0; i < fid_family->nr_flood_tables; i++) {
319 		if (fid_family->flood_tables[i].packet_type != packet_type)
320 			continue;
321 		return &fid_family->flood_tables[i];
322 	}
323 
324 	return NULL;
325 }
326 
327 static u16
mlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family * fid_family)328 mlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family *fid_family)
329 {
330 	return fid_family->end_index - fid_family->start_index + 1;
331 }
332 
333 static u16
mlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family * fid_family,const struct mlxsw_sp_flood_table * flood_table,u16 fid_offset)334 mlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family *fid_family,
335 			     const struct mlxsw_sp_flood_table *flood_table,
336 			     u16 fid_offset)
337 {
338 	u16 num_fids;
339 
340 	num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
341 	return fid_family->pgt_base + num_fids * flood_table->table_index +
342 	       fid_offset;
343 }
344 
mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid * fid,enum mlxsw_sp_flood_type packet_type,u16 local_port,bool member)345 int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
346 			   enum mlxsw_sp_flood_type packet_type, u16 local_port,
347 			   bool member)
348 {
349 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
350 	const struct mlxsw_sp_flood_table *flood_table;
351 	u16 mid_index;
352 
353 	if (WARN_ON(!fid_family->flood_tables))
354 		return -EINVAL;
355 
356 	flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
357 	if (!flood_table)
358 		return -ESRCH;
359 
360 	mid_index = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table,
361 						 fid->fid_offset);
362 	return mlxsw_sp_pgt_entry_port_set(fid_family->mlxsw_sp, mid_index,
363 					   fid->fid_index, local_port, member);
364 }
365 
mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)366 int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
367 			      struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
368 {
369 	if (WARN_ON(!fid->fid_family->ops->port_vid_map))
370 		return -EINVAL;
371 	return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);
372 }
373 
mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)374 void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
375 				 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
376 {
377 	fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
378 }
379 
mlxsw_sp_fid_index(const struct mlxsw_sp_fid * fid)380 u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
381 {
382 	return fid->fid_index;
383 }
384 
mlxsw_sp_fid_type(const struct mlxsw_sp_fid * fid)385 enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
386 {
387 	return fid->fid_family->type;
388 }
389 
mlxsw_sp_fid_rif(const struct mlxsw_sp_fid * fid)390 struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
391 {
392 	return fid->rif;
393 }
394 
395 enum mlxsw_sp_rif_type
mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_fid_type type)396 mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
397 			   enum mlxsw_sp_fid_type type)
398 {
399 	struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
400 
401 	return fid_core->fid_family_arr[type]->rif_type;
402 }
403 
404 static struct mlxsw_sp_fid_8021q *
mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid * fid)405 mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
406 {
407 	return container_of(fid, struct mlxsw_sp_fid_8021q, common);
408 }
409 
mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid * fid)410 u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
411 {
412 	return mlxsw_sp_fid_8021q_fid(fid)->vid;
413 }
414 
mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid * fid,const void * arg)415 static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
416 {
417 	u16 vid = *(u16 *) arg;
418 
419 	mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
420 	fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
421 }
422 
mlxsw_sp_sfmr_op(bool valid)423 static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
424 {
425 	return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
426 		       MLXSW_REG_SFMR_OP_DESTROY_FID;
427 }
428 
mlxsw_sp_fid_op(const struct mlxsw_sp_fid * fid,bool valid)429 static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid)
430 {
431 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
432 	char sfmr_pl[MLXSW_REG_SFMR_LEN];
433 	u16 smpe;
434 
435 	smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;
436 
437 	mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid->fid_index,
438 			    fid->fid_offset, fid->fid_family->flood_rsp,
439 			    fid->fid_family->bridge_type,
440 			    fid->fid_family->smpe_index_valid, smpe);
441 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
442 }
443 
mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)444 static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid,
445 				const struct mlxsw_sp_rif *rif)
446 {
447 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
448 	char sfmr_pl[MLXSW_REG_SFMR_LEN];
449 	u16 smpe;
450 
451 	smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;
452 
453 	mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID,
454 			    fid->fid_index, fid->fid_offset,
455 			    fid->fid_family->flood_rsp,
456 			    fid->fid_family->bridge_type,
457 			    fid->fid_family->smpe_index_valid, smpe);
458 	mlxsw_reg_sfmr_vv_set(sfmr_pl, fid->vni_valid);
459 	mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(fid->vni));
460 	mlxsw_reg_sfmr_vtfp_set(sfmr_pl, fid->nve_flood_index_valid);
461 	mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, fid->nve_flood_index);
462 
463 	if (rif) {
464 		mlxsw_reg_sfmr_irif_v_set(sfmr_pl, true);
465 		mlxsw_reg_sfmr_irif_set(sfmr_pl, mlxsw_sp_rif_index(rif));
466 	}
467 
468 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
469 }
470 
mlxsw_sp_fid_vni_to_fid_map(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif,bool valid)471 static int mlxsw_sp_fid_vni_to_fid_map(const struct mlxsw_sp_fid *fid,
472 				       const struct mlxsw_sp_rif *rif,
473 				       bool valid)
474 {
475 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
476 	char svfa_pl[MLXSW_REG_SVFA_LEN];
477 	bool irif_valid;
478 	u16 irif_index;
479 
480 	irif_valid = !!rif;
481 	irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
482 
483 	mlxsw_reg_svfa_vni_pack(svfa_pl, valid, fid->fid_index,
484 				be32_to_cpu(fid->vni), irif_valid, irif_index);
485 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
486 }
487 
mlxsw_sp_fid_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)488 static int mlxsw_sp_fid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
489 					  const struct mlxsw_sp_rif *rif)
490 {
491 	return mlxsw_sp_fid_edit_op(fid, rif);
492 }
493 
mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)494 static int mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
495 					      const struct mlxsw_sp_rif *rif)
496 {
497 	if (!fid->vni_valid)
498 		return 0;
499 
500 	return mlxsw_sp_fid_vni_to_fid_map(fid, rif, fid->vni_valid);
501 }
502 
503 static int
mlxsw_sp_fid_vid_to_fid_map(const struct mlxsw_sp_fid * fid,u16 vid,bool valid,const struct mlxsw_sp_rif * rif)504 mlxsw_sp_fid_vid_to_fid_map(const struct mlxsw_sp_fid *fid, u16 vid, bool valid,
505 			    const struct mlxsw_sp_rif *rif)
506 {
507 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
508 	char svfa_pl[MLXSW_REG_SVFA_LEN];
509 	bool irif_valid;
510 	u16 irif_index;
511 
512 	irif_valid = !!rif;
513 	irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
514 
515 	mlxsw_reg_svfa_vid_pack(svfa_pl, valid, fid->fid_index, vid, irif_valid,
516 				irif_index);
517 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
518 }
519 
520 static int
mlxsw_sp_fid_8021q_vid_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)521 mlxsw_sp_fid_8021q_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
522 					 const struct mlxsw_sp_rif *rif)
523 {
524 	struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
525 
526 	/* Update the global VID => FID mapping we created when the FID was
527 	 * configured.
528 	 */
529 	return mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, rif);
530 }
531 
532 static int
mlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid * fid,struct mlxsw_sp_fid_port_vid * pv,bool irif_valid,u16 irif_index)533 mlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid *fid,
534 					    struct mlxsw_sp_fid_port_vid *pv,
535 					    bool irif_valid, u16 irif_index)
536 {
537 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
538 	char svfa_pl[MLXSW_REG_SVFA_LEN];
539 
540 	mlxsw_reg_svfa_port_vid_pack(svfa_pl, pv->local_port, true,
541 				     fid->fid_index, pv->vid, irif_valid,
542 				     irif_index);
543 
544 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
545 }
546 
mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)547 static int mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid *fid,
548 					   const struct mlxsw_sp_rif *rif)
549 {
550 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
551 	struct mlxsw_sp_fid_port_vid *pv;
552 	u16 irif_index;
553 	int err;
554 
555 	err = fid->fid_family->ops->vid_to_fid_rif_update(fid, rif);
556 	if (err)
557 		return err;
558 
559 	irif_index = mlxsw_sp_rif_index(rif);
560 
561 	list_for_each_entry(pv, &fid->port_vid_list, list) {
562 		/* If port is not in virtual mode, then it does not have any
563 		 * {Port, VID}->FID mappings that need to be updated with the
564 		 * ingress RIF.
565 		 */
566 		if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
567 			continue;
568 
569 		err = mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv,
570 								  true,
571 								  irif_index);
572 		if (err)
573 			goto err_port_vid_to_fid_rif_update_one;
574 	}
575 
576 	return 0;
577 
578 err_port_vid_to_fid_rif_update_one:
579 	list_for_each_entry_continue_reverse(pv, &fid->port_vid_list, list) {
580 		if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
581 			continue;
582 
583 		mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
584 	}
585 
586 	fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
587 	return err;
588 }
589 
mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid * fid)590 static void mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid *fid)
591 {
592 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
593 	struct mlxsw_sp_fid_port_vid *pv;
594 
595 	list_for_each_entry(pv, &fid->port_vid_list, list) {
596 		/* If port is not in virtual mode, then it does not have any
597 		 * {Port, VID}->FID mappings that need to be updated.
598 		 */
599 		if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
600 			continue;
601 
602 		mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0);
603 	}
604 
605 	fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
606 }
607 
mlxsw_sp_fid_reiv_handle(struct mlxsw_sp_fid * fid,u16 rif_index,bool valid,u8 port_page)608 static int mlxsw_sp_fid_reiv_handle(struct mlxsw_sp_fid *fid, u16 rif_index,
609 				    bool valid, u8 port_page)
610 {
611 	u16 local_port_end = (port_page + 1) * MLXSW_REG_REIV_REC_MAX_COUNT - 1;
612 	u16 local_port_start = port_page * MLXSW_REG_REIV_REC_MAX_COUNT;
613 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
614 	struct mlxsw_sp_fid_port_vid *port_vid;
615 	u8 rec_num, entries_num = 0;
616 	char *reiv_pl;
617 	int err;
618 
619 	reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
620 	if (!reiv_pl)
621 		return -ENOMEM;
622 
623 	mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);
624 
625 	list_for_each_entry(port_vid, &fid->port_vid_list, list) {
626 		/* port_vid_list is sorted by local_port. */
627 		if (port_vid->local_port < local_port_start)
628 			continue;
629 
630 		if (port_vid->local_port > local_port_end)
631 			break;
632 
633 		rec_num = port_vid->local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
634 		mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);
635 		mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num,
636 					    valid ? port_vid->vid : 0);
637 		entries_num++;
638 	}
639 
640 	if (!entries_num) {
641 		kfree(reiv_pl);
642 		return 0;
643 	}
644 
645 	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);
646 	if (err)
647 		goto err_reg_write;
648 
649 	kfree(reiv_pl);
650 	return 0;
651 
652 err_reg_write:
653 	kfree(reiv_pl);
654 	return err;
655 }
656 
mlxsw_sp_fid_erif_eport_to_vid_map(struct mlxsw_sp_fid * fid,u16 rif_index,bool valid)657 static int mlxsw_sp_fid_erif_eport_to_vid_map(struct mlxsw_sp_fid *fid,
658 					      u16 rif_index, bool valid)
659 {
660 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
661 	u8 num_port_pages;
662 	int err, i;
663 
664 	num_port_pages = mlxsw_core_max_ports(mlxsw_sp->core) /
665 			 MLXSW_REG_REIV_REC_MAX_COUNT + 1;
666 
667 	for (i = 0; i < num_port_pages; i++) {
668 		err = mlxsw_sp_fid_reiv_handle(fid, rif_index, valid, i);
669 		if (err)
670 			goto err_reiv_handle;
671 	}
672 
673 	return 0;
674 
675 err_reiv_handle:
676 	for (; i >= 0; i--)
677 		mlxsw_sp_fid_reiv_handle(fid, rif_index, !valid, i);
678 	return err;
679 }
680 
mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid * fid,struct mlxsw_sp_rif * rif)681 int mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
682 {
683 	u16 rif_index = mlxsw_sp_rif_index(rif);
684 	int err;
685 
686 	err = mlxsw_sp_fid_to_fid_rif_update(fid, rif);
687 	if (err)
688 		return err;
689 
690 	err = mlxsw_sp_fid_vni_to_fid_rif_update(fid, rif);
691 	if (err)
692 		goto err_vni_to_fid_rif_update;
693 
694 	err = mlxsw_sp_fid_vid_to_fid_rif_set(fid, rif);
695 	if (err)
696 		goto err_vid_to_fid_rif_set;
697 
698 	err = mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, true);
699 	if (err)
700 		goto err_erif_eport_to_vid_map;
701 
702 	fid->rif = rif;
703 	return 0;
704 
705 err_erif_eport_to_vid_map:
706 	mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
707 err_vid_to_fid_rif_set:
708 	mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
709 err_vni_to_fid_rif_update:
710 	mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
711 	return err;
712 }
713 
mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid * fid)714 void mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid *fid)
715 {
716 	u16 rif_index;
717 
718 	if (!fid->rif)
719 		return;
720 
721 	rif_index = mlxsw_sp_rif_index(fid->rif);
722 	fid->rif = NULL;
723 
724 	mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, false);
725 	mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
726 	mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
727 	mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
728 }
729 
mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid * fid)730 static int mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid *fid)
731 {
732 	int err;
733 
734 	err = mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, fid->vni_valid);
735 	if (err)
736 		return err;
737 
738 	err = mlxsw_sp_fid_edit_op(fid, fid->rif);
739 	if (err)
740 		goto err_fid_edit_op;
741 
742 	return 0;
743 
744 err_fid_edit_op:
745 	mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, !fid->vni_valid);
746 	return err;
747 }
748 
__mlxsw_sp_fid_port_vid_map(const struct mlxsw_sp_fid * fid,u16 local_port,u16 vid,bool valid)749 static int __mlxsw_sp_fid_port_vid_map(const struct mlxsw_sp_fid *fid,
750 				       u16 local_port, u16 vid, bool valid)
751 {
752 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
753 	char svfa_pl[MLXSW_REG_SVFA_LEN];
754 	bool irif_valid = false;
755 	u16 irif_index = 0;
756 
757 	if (fid->rif) {
758 		irif_valid = true;
759 		irif_index = mlxsw_sp_rif_index(fid->rif);
760 	}
761 
762 	mlxsw_reg_svfa_port_vid_pack(svfa_pl, local_port, valid, fid->fid_index,
763 				     vid, irif_valid, irif_index);
764 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
765 }
766 
767 static struct mlxsw_sp_fid_8021d *
mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid * fid)768 mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
769 {
770 	return container_of(fid, struct mlxsw_sp_fid_8021d, common);
771 }
772 
mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid * fid,const void * arg)773 static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
774 {
775 	int br_ifindex = *(int *) arg;
776 
777 	mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
778 	fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
779 }
780 
mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid * fid)781 static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
782 {
783 	return mlxsw_sp_fid_op(fid, true);
784 }
785 
mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid * fid)786 static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
787 {
788 	if (fid->vni_valid)
789 		mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
790 	mlxsw_sp_fid_op(fid, false);
791 }
792 
mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid * fid,const void * arg,u16 * p_fid_index)793 static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
794 					  const void *arg, u16 *p_fid_index)
795 {
796 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
797 	u16 nr_fids, fid_index;
798 
799 	nr_fids = fid_family->end_index - fid_family->start_index + 1;
800 	fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);
801 	if (fid_index == nr_fids)
802 		return -ENOBUFS;
803 	*p_fid_index = fid_family->start_index + fid_index;
804 
805 	return 0;
806 }
807 
808 static bool
mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid * fid,const void * arg)809 mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
810 {
811 	int br_ifindex = *(int *) arg;
812 
813 	return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
814 }
815 
mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port * mlxsw_sp_port)816 static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
817 {
818 	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
819 	int err;
820 
821 	list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
822 			    list) {
823 		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
824 		u16 vid = mlxsw_sp_port_vlan->vid;
825 
826 		if (!fid)
827 			continue;
828 
829 		err = __mlxsw_sp_fid_port_vid_map(fid,
830 						  mlxsw_sp_port->local_port,
831 						  vid, true);
832 		if (err)
833 			goto err_fid_port_vid_map;
834 	}
835 
836 	err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
837 	if (err)
838 		goto err_port_vp_mode_set;
839 
840 	return 0;
841 
842 err_port_vp_mode_set:
843 err_fid_port_vid_map:
844 	list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
845 					     &mlxsw_sp_port->vlans_list, list) {
846 		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
847 		u16 vid = mlxsw_sp_port_vlan->vid;
848 
849 		if (!fid)
850 			continue;
851 
852 		__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
853 					    false);
854 	}
855 	return err;
856 }
857 
mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port * mlxsw_sp_port)858 static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
859 {
860 	struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
861 
862 	mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
863 
864 	list_for_each_entry_reverse(mlxsw_sp_port_vlan,
865 				    &mlxsw_sp_port->vlans_list, list) {
866 		struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
867 		u16 vid = mlxsw_sp_port_vlan->vid;
868 
869 		if (!fid)
870 			continue;
871 
872 		__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
873 					    false);
874 	}
875 }
876 
877 static int
mlxsw_sp_fid_port_vid_list_add(struct mlxsw_sp_fid * fid,u16 local_port,u16 vid)878 mlxsw_sp_fid_port_vid_list_add(struct mlxsw_sp_fid *fid, u16 local_port,
879 			       u16 vid)
880 {
881 	struct mlxsw_sp_fid_port_vid *port_vid, *tmp_port_vid;
882 
883 	port_vid = kzalloc(sizeof(*port_vid), GFP_KERNEL);
884 	if (!port_vid)
885 		return -ENOMEM;
886 
887 	port_vid->local_port = local_port;
888 	port_vid->vid = vid;
889 
890 	list_for_each_entry(tmp_port_vid, &fid->port_vid_list, list) {
891 		if (tmp_port_vid->local_port > local_port)
892 			break;
893 	}
894 
895 	list_add_tail(&port_vid->list, &tmp_port_vid->list);
896 	return 0;
897 }
898 
899 static void
mlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid * fid,u16 local_port,u16 vid)900 mlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid *fid, u16 local_port,
901 			       u16 vid)
902 {
903 	struct mlxsw_sp_fid_port_vid *port_vid, *tmp;
904 
905 	list_for_each_entry_safe(port_vid, tmp, &fid->port_vid_list, list) {
906 		if (port_vid->local_port != local_port || port_vid->vid != vid)
907 			continue;
908 
909 		list_del(&port_vid->list);
910 		kfree(port_vid);
911 		return;
912 	}
913 }
914 
915 static int
mlxsw_sp_fid_mpe_table_map(const struct mlxsw_sp_fid * fid,u16 local_port,u16 vid,bool valid)916 mlxsw_sp_fid_mpe_table_map(const struct mlxsw_sp_fid *fid, u16 local_port,
917 			   u16 vid, bool valid)
918 {
919 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
920 	char smpe_pl[MLXSW_REG_SMPE_LEN];
921 
922 	mlxsw_reg_smpe_pack(smpe_pl, local_port, fid->fid_index,
923 			    valid ? vid : 0);
924 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smpe), smpe_pl);
925 }
926 
927 static int
mlxsw_sp_fid_erif_eport_to_vid_map_one(const struct mlxsw_sp_fid * fid,u16 local_port,u16 vid,bool valid)928 mlxsw_sp_fid_erif_eport_to_vid_map_one(const struct mlxsw_sp_fid *fid,
929 				       u16 local_port, u16 vid, bool valid)
930 {
931 	u8 port_page = local_port / MLXSW_REG_REIV_REC_MAX_COUNT;
932 	u8 rec_num = local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
933 	struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
934 	u16 rif_index = mlxsw_sp_rif_index(fid->rif);
935 	char *reiv_pl;
936 	int err;
937 
938 	reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
939 	if (!reiv_pl)
940 		return -ENOMEM;
941 
942 	mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index);
943 	mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true);
944 	mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num, valid ? vid : 0);
945 	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl);
946 	kfree(reiv_pl);
947 	return err;
948 }
949 
mlxsw_sp_fid_evid_map(const struct mlxsw_sp_fid * fid,u16 local_port,u16 vid,bool valid)950 static int mlxsw_sp_fid_evid_map(const struct mlxsw_sp_fid *fid, u16 local_port,
951 				 u16 vid, bool valid)
952 {
953 	int err;
954 
955 	err = mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, valid);
956 	if (err)
957 		return err;
958 
959 	if (!fid->rif)
960 		return 0;
961 
962 	err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
963 						     valid);
964 	if (err)
965 		goto err_erif_eport_to_vid_map_one;
966 
967 	return 0;
968 
969 err_erif_eport_to_vid_map_one:
970 	mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, !valid);
971 	return err;
972 }
973 
mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)974 static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
975 					   struct mlxsw_sp_port *mlxsw_sp_port,
976 					   u16 vid)
977 {
978 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
979 	u16 local_port = mlxsw_sp_port->local_port;
980 	int err;
981 
982 	err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
983 					  true);
984 	if (err)
985 		return err;
986 
987 	err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);
988 	if (err)
989 		goto err_fid_evid_map;
990 
991 	err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
992 					     vid);
993 	if (err)
994 		goto err_port_vid_list_add;
995 
996 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
997 		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
998 		if (err)
999 			goto err_port_vp_mode_trans;
1000 	}
1001 
1002 	return 0;
1003 
1004 err_port_vp_mode_trans:
1005 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
1006 	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1007 err_port_vid_list_add:
1008 	mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
1009 err_fid_evid_map:
1010 	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1011 	return err;
1012 }
1013 
1014 static void
mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1015 mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
1016 				  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
1017 {
1018 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1019 	u16 local_port = mlxsw_sp_port->local_port;
1020 
1021 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
1022 		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
1023 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
1024 	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1025 	mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
1026 	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1027 }
1028 
mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid * fid)1029 static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid)
1030 {
1031 	return mlxsw_sp_fid_vni_op(fid);
1032 }
1033 
mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid * fid)1034 static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
1035 {
1036 	mlxsw_sp_fid_vni_op(fid);
1037 }
1038 
mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid * fid)1039 static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1040 {
1041 	return mlxsw_sp_fid_edit_op(fid, fid->rif);
1042 }
1043 
mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid * fid)1044 static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1045 {
1046 	mlxsw_sp_fid_edit_op(fid, fid->rif);
1047 }
1048 
1049 static void
mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid * fid,const struct net_device * nve_dev)1050 mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
1051 				     const struct net_device *nve_dev)
1052 {
1053 	br_fdb_clear_offload(nve_dev, 0);
1054 }
1055 
1056 static int
mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)1057 mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
1058 					 const struct mlxsw_sp_rif *rif)
1059 {
1060 	return 0;
1061 }
1062 
1063 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
1064 	.setup			= mlxsw_sp_fid_8021d_setup,
1065 	.configure		= mlxsw_sp_fid_8021d_configure,
1066 	.deconfigure		= mlxsw_sp_fid_8021d_deconfigure,
1067 	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,
1068 	.compare		= mlxsw_sp_fid_8021d_compare,
1069 	.port_vid_map		= mlxsw_sp_fid_8021d_port_vid_map,
1070 	.port_vid_unmap		= mlxsw_sp_fid_8021d_port_vid_unmap,
1071 	.vni_set		= mlxsw_sp_fid_8021d_vni_set,
1072 	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,
1073 	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,
1074 	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,
1075 	.fdb_clear_offload	= mlxsw_sp_fid_8021d_fdb_clear_offload,
1076 	.vid_to_fid_rif_update  = mlxsw_sp_fid_8021d_vid_to_fid_rif_update,
1077 };
1078 
1079 #define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2)
1080 #define MLXSW_SP_FID_RFID_MAX (11 * 1024)
1081 #define MLXSW_SP_FID_8021Q_PGT_BASE 0
1082 #define MLXSW_SP_FID_8021D_PGT_BASE (3 * MLXSW_SP_FID_8021Q_MAX)
1083 
1084 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
1085 	{
1086 		.packet_type	= MLXSW_SP_FLOOD_TYPE_UC,
1087 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
1088 		.table_index	= 0,
1089 	},
1090 	{
1091 		.packet_type	= MLXSW_SP_FLOOD_TYPE_MC,
1092 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
1093 		.table_index	= 1,
1094 	},
1095 	{
1096 		.packet_type	= MLXSW_SP_FLOOD_TYPE_BC,
1097 		.table_type	= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
1098 		.table_index	= 2,
1099 	},
1100 };
1101 
1102 static bool
mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid * fid,const void * arg)1103 mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
1104 {
1105 	u16 vid = *(u16 *) arg;
1106 
1107 	return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
1108 }
1109 
1110 static void
mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid * fid,const struct net_device * nve_dev)1111 mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
1112 				     const struct net_device *nve_dev)
1113 {
1114 	br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid));
1115 }
1116 
mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid * fid,const void * arg)1117 static void mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid *fid, const void *arg)
1118 {
1119 	fid->fid_offset = 0;
1120 }
1121 
mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid * fid)1122 static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
1123 {
1124 	return mlxsw_sp_fid_op(fid, true);
1125 }
1126 
mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid * fid)1127 static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
1128 {
1129 	mlxsw_sp_fid_op(fid, false);
1130 }
1131 
mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid * fid,const void * arg,u16 * p_fid_index)1132 static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
1133 					 const void *arg, u16 *p_fid_index)
1134 {
1135 	u16 rif_index = *(u16 *) arg;
1136 
1137 	*p_fid_index = fid->fid_family->start_index + rif_index;
1138 
1139 	return 0;
1140 }
1141 
mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid * fid,const void * arg)1142 static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
1143 				      const void *arg)
1144 {
1145 	u16 rif_index = *(u16 *) arg;
1146 
1147 	return fid->fid_index == rif_index + fid->fid_family->start_index;
1148 }
1149 
mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1150 static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
1151 					  struct mlxsw_sp_port *mlxsw_sp_port,
1152 					  u16 vid)
1153 {
1154 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1155 	u16 local_port = mlxsw_sp_port->local_port;
1156 	int err;
1157 
1158 	err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
1159 					     vid);
1160 	if (err)
1161 		return err;
1162 
1163 	/* Using legacy bridge model, we only need to transition the port to
1164 	 * virtual mode since {Port, VID} => FID is done by the firmware upon
1165 	 * RIF creation. Using unified bridge model, we need to map
1166 	 * {Port, VID} => FID and map egress VID.
1167 	 */
1168 	err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid,
1169 					  true);
1170 	if (err)
1171 		goto err_port_vid_map;
1172 
1173 	if (fid->rif) {
1174 		err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port,
1175 							     vid, true);
1176 		if (err)
1177 			goto err_erif_eport_to_vid_map_one;
1178 	}
1179 
1180 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
1181 		err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
1182 		if (err)
1183 			goto err_port_vp_mode_trans;
1184 	}
1185 
1186 	return 0;
1187 
1188 err_port_vp_mode_trans:
1189 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
1190 	if (fid->rif)
1191 		mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
1192 						       false);
1193 err_erif_eport_to_vid_map_one:
1194 	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1195 err_port_vid_map:
1196 	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1197 	return err;
1198 }
1199 
1200 static void
mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1201 mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
1202 				 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
1203 {
1204 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1205 	u16 local_port = mlxsw_sp_port->local_port;
1206 
1207 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
1208 		mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
1209 	mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
1210 
1211 	if (fid->rif)
1212 		mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
1213 						       false);
1214 	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1215 	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1216 }
1217 
mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid * fid)1218 static int mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid *fid)
1219 {
1220 	return -EOPNOTSUPP;
1221 }
1222 
mlxsw_sp_fid_rfid_vni_clear(struct mlxsw_sp_fid * fid)1223 static void mlxsw_sp_fid_rfid_vni_clear(struct mlxsw_sp_fid *fid)
1224 {
1225 	WARN_ON_ONCE(1);
1226 }
1227 
mlxsw_sp_fid_rfid_nve_flood_index_set(struct mlxsw_sp_fid * fid)1228 static int mlxsw_sp_fid_rfid_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1229 {
1230 	return -EOPNOTSUPP;
1231 }
1232 
mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid * fid)1233 static void mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1234 {
1235 	WARN_ON_ONCE(1);
1236 }
1237 
1238 static int
mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid * fid,const struct mlxsw_sp_rif * rif)1239 mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
1240 					const struct mlxsw_sp_rif *rif)
1241 {
1242 	return 0;
1243 }
1244 
1245 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
1246 	.setup			= mlxsw_sp_fid_rfid_setup,
1247 	.configure		= mlxsw_sp_fid_rfid_configure,
1248 	.deconfigure		= mlxsw_sp_fid_rfid_deconfigure,
1249 	.index_alloc		= mlxsw_sp_fid_rfid_index_alloc,
1250 	.compare		= mlxsw_sp_fid_rfid_compare,
1251 	.port_vid_map		= mlxsw_sp_fid_rfid_port_vid_map,
1252 	.port_vid_unmap		= mlxsw_sp_fid_rfid_port_vid_unmap,
1253 	.vni_set                = mlxsw_sp_fid_rfid_vni_set,
1254 	.vni_clear		= mlxsw_sp_fid_rfid_vni_clear,
1255 	.nve_flood_index_set	= mlxsw_sp_fid_rfid_nve_flood_index_set,
1256 	.nve_flood_index_clear	= mlxsw_sp_fid_rfid_nve_flood_index_clear,
1257 	.vid_to_fid_rif_update  = mlxsw_sp_fid_rfid_vid_to_fid_rif_update,
1258 };
1259 
mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid * fid,const void * arg)1260 static void mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg)
1261 {
1262 	fid->fid_offset = 0;
1263 }
1264 
mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid * fid)1265 static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
1266 {
1267 	return mlxsw_sp_fid_op(fid, true);
1268 }
1269 
mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid * fid)1270 static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
1271 {
1272 	mlxsw_sp_fid_op(fid, false);
1273 }
1274 
mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid * fid,const void * arg,u16 * p_fid_index)1275 static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
1276 					  const void *arg, u16 *p_fid_index)
1277 {
1278 	*p_fid_index = fid->fid_family->start_index;
1279 
1280 	return 0;
1281 }
1282 
mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid * fid,const void * arg)1283 static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
1284 				       const void *arg)
1285 {
1286 	return true;
1287 }
1288 
mlxsw_sp_fid_dummy_vni_set(struct mlxsw_sp_fid * fid)1289 static int mlxsw_sp_fid_dummy_vni_set(struct mlxsw_sp_fid *fid)
1290 {
1291 	return -EOPNOTSUPP;
1292 }
1293 
mlxsw_sp_fid_dummy_vni_clear(struct mlxsw_sp_fid * fid)1294 static void mlxsw_sp_fid_dummy_vni_clear(struct mlxsw_sp_fid *fid)
1295 {
1296 	WARN_ON_ONCE(1);
1297 }
1298 
mlxsw_sp_fid_dummy_nve_flood_index_set(struct mlxsw_sp_fid * fid)1299 static int mlxsw_sp_fid_dummy_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1300 {
1301 	return -EOPNOTSUPP;
1302 }
1303 
mlxsw_sp_fid_dummy_nve_flood_index_clear(struct mlxsw_sp_fid * fid)1304 static void mlxsw_sp_fid_dummy_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1305 {
1306 	WARN_ON_ONCE(1);
1307 }
1308 
1309 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
1310 	.setup			= mlxsw_sp_fid_dummy_setup,
1311 	.configure		= mlxsw_sp_fid_dummy_configure,
1312 	.deconfigure		= mlxsw_sp_fid_dummy_deconfigure,
1313 	.index_alloc		= mlxsw_sp_fid_dummy_index_alloc,
1314 	.compare		= mlxsw_sp_fid_dummy_compare,
1315 	.vni_set                = mlxsw_sp_fid_dummy_vni_set,
1316 	.vni_clear		= mlxsw_sp_fid_dummy_vni_clear,
1317 	.nve_flood_index_set	= mlxsw_sp_fid_dummy_nve_flood_index_set,
1318 	.nve_flood_index_clear	= mlxsw_sp_fid_dummy_nve_flood_index_clear,
1319 };
1320 
mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid * fid)1321 static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
1322 {
1323 	struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
1324 	int err;
1325 
1326 	err = mlxsw_sp_fid_op(fid, true);
1327 	if (err)
1328 		return err;
1329 
1330 	err = mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, fid->rif);
1331 	if (err)
1332 		goto err_vid_to_fid_map;
1333 
1334 	return 0;
1335 
1336 err_vid_to_fid_map:
1337 	mlxsw_sp_fid_op(fid, false);
1338 	return err;
1339 }
1340 
mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid * fid)1341 static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)
1342 {
1343 	struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
1344 
1345 	if (fid->vni_valid)
1346 		mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
1347 
1348 	mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, false, NULL);
1349 	mlxsw_sp_fid_op(fid, false);
1350 }
1351 
mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1352 static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,
1353 					   struct mlxsw_sp_port *mlxsw_sp_port,
1354 					   u16 vid)
1355 {
1356 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1357 	u16 local_port = mlxsw_sp_port->local_port;
1358 	int err;
1359 
1360 	/* In case there are no {Port, VID} => FID mappings on the port,
1361 	 * we can use the global VID => FID mapping we created when the
1362 	 * FID was configured, otherwise, configure new mapping.
1363 	 */
1364 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port]) {
1365 		err =  __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, true);
1366 		if (err)
1367 			return err;
1368 	}
1369 
1370 	err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true);
1371 	if (err)
1372 		goto err_fid_evid_map;
1373 
1374 	err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port,
1375 					     vid);
1376 	if (err)
1377 		goto err_port_vid_list_add;
1378 
1379 	return 0;
1380 
1381 err_port_vid_list_add:
1382 	 mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
1383 err_fid_evid_map:
1384 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
1385 		__mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
1386 	return err;
1387 }
1388 
1389 static void
mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid * fid,struct mlxsw_sp_port * mlxsw_sp_port,u16 vid)1390 mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
1391 				  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
1392 {
1393 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1394 	u16 local_port = mlxsw_sp_port->local_port;
1395 
1396 	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1397 	mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
1398 	if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
1399 		__mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false);
1400 }
1401 
1402 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
1403 	.setup			= mlxsw_sp_fid_8021q_setup,
1404 	.configure		= mlxsw_sp_fid_8021q_configure,
1405 	.deconfigure		= mlxsw_sp_fid_8021q_deconfigure,
1406 	.index_alloc		= mlxsw_sp_fid_8021d_index_alloc,
1407 	.compare		= mlxsw_sp_fid_8021q_compare,
1408 	.port_vid_map		= mlxsw_sp_fid_8021q_port_vid_map,
1409 	.port_vid_unmap		= mlxsw_sp_fid_8021q_port_vid_unmap,
1410 	.vni_set		= mlxsw_sp_fid_8021d_vni_set,
1411 	.vni_clear		= mlxsw_sp_fid_8021d_vni_clear,
1412 	.nve_flood_index_set	= mlxsw_sp_fid_8021d_nve_flood_index_set,
1413 	.nve_flood_index_clear	= mlxsw_sp_fid_8021d_nve_flood_index_clear,
1414 	.fdb_clear_offload	= mlxsw_sp_fid_8021q_fdb_clear_offload,
1415 	.vid_to_fid_rif_update  = mlxsw_sp_fid_8021q_vid_to_fid_rif_update,
1416 };
1417 
1418 /* There are 4K-2 802.1Q FIDs */
1419 #define MLXSW_SP_FID_8021Q_START	1 /* FID 0 is reserved. */
1420 #define MLXSW_SP_FID_8021Q_END		(MLXSW_SP_FID_8021Q_START + \
1421 					 MLXSW_SP_FID_8021Q_MAX - 1)
1422 
1423 /* There are 1K 802.1D FIDs */
1424 #define MLXSW_SP_FID_8021D_START	(MLXSW_SP_FID_8021Q_END + 1)
1425 #define MLXSW_SP_FID_8021D_END		(MLXSW_SP_FID_8021D_START + \
1426 					 MLXSW_SP_FID_8021D_MAX - 1)
1427 
1428 /* There is one dummy FID */
1429 #define MLXSW_SP_FID_DUMMY		(MLXSW_SP_FID_8021D_END + 1)
1430 
1431 /* There are 11K rFIDs */
1432 #define MLXSW_SP_RFID_START		(MLXSW_SP_FID_DUMMY + 1)
1433 #define MLXSW_SP_RFID_END		(MLXSW_SP_RFID_START + \
1434 					 MLXSW_SP_FID_RFID_MAX - 1)
1435 
1436 static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_family = {
1437 	.type			= MLXSW_SP_FID_TYPE_8021Q,
1438 	.fid_size		= sizeof(struct mlxsw_sp_fid_8021q),
1439 	.start_index		= MLXSW_SP_FID_8021Q_START,
1440 	.end_index		= MLXSW_SP_FID_8021Q_END,
1441 	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
1442 	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1443 	.rif_type		= MLXSW_SP_RIF_TYPE_VLAN,
1444 	.ops			= &mlxsw_sp_fid_8021q_ops,
1445 	.flood_rsp              = false,
1446 	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_0,
1447 	.pgt_base		= MLXSW_SP_FID_8021Q_PGT_BASE,
1448 	.smpe_index_valid	= false,
1449 };
1450 
1451 static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_family = {
1452 	.type			= MLXSW_SP_FID_TYPE_8021D,
1453 	.fid_size		= sizeof(struct mlxsw_sp_fid_8021d),
1454 	.start_index		= MLXSW_SP_FID_8021D_START,
1455 	.end_index		= MLXSW_SP_FID_8021D_END,
1456 	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
1457 	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1458 	.rif_type		= MLXSW_SP_RIF_TYPE_FID,
1459 	.ops			= &mlxsw_sp_fid_8021d_ops,
1460 	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_1,
1461 	.pgt_base		= MLXSW_SP_FID_8021D_PGT_BASE,
1462 	.smpe_index_valid       = false,
1463 };
1464 
1465 static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_dummy_family = {
1466 	.type			= MLXSW_SP_FID_TYPE_DUMMY,
1467 	.fid_size		= sizeof(struct mlxsw_sp_fid),
1468 	.start_index		= MLXSW_SP_FID_DUMMY,
1469 	.end_index		= MLXSW_SP_FID_DUMMY,
1470 	.ops			= &mlxsw_sp_fid_dummy_ops,
1471 	.smpe_index_valid       = false,
1472 };
1473 
1474 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
1475 	.type			= MLXSW_SP_FID_TYPE_RFID,
1476 	.fid_size		= sizeof(struct mlxsw_sp_fid),
1477 	.start_index		= MLXSW_SP_RFID_START,
1478 	.end_index		= MLXSW_SP_RFID_END,
1479 	.rif_type		= MLXSW_SP_RIF_TYPE_SUBPORT,
1480 	.ops			= &mlxsw_sp_fid_rfid_ops,
1481 	.flood_rsp              = true,
1482 	.smpe_index_valid       = false,
1483 };
1484 
1485 const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = {
1486 	[MLXSW_SP_FID_TYPE_8021Q]	= &mlxsw_sp1_fid_8021q_family,
1487 	[MLXSW_SP_FID_TYPE_8021D]	= &mlxsw_sp1_fid_8021d_family,
1488 	[MLXSW_SP_FID_TYPE_DUMMY]	= &mlxsw_sp1_fid_dummy_family,
1489 	[MLXSW_SP_FID_TYPE_RFID]	= &mlxsw_sp_fid_rfid_family,
1490 };
1491 
1492 static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family = {
1493 	.type			= MLXSW_SP_FID_TYPE_8021Q,
1494 	.fid_size		= sizeof(struct mlxsw_sp_fid_8021q),
1495 	.start_index		= MLXSW_SP_FID_8021Q_START,
1496 	.end_index		= MLXSW_SP_FID_8021Q_END,
1497 	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
1498 	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1499 	.rif_type		= MLXSW_SP_RIF_TYPE_VLAN,
1500 	.ops			= &mlxsw_sp_fid_8021q_ops,
1501 	.flood_rsp              = false,
1502 	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_0,
1503 	.pgt_base		= MLXSW_SP_FID_8021Q_PGT_BASE,
1504 	.smpe_index_valid	= true,
1505 };
1506 
1507 static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family = {
1508 	.type			= MLXSW_SP_FID_TYPE_8021D,
1509 	.fid_size		= sizeof(struct mlxsw_sp_fid_8021d),
1510 	.start_index		= MLXSW_SP_FID_8021D_START,
1511 	.end_index		= MLXSW_SP_FID_8021D_END,
1512 	.flood_tables		= mlxsw_sp_fid_8021d_flood_tables,
1513 	.nr_flood_tables	= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1514 	.rif_type		= MLXSW_SP_RIF_TYPE_FID,
1515 	.ops			= &mlxsw_sp_fid_8021d_ops,
1516 	.bridge_type            = MLXSW_REG_BRIDGE_TYPE_1,
1517 	.pgt_base		= MLXSW_SP_FID_8021D_PGT_BASE,
1518 	.smpe_index_valid       = true,
1519 };
1520 
1521 static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_dummy_family = {
1522 	.type			= MLXSW_SP_FID_TYPE_DUMMY,
1523 	.fid_size		= sizeof(struct mlxsw_sp_fid),
1524 	.start_index		= MLXSW_SP_FID_DUMMY,
1525 	.end_index		= MLXSW_SP_FID_DUMMY,
1526 	.ops			= &mlxsw_sp_fid_dummy_ops,
1527 	.smpe_index_valid       = false,
1528 };
1529 
1530 const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[] = {
1531 	[MLXSW_SP_FID_TYPE_8021Q]	= &mlxsw_sp2_fid_8021q_family,
1532 	[MLXSW_SP_FID_TYPE_8021D]	= &mlxsw_sp2_fid_8021d_family,
1533 	[MLXSW_SP_FID_TYPE_DUMMY]	= &mlxsw_sp2_fid_dummy_family,
1534 	[MLXSW_SP_FID_TYPE_RFID]	= &mlxsw_sp_fid_rfid_family,
1535 };
1536 
mlxsw_sp_fid_lookup(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_fid_type type,const void * arg)1537 static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,
1538 						enum mlxsw_sp_fid_type type,
1539 						const void *arg)
1540 {
1541 	struct mlxsw_sp_fid_family *fid_family;
1542 	struct mlxsw_sp_fid *fid;
1543 
1544 	fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
1545 	list_for_each_entry(fid, &fid_family->fids_list, list) {
1546 		if (!fid->fid_family->ops->compare(fid, arg))
1547 			continue;
1548 		refcount_inc(&fid->ref_count);
1549 		return fid;
1550 	}
1551 
1552 	return NULL;
1553 }
1554 
mlxsw_sp_fid_get(struct mlxsw_sp * mlxsw_sp,enum mlxsw_sp_fid_type type,const void * arg)1555 static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
1556 					     enum mlxsw_sp_fid_type type,
1557 					     const void *arg)
1558 {
1559 	struct mlxsw_sp_fid_family *fid_family;
1560 	struct mlxsw_sp_fid *fid;
1561 	u16 fid_index;
1562 	int err;
1563 
1564 	fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg);
1565 	if (fid)
1566 		return fid;
1567 
1568 	fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
1569 	fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
1570 	if (!fid)
1571 		return ERR_PTR(-ENOMEM);
1572 
1573 	INIT_LIST_HEAD(&fid->port_vid_list);
1574 	fid->fid_family = fid_family;
1575 
1576 	err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
1577 	if (err)
1578 		goto err_index_alloc;
1579 	fid->fid_index = fid_index;
1580 	__set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
1581 
1582 	fid->fid_family->ops->setup(fid, arg);
1583 
1584 	err = fid->fid_family->ops->configure(fid);
1585 	if (err)
1586 		goto err_configure;
1587 
1588 	err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node,
1589 				     mlxsw_sp_fid_ht_params);
1590 	if (err)
1591 		goto err_rhashtable_insert;
1592 
1593 	list_add(&fid->list, &fid_family->fids_list);
1594 	refcount_set(&fid->ref_count, 1);
1595 	return fid;
1596 
1597 err_rhashtable_insert:
1598 	fid->fid_family->ops->deconfigure(fid);
1599 err_configure:
1600 	__clear_bit(fid_index - fid_family->start_index,
1601 		    fid_family->fids_bitmap);
1602 err_index_alloc:
1603 	kfree(fid);
1604 	return ERR_PTR(err);
1605 }
1606 
mlxsw_sp_fid_put(struct mlxsw_sp_fid * fid)1607 void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
1608 {
1609 	struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
1610 	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1611 
1612 	if (!refcount_dec_and_test(&fid->ref_count))
1613 		return;
1614 
1615 	list_del(&fid->list);
1616 	rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht,
1617 			       &fid->ht_node, mlxsw_sp_fid_ht_params);
1618 	fid->fid_family->ops->deconfigure(fid);
1619 	__clear_bit(fid->fid_index - fid_family->start_index,
1620 		    fid_family->fids_bitmap);
1621 	WARN_ON_ONCE(!list_empty(&fid->port_vid_list));
1622 	kfree(fid);
1623 }
1624 
mlxsw_sp_fid_8021q_get(struct mlxsw_sp * mlxsw_sp,u16 vid)1625 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
1626 {
1627 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
1628 }
1629 
mlxsw_sp_fid_8021d_get(struct mlxsw_sp * mlxsw_sp,int br_ifindex)1630 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
1631 					    int br_ifindex)
1632 {
1633 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
1634 }
1635 
mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp * mlxsw_sp,u16 vid)1636 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp,
1637 					       u16 vid)
1638 {
1639 	return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
1640 }
1641 
mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp * mlxsw_sp,int br_ifindex)1642 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
1643 					       int br_ifindex)
1644 {
1645 	return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D,
1646 				   &br_ifindex);
1647 }
1648 
mlxsw_sp_fid_rfid_get(struct mlxsw_sp * mlxsw_sp,u16 rif_index)1649 struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
1650 					   u16 rif_index)
1651 {
1652 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);
1653 }
1654 
mlxsw_sp_fid_dummy_get(struct mlxsw_sp * mlxsw_sp)1655 struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
1656 {
1657 	return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);
1658 }
1659 
1660 static int
mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family * fid_family,const struct mlxsw_sp_flood_table * flood_table)1661 mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
1662 			      const struct mlxsw_sp_flood_table *flood_table)
1663 {
1664 	enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
1665 	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1666 	const int *sfgc_packet_types;
1667 	u16 num_fids, mid_base;
1668 	int err, i;
1669 
1670 	mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0);
1671 	num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
1672 	err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, mid_base, num_fids);
1673 	if (err)
1674 		return err;
1675 
1676 	sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
1677 	for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
1678 		char sfgc_pl[MLXSW_REG_SFGC_LEN];
1679 
1680 		if (!sfgc_packet_types[i])
1681 			continue;
1682 
1683 		mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type,
1684 				    flood_table->table_type, 0, mid_base);
1685 
1686 		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
1687 		if (err)
1688 			goto err_reg_write;
1689 	}
1690 
1691 	return 0;
1692 
1693 err_reg_write:
1694 	mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids);
1695 	return err;
1696 }
1697 
1698 static void
mlxsw_sp_fid_flood_table_fini(struct mlxsw_sp_fid_family * fid_family,const struct mlxsw_sp_flood_table * flood_table)1699 mlxsw_sp_fid_flood_table_fini(struct mlxsw_sp_fid_family *fid_family,
1700 			      const struct mlxsw_sp_flood_table *flood_table)
1701 {
1702 	struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1703 	u16 num_fids, mid_base;
1704 
1705 	mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0);
1706 	num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
1707 	mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids);
1708 }
1709 
1710 static int
mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family * fid_family)1711 mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
1712 {
1713 	int i;
1714 
1715 	for (i = 0; i < fid_family->nr_flood_tables; i++) {
1716 		const struct mlxsw_sp_flood_table *flood_table;
1717 		int err;
1718 
1719 		flood_table = &fid_family->flood_tables[i];
1720 		err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
1721 		if (err)
1722 			return err;
1723 	}
1724 
1725 	return 0;
1726 }
1727 
1728 static void
mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family * fid_family)1729 mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family)
1730 {
1731 	int i;
1732 
1733 	for (i = 0; i < fid_family->nr_flood_tables; i++) {
1734 		const struct mlxsw_sp_flood_table *flood_table;
1735 
1736 		flood_table = &fid_family->flood_tables[i];
1737 		mlxsw_sp_fid_flood_table_fini(fid_family, flood_table);
1738 	}
1739 }
1740 
mlxsw_sp_fid_family_register(struct mlxsw_sp * mlxsw_sp,const struct mlxsw_sp_fid_family * tmpl)1741 static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
1742 					const struct mlxsw_sp_fid_family *tmpl)
1743 {
1744 	u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
1745 	struct mlxsw_sp_fid_family *fid_family;
1746 	int err;
1747 
1748 	fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);
1749 	if (!fid_family)
1750 		return -ENOMEM;
1751 
1752 	fid_family->mlxsw_sp = mlxsw_sp;
1753 	INIT_LIST_HEAD(&fid_family->fids_list);
1754 	fid_family->fids_bitmap = bitmap_zalloc(nr_fids, GFP_KERNEL);
1755 	if (!fid_family->fids_bitmap) {
1756 		err = -ENOMEM;
1757 		goto err_alloc_fids_bitmap;
1758 	}
1759 
1760 	if (fid_family->flood_tables) {
1761 		err = mlxsw_sp_fid_flood_tables_init(fid_family);
1762 		if (err)
1763 			goto err_fid_flood_tables_init;
1764 	}
1765 
1766 	mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
1767 
1768 	return 0;
1769 
1770 err_fid_flood_tables_init:
1771 	bitmap_free(fid_family->fids_bitmap);
1772 err_alloc_fids_bitmap:
1773 	kfree(fid_family);
1774 	return err;
1775 }
1776 
1777 static void
mlxsw_sp_fid_family_unregister(struct mlxsw_sp * mlxsw_sp,struct mlxsw_sp_fid_family * fid_family)1778 mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
1779 			       struct mlxsw_sp_fid_family *fid_family)
1780 {
1781 	mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
1782 
1783 	if (fid_family->flood_tables)
1784 		mlxsw_sp_fid_flood_tables_fini(fid_family);
1785 
1786 	bitmap_free(fid_family->fids_bitmap);
1787 	WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
1788 	kfree(fid_family);
1789 }
1790 
mlxsw_sp_port_fids_init(struct mlxsw_sp_port * mlxsw_sp_port)1791 int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
1792 {
1793 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1794 
1795 	/* Track number of FIDs configured on the port with mapping type
1796 	 * PORT_VID_TO_FID, so that we know when to transition the port
1797 	 * back to non-virtual (VLAN) mode.
1798 	 */
1799 	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1800 
1801 	return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
1802 }
1803 
mlxsw_sp_port_fids_fini(struct mlxsw_sp_port * mlxsw_sp_port)1804 void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
1805 {
1806 	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1807 
1808 	mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1809 }
1810 
mlxsw_sp_fids_init(struct mlxsw_sp * mlxsw_sp)1811 int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
1812 {
1813 	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
1814 	struct mlxsw_sp_fid_core *fid_core;
1815 	int err, i;
1816 
1817 	fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
1818 	if (!fid_core)
1819 		return -ENOMEM;
1820 	mlxsw_sp->fid_core = fid_core;
1821 
1822 	err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params);
1823 	if (err)
1824 		goto err_rhashtable_fid_init;
1825 
1826 	err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params);
1827 	if (err)
1828 		goto err_rhashtable_vni_init;
1829 
1830 	fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
1831 					      GFP_KERNEL);
1832 	if (!fid_core->port_fid_mappings) {
1833 		err = -ENOMEM;
1834 		goto err_alloc_port_fid_mappings;
1835 	}
1836 
1837 	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
1838 		err = mlxsw_sp_fid_family_register(mlxsw_sp,
1839 						   mlxsw_sp->fid_family_arr[i]);
1840 
1841 		if (err)
1842 			goto err_fid_ops_register;
1843 	}
1844 
1845 	return 0;
1846 
1847 err_fid_ops_register:
1848 	for (i--; i >= 0; i--) {
1849 		struct mlxsw_sp_fid_family *fid_family;
1850 
1851 		fid_family = fid_core->fid_family_arr[i];
1852 		mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
1853 	}
1854 	kfree(fid_core->port_fid_mappings);
1855 err_alloc_port_fid_mappings:
1856 	rhashtable_destroy(&fid_core->vni_ht);
1857 err_rhashtable_vni_init:
1858 	rhashtable_destroy(&fid_core->fid_ht);
1859 err_rhashtable_fid_init:
1860 	kfree(fid_core);
1861 	return err;
1862 }
1863 
mlxsw_sp_fids_fini(struct mlxsw_sp * mlxsw_sp)1864 void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
1865 {
1866 	struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
1867 	int i;
1868 
1869 	for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
1870 		mlxsw_sp_fid_family_unregister(mlxsw_sp,
1871 					       fid_core->fid_family_arr[i]);
1872 	kfree(fid_core->port_fid_mappings);
1873 	rhashtable_destroy(&fid_core->vni_ht);
1874 	rhashtable_destroy(&fid_core->fid_ht);
1875 	kfree(fid_core);
1876 }
1877