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