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