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