Merge tag 'iommu-fixes-v5.0-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.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
12 #include "spectrum.h"
13 #include "reg.h"
14
15 struct mlxsw_sp_fid_family;
16
17 struct mlxsw_sp_fid_core {
18         struct rhashtable fid_ht;
19         struct rhashtable vni_ht;
20         struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
21         unsigned int *port_fid_mappings;
22 };
23
24 struct mlxsw_sp_fid {
25         struct list_head list;
26         struct mlxsw_sp_rif *rif;
27         unsigned int ref_count;
28         u16 fid_index;
29         struct mlxsw_sp_fid_family *fid_family;
30         struct rhash_head ht_node;
31
32         struct rhash_head vni_ht_node;
33         enum mlxsw_sp_nve_type nve_type;
34         __be32 vni;
35         u32 nve_flood_index;
36         int nve_ifindex;
37         u8 vni_valid:1,
38            nve_flood_index_valid:1;
39 };
40
41 struct mlxsw_sp_fid_8021q {
42         struct mlxsw_sp_fid common;
43         u16 vid;
44 };
45
46 struct mlxsw_sp_fid_8021d {
47         struct mlxsw_sp_fid common;
48         int br_ifindex;
49 };
50
51 static const struct rhashtable_params mlxsw_sp_fid_ht_params = {
52         .key_len = sizeof_field(struct mlxsw_sp_fid, fid_index),
53         .key_offset = offsetof(struct mlxsw_sp_fid, fid_index),
54         .head_offset = offsetof(struct mlxsw_sp_fid, ht_node),
55 };
56
57 static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = {
58         .key_len = sizeof_field(struct mlxsw_sp_fid, vni),
59         .key_offset = offsetof(struct mlxsw_sp_fid, vni),
60         .head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node),
61 };
62
63 struct mlxsw_sp_flood_table {
64         enum mlxsw_sp_flood_type packet_type;
65         enum mlxsw_reg_sfgc_bridge_type bridge_type;
66         enum mlxsw_flood_table_type table_type;
67         int table_index;
68 };
69
70 struct mlxsw_sp_fid_ops {
71         void (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
72         int (*configure)(struct mlxsw_sp_fid *fid);
73         void (*deconfigure)(struct mlxsw_sp_fid *fid);
74         int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
75                            u16 *p_fid_index);
76         bool (*compare)(const struct mlxsw_sp_fid *fid,
77                         const void *arg);
78         u16 (*flood_index)(const struct mlxsw_sp_fid *fid);
79         int (*port_vid_map)(struct mlxsw_sp_fid *fid,
80                             struct mlxsw_sp_port *port, u16 vid);
81         void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
82                                struct mlxsw_sp_port *port, u16 vid);
83         int (*vni_set)(struct mlxsw_sp_fid *fid, __be32 vni);
84         void (*vni_clear)(struct mlxsw_sp_fid *fid);
85         int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid,
86                                    u32 nve_flood_index);
87         void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);
88         void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid,
89                                   const struct net_device *nve_dev);
90 };
91
92 struct mlxsw_sp_fid_family {
93         enum mlxsw_sp_fid_type type;
94         size_t fid_size;
95         u16 start_index;
96         u16 end_index;
97         struct list_head fids_list;
98         unsigned long *fids_bitmap;
99         const struct mlxsw_sp_flood_table *flood_tables;
100         int nr_flood_tables;
101         enum mlxsw_sp_rif_type rif_type;
102         const struct mlxsw_sp_fid_ops *ops;
103         struct mlxsw_sp *mlxsw_sp;
104         u8 lag_vid_valid:1;
105 };
106
107 static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
108         [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST]                   = 1,
109 };
110
111 static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
112         [MLXSW_REG_SFGC_TYPE_BROADCAST]                         = 1,
113         [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP]     = 1,
114         [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL]                   = 1,
115         [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST]                     = 1,
116         [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6]       = 1,
117 };
118
119 static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
120         [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4]       = 1,
121 };
122
123 static const int *mlxsw_sp_packet_type_sfgc_types[] = {
124         [MLXSW_SP_FLOOD_TYPE_UC]        = mlxsw_sp_sfgc_uc_packet_types,
125         [MLXSW_SP_FLOOD_TYPE_BC]        = mlxsw_sp_sfgc_bc_packet_types,
126         [MLXSW_SP_FLOOD_TYPE_MC]        = mlxsw_sp_sfgc_mc_packet_types,
127 };
128
129 bool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid)
130 {
131         return fid->fid_family->lag_vid_valid;
132 }
133
134 struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
135                                                   u16 fid_index)
136 {
137         struct mlxsw_sp_fid *fid;
138
139         fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index,
140                                      mlxsw_sp_fid_ht_params);
141         if (fid)
142                 fid->ref_count++;
143
144         return fid;
145 }
146
147 int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex)
148 {
149         if (!fid->vni_valid)
150                 return -EINVAL;
151
152         *nve_ifindex = fid->nve_ifindex;
153
154         return 0;
155 }
156
157 int mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid,
158                           enum mlxsw_sp_nve_type *p_type)
159 {
160         if (!fid->vni_valid)
161                 return -EINVAL;
162
163         *p_type = fid->nve_type;
164
165         return 0;
166 }
167
168 struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,
169                                                 __be32 vni)
170 {
171         struct mlxsw_sp_fid *fid;
172
173         fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni,
174                                      mlxsw_sp_fid_vni_ht_params);
175         if (fid)
176                 fid->ref_count++;
177
178         return fid;
179 }
180
181 int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni)
182 {
183         if (!fid->vni_valid)
184                 return -EINVAL;
185
186         *vni = fid->vni;
187
188         return 0;
189 }
190
191 int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
192                                      u32 nve_flood_index)
193 {
194         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
195         const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
196         int err;
197
198         if (WARN_ON(!ops->nve_flood_index_set || fid->nve_flood_index_valid))
199                 return -EINVAL;
200
201         err = ops->nve_flood_index_set(fid, nve_flood_index);
202         if (err)
203                 return err;
204
205         fid->nve_flood_index = nve_flood_index;
206         fid->nve_flood_index_valid = true;
207
208         return 0;
209 }
210
211 void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
212 {
213         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
214         const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
215
216         if (WARN_ON(!ops->nve_flood_index_clear || !fid->nve_flood_index_valid))
217                 return;
218
219         fid->nve_flood_index_valid = false;
220         ops->nve_flood_index_clear(fid);
221 }
222
223 bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
224 {
225         return fid->nve_flood_index_valid;
226 }
227
228 int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type,
229                          __be32 vni, int nve_ifindex)
230 {
231         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
232         const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
233         struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
234         int err;
235
236         if (WARN_ON(!ops->vni_set || fid->vni_valid))
237                 return -EINVAL;
238
239         fid->nve_type = type;
240         fid->nve_ifindex = nve_ifindex;
241         fid->vni = vni;
242         err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht,
243                                             &fid->vni_ht_node,
244                                             mlxsw_sp_fid_vni_ht_params);
245         if (err)
246                 return err;
247
248         err = ops->vni_set(fid, vni);
249         if (err)
250                 goto err_vni_set;
251
252         fid->vni_valid = true;
253
254         return 0;
255
256 err_vni_set:
257         rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
258                                mlxsw_sp_fid_vni_ht_params);
259         return err;
260 }
261
262 void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid)
263 {
264         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
265         const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
266         struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
267
268         if (WARN_ON(!ops->vni_clear || !fid->vni_valid))
269                 return;
270
271         fid->vni_valid = false;
272         ops->vni_clear(fid);
273         rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
274                                mlxsw_sp_fid_vni_ht_params);
275 }
276
277 bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
278 {
279         return fid->vni_valid;
280 }
281
282 void mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
283                                     const struct net_device *nve_dev)
284 {
285         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
286         const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
287
288         if (ops->fdb_clear_offload)
289                 ops->fdb_clear_offload(fid, nve_dev);
290 }
291
292 static const struct mlxsw_sp_flood_table *
293 mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
294                                 enum mlxsw_sp_flood_type packet_type)
295 {
296         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
297         int i;
298
299         for (i = 0; i < fid_family->nr_flood_tables; i++) {
300                 if (fid_family->flood_tables[i].packet_type != packet_type)
301                         continue;
302                 return &fid_family->flood_tables[i];
303         }
304
305         return NULL;
306 }
307
308 int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
309                            enum mlxsw_sp_flood_type packet_type, u8 local_port,
310                            bool member)
311 {
312         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
313         const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
314         const struct mlxsw_sp_flood_table *flood_table;
315         char *sftr_pl;
316         int err;
317
318         if (WARN_ON(!fid_family->flood_tables || !ops->flood_index))
319                 return -EINVAL;
320
321         flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
322         if (!flood_table)
323                 return -ESRCH;
324
325         sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
326         if (!sftr_pl)
327                 return -ENOMEM;
328
329         mlxsw_reg_sftr_pack(sftr_pl, flood_table->table_index,
330                             ops->flood_index(fid), flood_table->table_type, 1,
331                             local_port, member);
332         err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr),
333                               sftr_pl);
334         kfree(sftr_pl);
335         return err;
336 }
337
338 int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
339                               struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
340 {
341         if (WARN_ON(!fid->fid_family->ops->port_vid_map))
342                 return -EINVAL;
343         return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);
344 }
345
346 void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
347                                  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
348 {
349         fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
350 }
351
352 u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
353 {
354         return fid->fid_index;
355 }
356
357 enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
358 {
359         return fid->fid_family->type;
360 }
361
362 void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
363 {
364         fid->rif = rif;
365 }
366
367 struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
368 {
369         return fid->rif;
370 }
371
372 enum mlxsw_sp_rif_type
373 mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
374                            enum mlxsw_sp_fid_type type)
375 {
376         struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
377
378         return fid_core->fid_family_arr[type]->rif_type;
379 }
380
381 static struct mlxsw_sp_fid_8021q *
382 mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
383 {
384         return container_of(fid, struct mlxsw_sp_fid_8021q, common);
385 }
386
387 u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
388 {
389         return mlxsw_sp_fid_8021q_fid(fid)->vid;
390 }
391
392 static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
393 {
394         u16 vid = *(u16 *) arg;
395
396         mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
397 }
398
399 static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
400 {
401         return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
402                        MLXSW_REG_SFMR_OP_DESTROY_FID;
403 }
404
405 static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
406                            u16 fid_offset, bool valid)
407 {
408         char sfmr_pl[MLXSW_REG_SFMR_LEN];
409
410         mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index,
411                             fid_offset);
412         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
413 }
414
415 static int mlxsw_sp_fid_vni_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
416                                __be32 vni, bool vni_valid, u32 nve_flood_index,
417                                bool nve_flood_index_valid)
418 {
419         char sfmr_pl[MLXSW_REG_SFMR_LEN];
420
421         mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, fid_index,
422                             0);
423         mlxsw_reg_sfmr_vv_set(sfmr_pl, vni_valid);
424         mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(vni));
425         mlxsw_reg_sfmr_vtfp_set(sfmr_pl, nve_flood_index_valid);
426         mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, nve_flood_index);
427         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
428 }
429
430 static int mlxsw_sp_fid_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
431                                 u16 vid, bool valid)
432 {
433         enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID;
434         char svfa_pl[MLXSW_REG_SVFA_LEN];
435
436         mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid_index, vid);
437         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
438 }
439
440 static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
441                                        u8 local_port, u16 vid, bool valid)
442 {
443         enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
444         char svfa_pl[MLXSW_REG_SVFA_LEN];
445
446         mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid);
447         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
448 }
449
450 static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
451 {
452         struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
453         struct mlxsw_sp_fid_8021q *fid_8021q;
454         int err;
455
456         err = mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, fid->fid_index, true);
457         if (err)
458                 return err;
459
460         fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
461         err = mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid,
462                                    true);
463         if (err)
464                 goto err_fid_map;
465
466         return 0;
467
468 err_fid_map:
469         mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false);
470         return err;
471 }
472
473 static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)
474 {
475         struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
476         struct mlxsw_sp_fid_8021q *fid_8021q;
477
478         fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
479         mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, false);
480         mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false);
481 }
482
483 static int mlxsw_sp_fid_8021q_index_alloc(struct mlxsw_sp_fid *fid,
484                                           const void *arg, u16 *p_fid_index)
485 {
486         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
487         u16 vid = *(u16 *) arg;
488
489         /* Use 1:1 mapping for simplicity although not a must */
490         if (vid < fid_family->start_index || vid > fid_family->end_index)
491                 return -EINVAL;
492         *p_fid_index = vid;
493
494         return 0;
495 }
496
497 static bool
498 mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
499 {
500         u16 vid = *(u16 *) arg;
501
502         return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
503 }
504
505 static u16 mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid *fid)
506 {
507         return fid->fid_index;
508 }
509
510 static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,
511                                            struct mlxsw_sp_port *mlxsw_sp_port,
512                                            u16 vid)
513 {
514         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
515         u8 local_port = mlxsw_sp_port->local_port;
516
517         /* In case there are no {Port, VID} => FID mappings on the port,
518          * we can use the global VID => FID mapping we created when the
519          * FID was configured.
520          */
521         if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0)
522                 return 0;
523         return __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port,
524                                            vid, true);
525 }
526
527 static void
528 mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
529                                   struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
530 {
531         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
532         u8 local_port = mlxsw_sp_port->local_port;
533
534         if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0)
535                 return;
536         __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, vid,
537                                     false);
538 }
539
540 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
541         .setup                  = mlxsw_sp_fid_8021q_setup,
542         .configure              = mlxsw_sp_fid_8021q_configure,
543         .deconfigure            = mlxsw_sp_fid_8021q_deconfigure,
544         .index_alloc            = mlxsw_sp_fid_8021q_index_alloc,
545         .compare                = mlxsw_sp_fid_8021q_compare,
546         .flood_index            = mlxsw_sp_fid_8021q_flood_index,
547         .port_vid_map           = mlxsw_sp_fid_8021q_port_vid_map,
548         .port_vid_unmap         = mlxsw_sp_fid_8021q_port_vid_unmap,
549 };
550
551 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021q_flood_tables[] = {
552         {
553                 .packet_type    = MLXSW_SP_FLOOD_TYPE_UC,
554                 .bridge_type    = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
555                 .table_type     = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
556                 .table_index    = 0,
557         },
558         {
559                 .packet_type    = MLXSW_SP_FLOOD_TYPE_MC,
560                 .bridge_type    = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
561                 .table_type     = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
562                 .table_index    = 1,
563         },
564         {
565                 .packet_type    = MLXSW_SP_FLOOD_TYPE_BC,
566                 .bridge_type    = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
567                 .table_type     = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
568                 .table_index    = 2,
569         },
570 };
571
572 /* Range and flood configuration must match mlxsw_config_profile */
573 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_family = {
574         .type                   = MLXSW_SP_FID_TYPE_8021Q,
575         .fid_size               = sizeof(struct mlxsw_sp_fid_8021q),
576         .start_index            = 1,
577         .end_index              = VLAN_VID_MASK,
578         .flood_tables           = mlxsw_sp_fid_8021q_flood_tables,
579         .nr_flood_tables        = ARRAY_SIZE(mlxsw_sp_fid_8021q_flood_tables),
580         .rif_type               = MLXSW_SP_RIF_TYPE_VLAN,
581         .ops                    = &mlxsw_sp_fid_8021q_ops,
582 };
583
584 static struct mlxsw_sp_fid_8021d *
585 mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
586 {
587         return container_of(fid, struct mlxsw_sp_fid_8021d, common);
588 }
589
590 static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
591 {
592         int br_ifindex = *(int *) arg;
593
594         mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
595 }
596
597 static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
598 {
599         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
600
601         return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true);
602 }
603
604 static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
605 {
606         if (fid->vni_valid)
607                 mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
608         mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
609 }
610
611 static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
612                                           const void *arg, u16 *p_fid_index)
613 {
614         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
615         u16 nr_fids, fid_index;
616
617         nr_fids = fid_family->end_index - fid_family->start_index + 1;
618         fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);
619         if (fid_index == nr_fids)
620                 return -ENOBUFS;
621         *p_fid_index = fid_family->start_index + fid_index;
622
623         return 0;
624 }
625
626 static bool
627 mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
628 {
629         int br_ifindex = *(int *) arg;
630
631         return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
632 }
633
634 static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid)
635 {
636         return fid->fid_index - VLAN_N_VID;
637 }
638
639 static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
640 {
641         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
642         struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
643         int err;
644
645         list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
646                             list) {
647                 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
648                 u16 vid = mlxsw_sp_port_vlan->vid;
649
650                 if (!fid)
651                         continue;
652
653                 err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
654                                                   mlxsw_sp_port->local_port,
655                                                   vid, true);
656                 if (err)
657                         goto err_fid_port_vid_map;
658         }
659
660         err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
661         if (err)
662                 goto err_port_vp_mode_set;
663
664         return 0;
665
666 err_port_vp_mode_set:
667 err_fid_port_vid_map:
668         list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
669                                              &mlxsw_sp_port->vlans_list, list) {
670                 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
671                 u16 vid = mlxsw_sp_port_vlan->vid;
672
673                 if (!fid)
674                         continue;
675
676                 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
677                                             mlxsw_sp_port->local_port, vid,
678                                             false);
679         }
680         return err;
681 }
682
683 static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
684 {
685         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
686         struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
687
688         mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
689
690         list_for_each_entry_reverse(mlxsw_sp_port_vlan,
691                                     &mlxsw_sp_port->vlans_list, list) {
692                 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
693                 u16 vid = mlxsw_sp_port_vlan->vid;
694
695                 if (!fid)
696                         continue;
697
698                 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
699                                             mlxsw_sp_port->local_port, vid,
700                                             false);
701         }
702 }
703
704 static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
705                                            struct mlxsw_sp_port *mlxsw_sp_port,
706                                            u16 vid)
707 {
708         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
709         u8 local_port = mlxsw_sp_port->local_port;
710         int err;
711
712         err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
713                                           mlxsw_sp_port->local_port, vid, true);
714         if (err)
715                 return err;
716
717         if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
718                 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
719                 if (err)
720                         goto err_port_vp_mode_trans;
721         }
722
723         return 0;
724
725 err_port_vp_mode_trans:
726         mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
727         __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
728                                     mlxsw_sp_port->local_port, vid, false);
729         return err;
730 }
731
732 static void
733 mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
734                                   struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
735 {
736         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
737         u8 local_port = mlxsw_sp_port->local_port;
738
739         if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
740                 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
741         mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
742         __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
743                                     mlxsw_sp_port->local_port, vid, false);
744 }
745
746 static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid, __be32 vni)
747 {
748         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
749
750         return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, vni,
751                                    true, fid->nve_flood_index,
752                                    fid->nve_flood_index_valid);
753 }
754
755 static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
756 {
757         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
758
759         mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, 0, false,
760                             fid->nve_flood_index, fid->nve_flood_index_valid);
761 }
762
763 static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid,
764                                                   u32 nve_flood_index)
765 {
766         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
767
768         return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index,
769                                    fid->vni, fid->vni_valid, nve_flood_index,
770                                    true);
771 }
772
773 static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
774 {
775         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
776
777         mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, fid->vni,
778                             fid->vni_valid, 0, false);
779 }
780
781 static void
782 mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
783                                      const struct net_device *nve_dev)
784 {
785         br_fdb_clear_offload(nve_dev, 0);
786 }
787
788 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
789         .setup                  = mlxsw_sp_fid_8021d_setup,
790         .configure              = mlxsw_sp_fid_8021d_configure,
791         .deconfigure            = mlxsw_sp_fid_8021d_deconfigure,
792         .index_alloc            = mlxsw_sp_fid_8021d_index_alloc,
793         .compare                = mlxsw_sp_fid_8021d_compare,
794         .flood_index            = mlxsw_sp_fid_8021d_flood_index,
795         .port_vid_map           = mlxsw_sp_fid_8021d_port_vid_map,
796         .port_vid_unmap         = mlxsw_sp_fid_8021d_port_vid_unmap,
797         .vni_set                = mlxsw_sp_fid_8021d_vni_set,
798         .vni_clear              = mlxsw_sp_fid_8021d_vni_clear,
799         .nve_flood_index_set    = mlxsw_sp_fid_8021d_nve_flood_index_set,
800         .nve_flood_index_clear  = mlxsw_sp_fid_8021d_nve_flood_index_clear,
801         .fdb_clear_offload      = mlxsw_sp_fid_8021d_fdb_clear_offload,
802 };
803
804 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
805         {
806                 .packet_type    = MLXSW_SP_FLOOD_TYPE_UC,
807                 .bridge_type    = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
808                 .table_type     = MLXSW_REG_SFGC_TABLE_TYPE_FID,
809                 .table_index    = 0,
810         },
811         {
812                 .packet_type    = MLXSW_SP_FLOOD_TYPE_MC,
813                 .bridge_type    = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
814                 .table_type     = MLXSW_REG_SFGC_TABLE_TYPE_FID,
815                 .table_index    = 1,
816         },
817         {
818                 .packet_type    = MLXSW_SP_FLOOD_TYPE_BC,
819                 .bridge_type    = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
820                 .table_type     = MLXSW_REG_SFGC_TABLE_TYPE_FID,
821                 .table_index    = 2,
822         },
823 };
824
825 /* Range and flood configuration must match mlxsw_config_profile */
826 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = {
827         .type                   = MLXSW_SP_FID_TYPE_8021D,
828         .fid_size               = sizeof(struct mlxsw_sp_fid_8021d),
829         .start_index            = VLAN_N_VID,
830         .end_index              = VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1,
831         .flood_tables           = mlxsw_sp_fid_8021d_flood_tables,
832         .nr_flood_tables        = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
833         .rif_type               = MLXSW_SP_RIF_TYPE_FID,
834         .ops                    = &mlxsw_sp_fid_8021d_ops,
835         .lag_vid_valid          = 1,
836 };
837
838 static void
839 mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
840                                      const struct net_device *nve_dev)
841 {
842         br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid));
843 }
844
845 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_emu_ops = {
846         .setup                  = mlxsw_sp_fid_8021q_setup,
847         .configure              = mlxsw_sp_fid_8021d_configure,
848         .deconfigure            = mlxsw_sp_fid_8021d_deconfigure,
849         .index_alloc            = mlxsw_sp_fid_8021d_index_alloc,
850         .compare                = mlxsw_sp_fid_8021q_compare,
851         .flood_index            = mlxsw_sp_fid_8021d_flood_index,
852         .port_vid_map           = mlxsw_sp_fid_8021d_port_vid_map,
853         .port_vid_unmap         = mlxsw_sp_fid_8021d_port_vid_unmap,
854         .vni_set                = mlxsw_sp_fid_8021d_vni_set,
855         .vni_clear              = mlxsw_sp_fid_8021d_vni_clear,
856         .nve_flood_index_set    = mlxsw_sp_fid_8021d_nve_flood_index_set,
857         .nve_flood_index_clear  = mlxsw_sp_fid_8021d_nve_flood_index_clear,
858         .fdb_clear_offload      = mlxsw_sp_fid_8021q_fdb_clear_offload,
859 };
860
861 /* There are 4K-2 emulated 802.1Q FIDs, starting right after the 802.1D FIDs */
862 #define MLXSW_SP_FID_8021Q_EMU_START    (VLAN_N_VID + MLXSW_SP_FID_8021D_MAX)
863 #define MLXSW_SP_FID_8021Q_EMU_END      (MLXSW_SP_FID_8021Q_EMU_START + \
864                                          VLAN_VID_MASK - 2)
865
866 /* Range and flood configuration must match mlxsw_config_profile */
867 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_emu_family = {
868         .type                   = MLXSW_SP_FID_TYPE_8021Q,
869         .fid_size               = sizeof(struct mlxsw_sp_fid_8021q),
870         .start_index            = MLXSW_SP_FID_8021Q_EMU_START,
871         .end_index              = MLXSW_SP_FID_8021Q_EMU_END,
872         .flood_tables           = mlxsw_sp_fid_8021d_flood_tables,
873         .nr_flood_tables        = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
874         .rif_type               = MLXSW_SP_RIF_TYPE_VLAN,
875         .ops                    = &mlxsw_sp_fid_8021q_emu_ops,
876         .lag_vid_valid          = 1,
877 };
878
879 static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
880 {
881         /* rFIDs are allocated by the device during init */
882         return 0;
883 }
884
885 static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
886 {
887 }
888
889 static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
890                                          const void *arg, u16 *p_fid_index)
891 {
892         u16 rif_index = *(u16 *) arg;
893
894         *p_fid_index = fid->fid_family->start_index + rif_index;
895
896         return 0;
897 }
898
899 static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
900                                       const void *arg)
901 {
902         u16 rif_index = *(u16 *) arg;
903
904         return fid->fid_index == rif_index + fid->fid_family->start_index;
905 }
906
907 static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
908                                           struct mlxsw_sp_port *mlxsw_sp_port,
909                                           u16 vid)
910 {
911         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
912         u8 local_port = mlxsw_sp_port->local_port;
913         int err;
914
915         /* We only need to transition the port to virtual mode since
916          * {Port, VID} => FID is done by the firmware upon RIF creation.
917          */
918         if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
919                 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
920                 if (err)
921                         goto err_port_vp_mode_trans;
922         }
923
924         return 0;
925
926 err_port_vp_mode_trans:
927         mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
928         return err;
929 }
930
931 static void
932 mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
933                                  struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
934 {
935         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
936         u8 local_port = mlxsw_sp_port->local_port;
937
938         if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
939                 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
940         mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
941 }
942
943 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
944         .configure              = mlxsw_sp_fid_rfid_configure,
945         .deconfigure            = mlxsw_sp_fid_rfid_deconfigure,
946         .index_alloc            = mlxsw_sp_fid_rfid_index_alloc,
947         .compare                = mlxsw_sp_fid_rfid_compare,
948         .port_vid_map           = mlxsw_sp_fid_rfid_port_vid_map,
949         .port_vid_unmap         = mlxsw_sp_fid_rfid_port_vid_unmap,
950 };
951
952 #define MLXSW_SP_RFID_BASE      (15 * 1024)
953 #define MLXSW_SP_RFID_MAX       1024
954
955 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
956         .type                   = MLXSW_SP_FID_TYPE_RFID,
957         .fid_size               = sizeof(struct mlxsw_sp_fid),
958         .start_index            = MLXSW_SP_RFID_BASE,
959         .end_index              = MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1,
960         .rif_type               = MLXSW_SP_RIF_TYPE_SUBPORT,
961         .ops                    = &mlxsw_sp_fid_rfid_ops,
962 };
963
964 static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
965 {
966         struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
967
968         return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true);
969 }
970
971 static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
972 {
973         mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
974 }
975
976 static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
977                                           const void *arg, u16 *p_fid_index)
978 {
979         *p_fid_index = fid->fid_family->start_index;
980
981         return 0;
982 }
983
984 static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
985                                        const void *arg)
986 {
987         return true;
988 }
989
990 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
991         .configure              = mlxsw_sp_fid_dummy_configure,
992         .deconfigure            = mlxsw_sp_fid_dummy_deconfigure,
993         .index_alloc            = mlxsw_sp_fid_dummy_index_alloc,
994         .compare                = mlxsw_sp_fid_dummy_compare,
995 };
996
997 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = {
998         .type                   = MLXSW_SP_FID_TYPE_DUMMY,
999         .fid_size               = sizeof(struct mlxsw_sp_fid),
1000         .start_index            = VLAN_N_VID - 1,
1001         .end_index              = VLAN_N_VID - 1,
1002         .ops                    = &mlxsw_sp_fid_dummy_ops,
1003 };
1004
1005 static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = {
1006         [MLXSW_SP_FID_TYPE_8021Q]       = &mlxsw_sp_fid_8021q_emu_family,
1007         [MLXSW_SP_FID_TYPE_8021D]       = &mlxsw_sp_fid_8021d_family,
1008         [MLXSW_SP_FID_TYPE_RFID]        = &mlxsw_sp_fid_rfid_family,
1009         [MLXSW_SP_FID_TYPE_DUMMY]       = &mlxsw_sp_fid_dummy_family,
1010 };
1011
1012 static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,
1013                                                 enum mlxsw_sp_fid_type type,
1014                                                 const void *arg)
1015 {
1016         struct mlxsw_sp_fid_family *fid_family;
1017         struct mlxsw_sp_fid *fid;
1018
1019         fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
1020         list_for_each_entry(fid, &fid_family->fids_list, list) {
1021                 if (!fid->fid_family->ops->compare(fid, arg))
1022                         continue;
1023                 fid->ref_count++;
1024                 return fid;
1025         }
1026
1027         return NULL;
1028 }
1029
1030 static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
1031                                              enum mlxsw_sp_fid_type type,
1032                                              const void *arg)
1033 {
1034         struct mlxsw_sp_fid_family *fid_family;
1035         struct mlxsw_sp_fid *fid;
1036         u16 fid_index;
1037         int err;
1038
1039         fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg);
1040         if (fid)
1041                 return fid;
1042
1043         fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
1044         fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
1045         if (!fid)
1046                 return ERR_PTR(-ENOMEM);
1047         fid->fid_family = fid_family;
1048
1049         err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
1050         if (err)
1051                 goto err_index_alloc;
1052         fid->fid_index = fid_index;
1053         __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
1054
1055         if (fid->fid_family->ops->setup)
1056                 fid->fid_family->ops->setup(fid, arg);
1057
1058         err = fid->fid_family->ops->configure(fid);
1059         if (err)
1060                 goto err_configure;
1061
1062         err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node,
1063                                      mlxsw_sp_fid_ht_params);
1064         if (err)
1065                 goto err_rhashtable_insert;
1066
1067         list_add(&fid->list, &fid_family->fids_list);
1068         fid->ref_count++;
1069         return fid;
1070
1071 err_rhashtable_insert:
1072         fid->fid_family->ops->deconfigure(fid);
1073 err_configure:
1074         __clear_bit(fid_index - fid_family->start_index,
1075                     fid_family->fids_bitmap);
1076 err_index_alloc:
1077         kfree(fid);
1078         return ERR_PTR(err);
1079 }
1080
1081 void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
1082 {
1083         struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
1084         struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1085
1086         if (--fid->ref_count != 0)
1087                 return;
1088
1089         list_del(&fid->list);
1090         rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht,
1091                                &fid->ht_node, mlxsw_sp_fid_ht_params);
1092         fid->fid_family->ops->deconfigure(fid);
1093         __clear_bit(fid->fid_index - fid_family->start_index,
1094                     fid_family->fids_bitmap);
1095         kfree(fid);
1096 }
1097
1098 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
1099 {
1100         return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
1101 }
1102
1103 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
1104                                             int br_ifindex)
1105 {
1106         return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
1107 }
1108
1109 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp,
1110                                                u16 vid)
1111 {
1112         return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
1113 }
1114
1115 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
1116                                                int br_ifindex)
1117 {
1118         return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D,
1119                                    &br_ifindex);
1120 }
1121
1122 struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
1123                                            u16 rif_index)
1124 {
1125         return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);
1126 }
1127
1128 struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
1129 {
1130         return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);
1131 }
1132
1133 static int
1134 mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
1135                               const struct mlxsw_sp_flood_table *flood_table)
1136 {
1137         enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
1138         const int *sfgc_packet_types;
1139         int i;
1140
1141         sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
1142         for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
1143                 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1144                 char sfgc_pl[MLXSW_REG_SFGC_LEN];
1145                 int err;
1146
1147                 if (!sfgc_packet_types[i])
1148                         continue;
1149                 mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type,
1150                                     flood_table->table_type,
1151                                     flood_table->table_index);
1152                 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
1153                 if (err)
1154                         return err;
1155         }
1156
1157         return 0;
1158 }
1159
1160 static int
1161 mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
1162 {
1163         int i;
1164
1165         for (i = 0; i < fid_family->nr_flood_tables; i++) {
1166                 const struct mlxsw_sp_flood_table *flood_table;
1167                 int err;
1168
1169                 flood_table = &fid_family->flood_tables[i];
1170                 err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
1171                 if (err)
1172                         return err;
1173         }
1174
1175         return 0;
1176 }
1177
1178 static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
1179                                         const struct mlxsw_sp_fid_family *tmpl)
1180 {
1181         u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
1182         struct mlxsw_sp_fid_family *fid_family;
1183         int err;
1184
1185         fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);
1186         if (!fid_family)
1187                 return -ENOMEM;
1188
1189         fid_family->mlxsw_sp = mlxsw_sp;
1190         INIT_LIST_HEAD(&fid_family->fids_list);
1191         fid_family->fids_bitmap = kcalloc(BITS_TO_LONGS(nr_fids),
1192                                           sizeof(unsigned long), GFP_KERNEL);
1193         if (!fid_family->fids_bitmap) {
1194                 err = -ENOMEM;
1195                 goto err_alloc_fids_bitmap;
1196         }
1197
1198         if (fid_family->flood_tables) {
1199                 err = mlxsw_sp_fid_flood_tables_init(fid_family);
1200                 if (err)
1201                         goto err_fid_flood_tables_init;
1202         }
1203
1204         mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
1205
1206         return 0;
1207
1208 err_fid_flood_tables_init:
1209         kfree(fid_family->fids_bitmap);
1210 err_alloc_fids_bitmap:
1211         kfree(fid_family);
1212         return err;
1213 }
1214
1215 static void
1216 mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
1217                                struct mlxsw_sp_fid_family *fid_family)
1218 {
1219         mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
1220         kfree(fid_family->fids_bitmap);
1221         WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
1222         kfree(fid_family);
1223 }
1224
1225 int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
1226 {
1227         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1228
1229         /* Track number of FIDs configured on the port with mapping type
1230          * PORT_VID_TO_FID, so that we know when to transition the port
1231          * back to non-virtual (VLAN) mode.
1232          */
1233         mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1234
1235         return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
1236 }
1237
1238 void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
1239 {
1240         struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1241
1242         mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1243 }
1244
1245 int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
1246 {
1247         unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
1248         struct mlxsw_sp_fid_core *fid_core;
1249         int err, i;
1250
1251         fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
1252         if (!fid_core)
1253                 return -ENOMEM;
1254         mlxsw_sp->fid_core = fid_core;
1255
1256         err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params);
1257         if (err)
1258                 goto err_rhashtable_fid_init;
1259
1260         err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params);
1261         if (err)
1262                 goto err_rhashtable_vni_init;
1263
1264         fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
1265                                               GFP_KERNEL);
1266         if (!fid_core->port_fid_mappings) {
1267                 err = -ENOMEM;
1268                 goto err_alloc_port_fid_mappings;
1269         }
1270
1271         for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
1272                 err = mlxsw_sp_fid_family_register(mlxsw_sp,
1273                                                    mlxsw_sp_fid_family_arr[i]);
1274
1275                 if (err)
1276                         goto err_fid_ops_register;
1277         }
1278
1279         return 0;
1280
1281 err_fid_ops_register:
1282         for (i--; i >= 0; i--) {
1283                 struct mlxsw_sp_fid_family *fid_family;
1284
1285                 fid_family = fid_core->fid_family_arr[i];
1286                 mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
1287         }
1288         kfree(fid_core->port_fid_mappings);
1289 err_alloc_port_fid_mappings:
1290         rhashtable_destroy(&fid_core->vni_ht);
1291 err_rhashtable_vni_init:
1292         rhashtable_destroy(&fid_core->fid_ht);
1293 err_rhashtable_fid_init:
1294         kfree(fid_core);
1295         return err;
1296 }
1297
1298 void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
1299 {
1300         struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
1301         int i;
1302
1303         for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
1304                 mlxsw_sp_fid_family_unregister(mlxsw_sp,
1305                                                fid_core->fid_family_arr[i]);
1306         kfree(fid_core->port_fid_mappings);
1307         rhashtable_destroy(&fid_core->vni_ht);
1308         rhashtable_destroy(&fid_core->fid_ht);
1309         kfree(fid_core);
1310 }