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