1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
3
4#include <linux/kernel.h>
5#include <linux/bitops.h>
6#include <linux/if_vlan.h>
7#include <linux/if_bridge.h>
8#include <linux/netdevice.h>
9#include <linux/rhashtable.h>
10#include <linux/rtnetlink.h>
11#include <linux/refcount.h>
12
13#include "spectrum.h"
14#include "reg.h"
15
16struct mlxsw_sp_fid_family;
17
18struct mlxsw_sp_fid_core {
19	struct rhashtable fid_ht;
20	struct rhashtable vni_ht;
21	struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
22	unsigned int *port_fid_mappings;
23};
24
25struct mlxsw_sp_fid_port_vid {
26	struct list_head list;
27	u16 local_port;
28	u16 vid;
29};
30
31struct 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
50struct mlxsw_sp_fid_8021q {
51	struct mlxsw_sp_fid common;
52	u16 vid;
53};
54
55struct mlxsw_sp_fid_8021d {
56	struct mlxsw_sp_fid common;
57	int br_ifindex;
58};
59
60static 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
66static 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
72struct 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
78struct 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
100struct 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
118static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
119	[MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST]			= 1,
120};
121
122static 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
130static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
131	[MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4]	= 1,
132};
133
134static 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
140struct 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
153int 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
163int 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
174struct 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
187int 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
197int 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
215err_nve_flood_index_set:
216	fid->nve_flood_index_valid = false;
217	return err;
218}
219
220void 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
232bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
233{
234	return fid->nve_flood_index_valid;
235}
236
237int 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
264err_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
271void 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
286bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
287{
288	return fid->vni_valid;
289}
290
291void 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
301static const struct mlxsw_sp_flood_table *
302mlxsw_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
317static u16
318mlxsw_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
323static u16
324mlxsw_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
335int 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
356int 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
364void 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
370u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
371{
372	return fid->fid_index;
373}
374
375enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
376{
377	return fid->fid_family->type;
378}
379
380struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
381{
382	return fid->rif;
383}
384
385enum mlxsw_sp_rif_type
386mlxsw_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
394static struct mlxsw_sp_fid_8021q *
395mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
396{
397	return container_of(fid, struct mlxsw_sp_fid_8021q, common);
398}
399
400u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
401{
402	return mlxsw_sp_fid_8021q_fid(fid)->vid;
403}
404
405static 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
413static 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
419static 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
434static 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
461static 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
478static 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
484static 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
493static int
494mlxsw_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
510static int
511mlxsw_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
522static int
523mlxsw_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
537static 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
568err_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
580static 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
598static 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
642err_reg_write:
643	kfree(reiv_pl);
644	return err;
645}
646
647static 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
665err_reiv_handle:
666	for (; i >= 0; i--)
667		mlxsw_sp_fid_reiv_handle(fid, rif_index, !valid, i);
668	return err;
669}
670
671int 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
695err_erif_eport_to_vid_map:
696	mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
697err_vid_to_fid_rif_set:
698	mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
699err_vni_to_fid_rif_update:
700	mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
701	return err;
702}
703
704void 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
720static 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
734err_fid_edit_op:
735	mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, !fid->vni_valid);
736	return err;
737}
738
739static 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
757static struct mlxsw_sp_fid_8021d *
758mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
759{
760	return container_of(fid, struct mlxsw_sp_fid_8021d, common);
761}
762
763static 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
771static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
772{
773	return mlxsw_sp_fid_op(fid, true);
774}
775
776static 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
783static 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
798static bool
799mlxsw_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
806static 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
832err_port_vp_mode_set:
833err_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
848static 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
867static int
868mlxsw_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
889static void
890mlxsw_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
905static int
906mlxsw_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
917static int
918mlxsw_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
940static 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
959err_erif_eport_to_vid_map_one:
960	mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, !valid);
961	return err;
962}
963
964static 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
994err_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);
997err_port_vid_list_add:
998	mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
999err_fid_evid_map:
1000	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1001	return err;
1002}
1003
1004static void
1005mlxsw_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
1019static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid)
1020{
1021	return mlxsw_sp_fid_vni_op(fid);
1022}
1023
1024static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
1025{
1026	mlxsw_sp_fid_vni_op(fid);
1027}
1028
1029static 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
1034static 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
1039static void
1040mlxsw_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
1046static int
1047mlxsw_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
1053static 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
1074static 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
1092static bool
1093mlxsw_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
1100static void
1101mlxsw_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
1107static void mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid *fid, const void *arg)
1108{
1109	fid->fid_offset = 0;
1110}
1111
1112static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
1113{
1114	return mlxsw_sp_fid_op(fid, true);
1115}
1116
1117static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
1118{
1119	mlxsw_sp_fid_op(fid, false);
1120}
1121
1122static 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
1132static 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
1140static 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
1178err_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);
1183err_erif_eport_to_vid_map_one:
1184	__mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false);
1185err_port_vid_map:
1186	mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid);
1187	return err;
1188}
1189
1190static void
1191mlxsw_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
1208static int mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid *fid)
1209{
1210	return -EOPNOTSUPP;
1211}
1212
1213static void mlxsw_sp_fid_rfid_vni_clear(struct mlxsw_sp_fid *fid)
1214{
1215	WARN_ON_ONCE(1);
1216}
1217
1218static int mlxsw_sp_fid_rfid_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1219{
1220	return -EOPNOTSUPP;
1221}
1222
1223static void mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1224{
1225	WARN_ON_ONCE(1);
1226}
1227
1228static int
1229mlxsw_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
1235static 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
1250static void mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg)
1251{
1252	fid->fid_offset = 0;
1253}
1254
1255static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
1256{
1257	return mlxsw_sp_fid_op(fid, true);
1258}
1259
1260static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
1261{
1262	mlxsw_sp_fid_op(fid, false);
1263}
1264
1265static 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
1273static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
1274				       const void *arg)
1275{
1276	return true;
1277}
1278
1279static int mlxsw_sp_fid_dummy_vni_set(struct mlxsw_sp_fid *fid)
1280{
1281	return -EOPNOTSUPP;
1282}
1283
1284static void mlxsw_sp_fid_dummy_vni_clear(struct mlxsw_sp_fid *fid)
1285{
1286	WARN_ON_ONCE(1);
1287}
1288
1289static int mlxsw_sp_fid_dummy_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1290{
1291	return -EOPNOTSUPP;
1292}
1293
1294static void mlxsw_sp_fid_dummy_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1295{
1296	WARN_ON_ONCE(1);
1297}
1298
1299static 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
1311static 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
1326err_vid_to_fid_map:
1327	mlxsw_sp_fid_op(fid, false);
1328	return err;
1329}
1330
1331static 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
1342static 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
1371err_port_vid_list_add:
1372	 mlxsw_sp_fid_evid_map(fid, local_port, vid, false);
1373err_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
1379static void
1380mlxsw_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
1392static 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
1426static 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
1441static 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
1455static 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
1464static 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
1475const 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
1482static 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
1497static 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
1511static 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
1520const 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
1527static 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
1545static 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
1587err_rhashtable_insert:
1588	fid->fid_family->ops->deconfigure(fid);
1589err_configure:
1590	__clear_bit(fid_index - fid_family->start_index,
1591		    fid_family->fids_bitmap);
1592err_index_alloc:
1593	kfree(fid);
1594	return ERR_PTR(err);
1595}
1596
1597void 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
1615struct 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
1620struct 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
1626struct 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
1632struct 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
1639struct 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
1645struct 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
1650static int
1651mlxsw_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
1683err_reg_write:
1684	mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids);
1685	return err;
1686}
1687
1688static void
1689mlxsw_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
1700static int
1701mlxsw_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
1718static void
1719mlxsw_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
1731static 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
1760err_fid_flood_tables_init:
1761	bitmap_free(fid_family->fids_bitmap);
1762err_alloc_fids_bitmap:
1763	kfree(fid_family);
1764	return err;
1765}
1766
1767static void
1768mlxsw_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
1781int 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
1794void 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
1801int 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
1837err_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);
1845err_alloc_port_fid_mappings:
1846	rhashtable_destroy(&fid_core->vni_ht);
1847err_rhashtable_vni_init:
1848	rhashtable_destroy(&fid_core->fid_ht);
1849err_rhashtable_fid_init:
1850	kfree(fid_core);
1851	return err;
1852}
1853
1854void 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