1
2
3
4#include <linux/kernel.h>
5#include <linux/bitops.h>
6#include <linux/if_vlan.h>
7#include <linux/if_bridge.h>
8#include <linux/netdevice.h>
9#include <linux/rhashtable.h>
10#include <linux/rtnetlink.h>
11#include <linux/refcount.h>
12
13#include "spectrum.h"
14#include "reg.h"
15
16struct mlxsw_sp_fid_family;
17
18struct mlxsw_sp_fid_core {
19 struct rhashtable fid_ht;
20 struct rhashtable vni_ht;
21 struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
22 unsigned int *port_fid_mappings;
23};
24
25struct mlxsw_sp_fid {
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
42struct mlxsw_sp_fid_8021q {
43 struct mlxsw_sp_fid common;
44 u16 vid;
45};
46
47struct mlxsw_sp_fid_8021d {
48 struct mlxsw_sp_fid common;
49 int br_ifindex;
50};
51
52static 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
58static 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
64struct 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
71struct 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
93struct 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
108static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
109 [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1,
110};
111
112static 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
120static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
121 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
122};
123
124static 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
130bool 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
140bool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid)
141{
142 return fid->fid_family->lag_vid_valid;
143}
144
145struct 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
158int 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
168int 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
179struct 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
192int 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
202int 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
222void 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
234bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
235{
236 return fid->nve_flood_index_valid;
237}
238
239int 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
267err_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
273void 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
288bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
289{
290 return fid->vni_valid;
291}
292
293void 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
303static const struct mlxsw_sp_flood_table *
304mlxsw_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
319int 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
349int 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
357void 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
363u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
364{
365 return fid->fid_index;
366}
367
368enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
369{
370 return fid->fid_family->type;
371}
372
373void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
374{
375 fid->rif = rif;
376}
377
378struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
379{
380 return fid->rif;
381}
382
383enum mlxsw_sp_rif_type
384mlxsw_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
392static struct mlxsw_sp_fid_8021q *
393mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
394{
395 return container_of(fid, struct mlxsw_sp_fid_8021q, common);
396}
397
398u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
399{
400 return mlxsw_sp_fid_8021q_fid(fid)->vid;
401}
402
403static 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
410static 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
416static 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
426static 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
441static 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
451static struct mlxsw_sp_fid_8021d *
452mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
453{
454 return container_of(fid, struct mlxsw_sp_fid_8021d, common);
455}
456
457static 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
464static 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
471static 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
478static 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
493static bool
494mlxsw_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
501static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid)
502{
503 return fid->fid_index - VLAN_N_VID;
504}
505
506static 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
533err_port_vp_mode_set:
534err_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
550static 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
571static 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
592err_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
599static void
600mlxsw_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
613static 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
622static 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
630static 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
640static 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
648static void
649mlxsw_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
655static 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
671static 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
693static 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
705static bool
706mlxsw_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
713static void
714mlxsw_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
720static 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
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
742static 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
754static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
755{
756
757 return 0;
758}
759
760static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
761{
762}
763
764static 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
774static 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
782static 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
791
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
801err_port_vp_mode_trans:
802 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
803 return err;
804}
805
806static void
807mlxsw_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
818static 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
830static 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
839static 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
846static 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
851static 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
859static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
860 const void *arg)
861{
862 return true;
863}
864
865static 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
872static 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
880static 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
887static 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
905static 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
946err_rhashtable_insert:
947 fid->fid_family->ops->deconfigure(fid);
948err_configure:
949 __clear_bit(fid_index - fid_family->start_index,
950 fid_family->fids_bitmap);
951err_index_alloc:
952 kfree(fid);
953 return ERR_PTR(err);
954}
955
956void 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
973struct 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
978struct 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
984struct 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
990struct 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
997struct 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
1003struct 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
1008static int
1009mlxsw_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
1035static int
1036mlxsw_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
1053static 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
1082err_fid_flood_tables_init:
1083 bitmap_free(fid_family->fids_bitmap);
1084err_alloc_fids_bitmap:
1085 kfree(fid_family);
1086 return err;
1087}
1088
1089static void
1090mlxsw_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
1099int 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
1104
1105
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
1112void 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
1119int 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
1155err_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);
1163err_alloc_port_fid_mappings:
1164 rhashtable_destroy(&fid_core->vni_ht);
1165err_rhashtable_vni_init:
1166 rhashtable_destroy(&fid_core->fid_ht);
1167err_rhashtable_fid_init:
1168 kfree(fid_core);
1169 return err;
1170}
1171
1172void 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}
1185