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