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
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_port_vid {
26 struct list_head list;
27 u16 local_port;
28 u16 vid;
29};
30
31struct mlxsw_sp_fid {
32 struct list_head list;
33 struct mlxsw_sp_rif *rif;
34 refcount_t ref_count;
35 u16 fid_index;
36 u16 fid_offset;
37 struct mlxsw_sp_fid_family *fid_family;
38 struct rhash_head ht_node;
39
40 struct rhash_head vni_ht_node;
41 enum mlxsw_sp_nve_type nve_type;
42 __be32 vni;
43 u32 nve_flood_index;
44 int nve_ifindex;
45 u8 vni_valid:1,
46 nve_flood_index_valid:1;
47 struct list_head port_vid_list; /* Ordered by local port. */
48};
49
50struct mlxsw_sp_fid_8021q {
51 struct mlxsw_sp_fid common;
52 u16 vid;
53};
54
55struct mlxsw_sp_fid_8021d {
56 struct mlxsw_sp_fid common;
57 int br_ifindex;
58};
59
60static const struct rhashtable_params mlxsw_sp_fid_ht_params = {
61 .key_len = sizeof_field(struct mlxsw_sp_fid, fid_index),
62 .key_offset = offsetof(struct mlxsw_sp_fid, fid_index),
63 .head_offset = offsetof(struct mlxsw_sp_fid, ht_node),
64};
65
66static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = {
67 .key_len = sizeof_field(struct mlxsw_sp_fid, vni),
68 .key_offset = offsetof(struct mlxsw_sp_fid, vni),
69 .head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node),
70};
71
72struct mlxsw_sp_flood_table {
73 enum mlxsw_sp_flood_type packet_type;
74 enum mlxsw_flood_table_type table_type;
75 int table_index;
76};
77
78struct mlxsw_sp_fid_ops {
79 void (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
80 int (*configure)(struct mlxsw_sp_fid *fid);
81 void (*deconfigure)(struct mlxsw_sp_fid *fid);
82 int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
83 u16 *p_fid_index);
84 bool (*compare)(const struct mlxsw_sp_fid *fid,
85 const void *arg);
86 int (*port_vid_map)(struct mlxsw_sp_fid *fid,
87 struct mlxsw_sp_port *port, u16 vid);
88 void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
89 struct mlxsw_sp_port *port, u16 vid);
90 int (*vni_set)(struct mlxsw_sp_fid *fid);
91 void (*vni_clear)(struct mlxsw_sp_fid *fid);
92 int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid);
93 void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);
94 void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid,
95 const struct net_device *nve_dev);
96 int (*vid_to_fid_rif_update)(const struct mlxsw_sp_fid *fid,
97 const struct mlxsw_sp_rif *rif);
98};
99
100struct mlxsw_sp_fid_family {
101 enum mlxsw_sp_fid_type type;
102 size_t fid_size;
103 u16 start_index;
104 u16 end_index;
105 struct list_head fids_list;
106 unsigned long *fids_bitmap;
107 const struct mlxsw_sp_flood_table *flood_tables;
108 int nr_flood_tables;
109 enum mlxsw_sp_rif_type rif_type;
110 const struct mlxsw_sp_fid_ops *ops;
111 struct mlxsw_sp *mlxsw_sp;
112 bool flood_rsp;
113 enum mlxsw_reg_bridge_type bridge_type;
114 u16 pgt_base;
115 bool smpe_index_valid;
116};
117
118static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
119 [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1,
120};
121
122static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
123 [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1,
124 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1,
125 [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1,
126 [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1,
127 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1,
128};
129
130static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
131 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
132};
133
134static const int *mlxsw_sp_packet_type_sfgc_types[] = {
135 [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types,
136 [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types,
137 [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types,
138};
139
140struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
141 u16 fid_index)
142{
143 struct mlxsw_sp_fid *fid;
144
145 fid = rhashtable_lookup_fast(ht: &mlxsw_sp->fid_core->fid_ht, key: &fid_index,
146 params: mlxsw_sp_fid_ht_params);
147 if (fid)
148 refcount_inc(r: &fid->ref_count);
149
150 return fid;
151}
152
153int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex)
154{
155 if (!fid->vni_valid)
156 return -EINVAL;
157
158 *nve_ifindex = fid->nve_ifindex;
159
160 return 0;
161}
162
163int mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid,
164 enum mlxsw_sp_nve_type *p_type)
165{
166 if (!fid->vni_valid)
167 return -EINVAL;
168
169 *p_type = fid->nve_type;
170
171 return 0;
172}
173
174struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,
175 __be32 vni)
176{
177 struct mlxsw_sp_fid *fid;
178
179 fid = rhashtable_lookup_fast(ht: &mlxsw_sp->fid_core->vni_ht, key: &vni,
180 params: mlxsw_sp_fid_vni_ht_params);
181 if (fid)
182 refcount_inc(r: &fid->ref_count);
183
184 return fid;
185}
186
187int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni)
188{
189 if (!fid->vni_valid)
190 return -EINVAL;
191
192 *vni = fid->vni;
193
194 return 0;
195}
196
197int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
198 u32 nve_flood_index)
199{
200 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
201 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
202 int err;
203
204 if (WARN_ON(fid->nve_flood_index_valid))
205 return -EINVAL;
206
207 fid->nve_flood_index = nve_flood_index;
208 fid->nve_flood_index_valid = true;
209 err = ops->nve_flood_index_set(fid);
210 if (err)
211 goto err_nve_flood_index_set;
212
213 return 0;
214
215err_nve_flood_index_set:
216 fid->nve_flood_index_valid = false;
217 return err;
218}
219
220void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
221{
222 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
223 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
224
225 if (WARN_ON(!fid->nve_flood_index_valid))
226 return;
227
228 fid->nve_flood_index_valid = false;
229 ops->nve_flood_index_clear(fid);
230}
231
232bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
233{
234 return fid->nve_flood_index_valid;
235}
236
237int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type,
238 __be32 vni, int nve_ifindex)
239{
240 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
241 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
242 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
243 int err;
244
245 if (WARN_ON(fid->vni_valid))
246 return -EINVAL;
247
248 fid->nve_type = type;
249 fid->nve_ifindex = nve_ifindex;
250 fid->vni = vni;
251 err = rhashtable_lookup_insert_fast(ht: &mlxsw_sp->fid_core->vni_ht,
252 obj: &fid->vni_ht_node,
253 params: mlxsw_sp_fid_vni_ht_params);
254 if (err)
255 return err;
256
257 fid->vni_valid = true;
258 err = ops->vni_set(fid);
259 if (err)
260 goto err_vni_set;
261
262 return 0;
263
264err_vni_set:
265 fid->vni_valid = false;
266 rhashtable_remove_fast(ht: &mlxsw_sp->fid_core->vni_ht, obj: &fid->vni_ht_node,
267 params: mlxsw_sp_fid_vni_ht_params);
268 return err;
269}
270
271void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid)
272{
273 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
274 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
275 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
276
277 if (WARN_ON(!fid->vni_valid))
278 return;
279
280 fid->vni_valid = false;
281 ops->vni_clear(fid);
282 rhashtable_remove_fast(ht: &mlxsw_sp->fid_core->vni_ht, obj: &fid->vni_ht_node,
283 params: mlxsw_sp_fid_vni_ht_params);
284}
285
286bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
287{
288 return fid->vni_valid;
289}
290
291void mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
292 const struct net_device *nve_dev)
293{
294 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
295 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
296
297 if (ops->fdb_clear_offload)
298 ops->fdb_clear_offload(fid, nve_dev);
299}
300
301static const struct mlxsw_sp_flood_table *
302mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
303 enum mlxsw_sp_flood_type packet_type)
304{
305 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
306 int i;
307
308 for (i = 0; i < fid_family->nr_flood_tables; i++) {
309 if (fid_family->flood_tables[i].packet_type != packet_type)
310 continue;
311 return &fid_family->flood_tables[i];
312 }
313
314 return NULL;
315}
316
317static u16
318mlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family *fid_family)
319{
320 return fid_family->end_index - fid_family->start_index + 1;
321}
322
323static u16
324mlxsw_sp_fid_family_pgt_size(const struct mlxsw_sp_fid_family *fid_family)
325{
326 u16 num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
327
328 return num_fids * fid_family->nr_flood_tables;
329}
330
331static u16
332mlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family *fid_family,
333 const struct mlxsw_sp_flood_table *flood_table,
334 u16 fid_offset)
335{
336 u16 num_fids;
337
338 num_fids = mlxsw_sp_fid_family_num_fids(fid_family);
339 return fid_family->pgt_base + num_fids * flood_table->table_index +
340 fid_offset;
341}
342
343int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
344 enum mlxsw_sp_flood_type packet_type, u16 local_port,
345 bool member)
346{
347 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
348 const struct mlxsw_sp_flood_table *flood_table;
349 u16 mid_index;
350
351 if (WARN_ON(!fid_family->flood_tables))
352 return -EINVAL;
353
354 flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
355 if (!flood_table)
356 return -ESRCH;
357
358 mid_index = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table,
359 fid_offset: fid->fid_offset);
360 return mlxsw_sp_pgt_entry_port_set(mlxsw_sp: fid_family->mlxsw_sp, mid: mid_index,
361 smpe: fid->fid_index, local_port, member);
362}
363
364int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
365 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
366{
367 if (WARN_ON(!fid->fid_family->ops->port_vid_map))
368 return -EINVAL;
369 return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);
370}
371
372void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
373 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
374{
375 fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
376}
377
378u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
379{
380 return fid->fid_index;
381}
382
383enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
384{
385 return fid->fid_family->type;
386}
387
388struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
389{
390 return fid->rif;
391}
392
393enum mlxsw_sp_rif_type
394mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
395 enum mlxsw_sp_fid_type type)
396{
397 struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
398
399 return fid_core->fid_family_arr[type]->rif_type;
400}
401
402static struct mlxsw_sp_fid_8021q *
403mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
404{
405 return container_of(fid, struct mlxsw_sp_fid_8021q, common);
406}
407
408u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
409{
410 return mlxsw_sp_fid_8021q_fid(fid)->vid;
411}
412
413static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
414{
415 u16 vid = *(u16 *) arg;
416
417 mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
418 fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
419}
420
421static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
422{
423 return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
424 MLXSW_REG_SFMR_OP_DESTROY_FID;
425}
426
427static int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid)
428{
429 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
430 char sfmr_pl[MLXSW_REG_SFMR_LEN];
431 u16 smpe;
432
433 smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;
434
435 mlxsw_reg_sfmr_pack(payload: sfmr_pl, op: mlxsw_sp_sfmr_op(valid), fid: fid->fid_index,
436 fid_offset: fid->fid_offset, flood_rsp: fid->fid_family->flood_rsp,
437 bridge_type: fid->fid_family->bridge_type,
438 smpe_valid: fid->fid_family->smpe_index_valid, smpe);
439 return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(sfmr), payload: sfmr_pl);
440}
441
442static int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid,
443 const struct mlxsw_sp_rif *rif)
444{
445 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
446 char sfmr_pl[MLXSW_REG_SFMR_LEN];
447 u16 smpe;
448
449 smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0;
450
451 mlxsw_reg_sfmr_pack(payload: sfmr_pl, op: MLXSW_REG_SFMR_OP_CREATE_FID,
452 fid: fid->fid_index, fid_offset: fid->fid_offset,
453 flood_rsp: fid->fid_family->flood_rsp,
454 bridge_type: fid->fid_family->bridge_type,
455 smpe_valid: fid->fid_family->smpe_index_valid, smpe);
456 mlxsw_reg_sfmr_vv_set(buf: sfmr_pl, val: fid->vni_valid);
457 mlxsw_reg_sfmr_vni_set(buf: sfmr_pl, be32_to_cpu(fid->vni));
458 mlxsw_reg_sfmr_vtfp_set(buf: sfmr_pl, val: fid->nve_flood_index_valid);
459 mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(buf: sfmr_pl, val: fid->nve_flood_index);
460
461 if (rif) {
462 mlxsw_reg_sfmr_irif_v_set(buf: sfmr_pl, val: true);
463 mlxsw_reg_sfmr_irif_set(buf: sfmr_pl, val: mlxsw_sp_rif_index(rif));
464 }
465
466 return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(sfmr), payload: sfmr_pl);
467}
468
469static int mlxsw_sp_fid_vni_to_fid_map(const struct mlxsw_sp_fid *fid,
470 const struct mlxsw_sp_rif *rif,
471 bool valid)
472{
473 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
474 char svfa_pl[MLXSW_REG_SVFA_LEN];
475 bool irif_valid;
476 u16 irif_index;
477
478 irif_valid = !!rif;
479 irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
480
481 mlxsw_reg_svfa_vni_pack(payload: svfa_pl, valid, fid: fid->fid_index,
482 be32_to_cpu(fid->vni), irif_v: irif_valid, irif: irif_index);
483 return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(svfa), payload: svfa_pl);
484}
485
486static int mlxsw_sp_fid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
487 const struct mlxsw_sp_rif *rif)
488{
489 return mlxsw_sp_fid_edit_op(fid, rif);
490}
491
492static int mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
493 const struct mlxsw_sp_rif *rif)
494{
495 if (!fid->vni_valid)
496 return 0;
497
498 return mlxsw_sp_fid_vni_to_fid_map(fid, rif, valid: fid->vni_valid);
499}
500
501static int
502mlxsw_sp_fid_vid_to_fid_map(const struct mlxsw_sp_fid *fid, u16 vid, bool valid,
503 const struct mlxsw_sp_rif *rif)
504{
505 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
506 char svfa_pl[MLXSW_REG_SVFA_LEN];
507 bool irif_valid;
508 u16 irif_index;
509
510 irif_valid = !!rif;
511 irif_index = rif ? mlxsw_sp_rif_index(rif) : 0;
512
513 mlxsw_reg_svfa_vid_pack(payload: svfa_pl, valid, fid: fid->fid_index, vid, irif_v: irif_valid,
514 irif: irif_index);
515 return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(svfa), payload: svfa_pl);
516}
517
518static int
519mlxsw_sp_fid_8021q_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
520 const struct mlxsw_sp_rif *rif)
521{
522 struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
523
524 /* Update the global VID => FID mapping we created when the FID was
525 * configured.
526 */
527 return mlxsw_sp_fid_vid_to_fid_map(fid, vid: fid_8021q->vid, valid: true, rif);
528}
529
530static int
531mlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid *fid,
532 struct mlxsw_sp_fid_port_vid *pv,
533 bool irif_valid, u16 irif_index)
534{
535 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
536 char svfa_pl[MLXSW_REG_SVFA_LEN];
537
538 mlxsw_reg_svfa_port_vid_pack(payload: svfa_pl, local_port: pv->local_port, valid: true,
539 fid: fid->fid_index, vid: pv->vid, irif_v: irif_valid,
540 irif: irif_index);
541
542 return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(svfa), payload: svfa_pl);
543}
544
545static int mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid *fid,
546 const struct mlxsw_sp_rif *rif)
547{
548 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
549 struct mlxsw_sp_fid_port_vid *pv;
550 u16 irif_index;
551 int err;
552
553 err = fid->fid_family->ops->vid_to_fid_rif_update(fid, rif);
554 if (err)
555 return err;
556
557 irif_index = mlxsw_sp_rif_index(rif);
558
559 list_for_each_entry(pv, &fid->port_vid_list, list) {
560 /* If port is not in virtual mode, then it does not have any
561 * {Port, VID}->FID mappings that need to be updated with the
562 * ingress RIF.
563 */
564 if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
565 continue;
566
567 err = mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv,
568 irif_valid: true,
569 irif_index);
570 if (err)
571 goto err_port_vid_to_fid_rif_update_one;
572 }
573
574 return 0;
575
576err_port_vid_to_fid_rif_update_one:
577 list_for_each_entry_continue_reverse(pv, &fid->port_vid_list, list) {
578 if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
579 continue;
580
581 mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, irif_valid: false, irif_index: 0);
582 }
583
584 fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
585 return err;
586}
587
588static void mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid *fid)
589{
590 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
591 struct mlxsw_sp_fid_port_vid *pv;
592
593 list_for_each_entry(pv, &fid->port_vid_list, list) {
594 /* If port is not in virtual mode, then it does not have any
595 * {Port, VID}->FID mappings that need to be updated.
596 */
597 if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port])
598 continue;
599
600 mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, irif_valid: false, irif_index: 0);
601 }
602
603 fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL);
604}
605
606static int mlxsw_sp_fid_reiv_handle(struct mlxsw_sp_fid *fid, u16 rif_index,
607 bool valid, u8 port_page)
608{
609 u16 local_port_end = (port_page + 1) * MLXSW_REG_REIV_REC_MAX_COUNT - 1;
610 u16 local_port_start = port_page * MLXSW_REG_REIV_REC_MAX_COUNT;
611 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
612 struct mlxsw_sp_fid_port_vid *port_vid;
613 u8 rec_num, entries_num = 0;
614 char *reiv_pl;
615 int err;
616
617 reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
618 if (!reiv_pl)
619 return -ENOMEM;
620
621 mlxsw_reg_reiv_pack(payload: reiv_pl, port_page, erif: rif_index);
622
623 list_for_each_entry(port_vid, &fid->port_vid_list, list) {
624 /* port_vid_list is sorted by local_port. */
625 if (port_vid->local_port < local_port_start)
626 continue;
627
628 if (port_vid->local_port > local_port_end)
629 break;
630
631 rec_num = port_vid->local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
632 mlxsw_reg_reiv_rec_update_set(buf: reiv_pl, index: rec_num, val: true);
633 mlxsw_reg_reiv_rec_evid_set(buf: reiv_pl, index: rec_num,
634 val: valid ? port_vid->vid : 0);
635 entries_num++;
636 }
637
638 if (!entries_num) {
639 kfree(objp: reiv_pl);
640 return 0;
641 }
642
643 err = mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(reiv), payload: reiv_pl);
644 if (err)
645 goto err_reg_write;
646
647 kfree(objp: reiv_pl);
648 return 0;
649
650err_reg_write:
651 kfree(objp: reiv_pl);
652 return err;
653}
654
655static int mlxsw_sp_fid_erif_eport_to_vid_map(struct mlxsw_sp_fid *fid,
656 u16 rif_index, bool valid)
657{
658 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
659 u8 num_port_pages;
660 int err, i;
661
662 num_port_pages = mlxsw_core_max_ports(mlxsw_core: mlxsw_sp->core) /
663 MLXSW_REG_REIV_REC_MAX_COUNT + 1;
664
665 for (i = 0; i < num_port_pages; i++) {
666 err = mlxsw_sp_fid_reiv_handle(fid, rif_index, valid, port_page: i);
667 if (err)
668 goto err_reiv_handle;
669 }
670
671 return 0;
672
673err_reiv_handle:
674 for (; i >= 0; i--)
675 mlxsw_sp_fid_reiv_handle(fid, rif_index, valid: !valid, port_page: i);
676 return err;
677}
678
679int mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
680{
681 u16 rif_index = mlxsw_sp_rif_index(rif);
682 int err;
683
684 err = mlxsw_sp_fid_to_fid_rif_update(fid, rif);
685 if (err)
686 return err;
687
688 err = mlxsw_sp_fid_vni_to_fid_rif_update(fid, rif);
689 if (err)
690 goto err_vni_to_fid_rif_update;
691
692 err = mlxsw_sp_fid_vid_to_fid_rif_set(fid, rif);
693 if (err)
694 goto err_vid_to_fid_rif_set;
695
696 err = mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, valid: true);
697 if (err)
698 goto err_erif_eport_to_vid_map;
699
700 fid->rif = rif;
701 return 0;
702
703err_erif_eport_to_vid_map:
704 mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
705err_vid_to_fid_rif_set:
706 mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
707err_vni_to_fid_rif_update:
708 mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
709 return err;
710}
711
712void mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid *fid)
713{
714 u16 rif_index;
715
716 if (!fid->rif)
717 return;
718
719 rif_index = mlxsw_sp_rif_index(rif: fid->rif);
720 fid->rif = NULL;
721
722 mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, valid: false);
723 mlxsw_sp_fid_vid_to_fid_rif_unset(fid);
724 mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL);
725 mlxsw_sp_fid_to_fid_rif_update(fid, NULL);
726}
727
728static int mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid *fid)
729{
730 int err;
731
732 err = mlxsw_sp_fid_vni_to_fid_map(fid, rif: fid->rif, valid: fid->vni_valid);
733 if (err)
734 return err;
735
736 err = mlxsw_sp_fid_edit_op(fid, rif: fid->rif);
737 if (err)
738 goto err_fid_edit_op;
739
740 return 0;
741
742err_fid_edit_op:
743 mlxsw_sp_fid_vni_to_fid_map(fid, rif: fid->rif, valid: !fid->vni_valid);
744 return err;
745}
746
747static int __mlxsw_sp_fid_port_vid_map(const struct mlxsw_sp_fid *fid,
748 u16 local_port, u16 vid, bool valid)
749{
750 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
751 char svfa_pl[MLXSW_REG_SVFA_LEN];
752 bool irif_valid = false;
753 u16 irif_index = 0;
754
755 if (fid->rif) {
756 irif_valid = true;
757 irif_index = mlxsw_sp_rif_index(rif: fid->rif);
758 }
759
760 mlxsw_reg_svfa_port_vid_pack(payload: svfa_pl, local_port, valid, fid: fid->fid_index,
761 vid, irif_v: irif_valid, irif: irif_index);
762 return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(svfa), payload: svfa_pl);
763}
764
765static struct mlxsw_sp_fid_8021d *
766mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
767{
768 return container_of(fid, struct mlxsw_sp_fid_8021d, common);
769}
770
771static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
772{
773 int br_ifindex = *(int *) arg;
774
775 mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
776 fid->fid_offset = fid->fid_index - fid->fid_family->start_index;
777}
778
779static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
780{
781 return mlxsw_sp_fid_op(fid, valid: true);
782}
783
784static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
785{
786 if (fid->vni_valid)
787 mlxsw_sp_nve_fid_disable(mlxsw_sp: fid->fid_family->mlxsw_sp, fid);
788 mlxsw_sp_fid_op(fid, valid: false);
789}
790
791static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
792 const void *arg, u16 *p_fid_index)
793{
794 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
795 u16 nr_fids, fid_index;
796
797 nr_fids = fid_family->end_index - fid_family->start_index + 1;
798 fid_index = find_first_zero_bit(addr: fid_family->fids_bitmap, size: nr_fids);
799 if (fid_index == nr_fids)
800 return -ENOBUFS;
801 *p_fid_index = fid_family->start_index + fid_index;
802
803 return 0;
804}
805
806static bool
807mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
808{
809 int br_ifindex = *(int *) arg;
810
811 return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
812}
813
814static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
815{
816 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
817 int err;
818
819 list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
820 list) {
821 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
822 u16 vid = mlxsw_sp_port_vlan->vid;
823
824 if (!fid)
825 continue;
826
827 err = __mlxsw_sp_fid_port_vid_map(fid,
828 local_port: mlxsw_sp_port->local_port,
829 vid, valid: true);
830 if (err)
831 goto err_fid_port_vid_map;
832 }
833
834 err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, enable: true);
835 if (err)
836 goto err_port_vp_mode_set;
837
838 return 0;
839
840err_port_vp_mode_set:
841err_fid_port_vid_map:
842 list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
843 &mlxsw_sp_port->vlans_list, list) {
844 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
845 u16 vid = mlxsw_sp_port_vlan->vid;
846
847 if (!fid)
848 continue;
849
850 __mlxsw_sp_fid_port_vid_map(fid, local_port: mlxsw_sp_port->local_port, vid,
851 valid: false);
852 }
853 return err;
854}
855
856static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
857{
858 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
859
860 mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, enable: false);
861
862 list_for_each_entry_reverse(mlxsw_sp_port_vlan,
863 &mlxsw_sp_port->vlans_list, list) {
864 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
865 u16 vid = mlxsw_sp_port_vlan->vid;
866
867 if (!fid)
868 continue;
869
870 __mlxsw_sp_fid_port_vid_map(fid, local_port: mlxsw_sp_port->local_port, vid,
871 valid: false);
872 }
873}
874
875static int
876mlxsw_sp_fid_port_vid_list_add(struct mlxsw_sp_fid *fid, u16 local_port,
877 u16 vid)
878{
879 struct mlxsw_sp_fid_port_vid *port_vid, *tmp_port_vid;
880
881 port_vid = kzalloc(size: sizeof(*port_vid), GFP_KERNEL);
882 if (!port_vid)
883 return -ENOMEM;
884
885 port_vid->local_port = local_port;
886 port_vid->vid = vid;
887
888 list_for_each_entry(tmp_port_vid, &fid->port_vid_list, list) {
889 if (tmp_port_vid->local_port > local_port)
890 break;
891 }
892
893 list_add_tail(new: &port_vid->list, head: &tmp_port_vid->list);
894 return 0;
895}
896
897static void
898mlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid *fid, u16 local_port,
899 u16 vid)
900{
901 struct mlxsw_sp_fid_port_vid *port_vid, *tmp;
902
903 list_for_each_entry_safe(port_vid, tmp, &fid->port_vid_list, list) {
904 if (port_vid->local_port != local_port || port_vid->vid != vid)
905 continue;
906
907 list_del(entry: &port_vid->list);
908 kfree(objp: port_vid);
909 return;
910 }
911}
912
913static int
914mlxsw_sp_fid_mpe_table_map(const struct mlxsw_sp_fid *fid, u16 local_port,
915 u16 vid, bool valid)
916{
917 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
918 char smpe_pl[MLXSW_REG_SMPE_LEN];
919
920 mlxsw_reg_smpe_pack(payload: smpe_pl, local_port, smpe_index: fid->fid_index,
921 evid: valid ? vid : 0);
922 return mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(smpe), payload: smpe_pl);
923}
924
925static int
926mlxsw_sp_fid_erif_eport_to_vid_map_one(const struct mlxsw_sp_fid *fid,
927 u16 local_port, u16 vid, bool valid)
928{
929 u8 port_page = local_port / MLXSW_REG_REIV_REC_MAX_COUNT;
930 u8 rec_num = local_port % MLXSW_REG_REIV_REC_MAX_COUNT;
931 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
932 u16 rif_index = mlxsw_sp_rif_index(rif: fid->rif);
933 char *reiv_pl;
934 int err;
935
936 reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL);
937 if (!reiv_pl)
938 return -ENOMEM;
939
940 mlxsw_reg_reiv_pack(payload: reiv_pl, port_page, erif: rif_index);
941 mlxsw_reg_reiv_rec_update_set(buf: reiv_pl, index: rec_num, val: true);
942 mlxsw_reg_reiv_rec_evid_set(buf: reiv_pl, index: rec_num, val: valid ? vid : 0);
943 err = mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(reiv), payload: reiv_pl);
944 kfree(objp: reiv_pl);
945 return err;
946}
947
948static int mlxsw_sp_fid_evid_map(const struct mlxsw_sp_fid *fid, u16 local_port,
949 u16 vid, bool valid)
950{
951 int err;
952
953 err = mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, valid);
954 if (err)
955 return err;
956
957 if (!fid->rif)
958 return 0;
959
960 err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
961 valid);
962 if (err)
963 goto err_erif_eport_to_vid_map_one;
964
965 return 0;
966
967err_erif_eport_to_vid_map_one:
968 mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, valid: !valid);
969 return err;
970}
971
972static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
973 struct mlxsw_sp_port *mlxsw_sp_port,
974 u16 vid)
975{
976 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
977 u16 local_port = mlxsw_sp_port->local_port;
978 int err;
979
980 err = __mlxsw_sp_fid_port_vid_map(fid, local_port: mlxsw_sp_port->local_port, vid,
981 valid: true);
982 if (err)
983 return err;
984
985 err = mlxsw_sp_fid_evid_map(fid, local_port, vid, valid: true);
986 if (err)
987 goto err_fid_evid_map;
988
989 err = mlxsw_sp_fid_port_vid_list_add(fid, local_port: mlxsw_sp_port->local_port,
990 vid);
991 if (err)
992 goto err_port_vid_list_add;
993
994 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
995 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
996 if (err)
997 goto err_port_vp_mode_trans;
998 }
999
1000 return 0;
1001
1002err_port_vp_mode_trans:
1003 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
1004 mlxsw_sp_fid_port_vid_list_del(fid, local_port: mlxsw_sp_port->local_port, vid);
1005err_port_vid_list_add:
1006 mlxsw_sp_fid_evid_map(fid, local_port, vid, valid: false);
1007err_fid_evid_map:
1008 __mlxsw_sp_fid_port_vid_map(fid, local_port: mlxsw_sp_port->local_port, vid, valid: false);
1009 return err;
1010}
1011
1012static void
1013mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
1014 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
1015{
1016 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1017 u16 local_port = mlxsw_sp_port->local_port;
1018
1019 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
1020 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
1021 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
1022 mlxsw_sp_fid_port_vid_list_del(fid, local_port: mlxsw_sp_port->local_port, vid);
1023 mlxsw_sp_fid_evid_map(fid, local_port, vid, valid: false);
1024 __mlxsw_sp_fid_port_vid_map(fid, local_port: mlxsw_sp_port->local_port, vid, valid: false);
1025}
1026
1027static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid)
1028{
1029 return mlxsw_sp_fid_vni_op(fid);
1030}
1031
1032static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
1033{
1034 mlxsw_sp_fid_vni_op(fid);
1035}
1036
1037static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1038{
1039 return mlxsw_sp_fid_edit_op(fid, rif: fid->rif);
1040}
1041
1042static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1043{
1044 mlxsw_sp_fid_edit_op(fid, rif: fid->rif);
1045}
1046
1047static void
1048mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
1049 const struct net_device *nve_dev)
1050{
1051 br_fdb_clear_offload(dev: nve_dev, vid: 0);
1052}
1053
1054static int
1055mlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
1056 const struct mlxsw_sp_rif *rif)
1057{
1058 return 0;
1059}
1060
1061static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
1062 .setup = mlxsw_sp_fid_8021d_setup,
1063 .configure = mlxsw_sp_fid_8021d_configure,
1064 .deconfigure = mlxsw_sp_fid_8021d_deconfigure,
1065 .index_alloc = mlxsw_sp_fid_8021d_index_alloc,
1066 .compare = mlxsw_sp_fid_8021d_compare,
1067 .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map,
1068 .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap,
1069 .vni_set = mlxsw_sp_fid_8021d_vni_set,
1070 .vni_clear = mlxsw_sp_fid_8021d_vni_clear,
1071 .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set,
1072 .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear,
1073 .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload,
1074 .vid_to_fid_rif_update = mlxsw_sp_fid_8021d_vid_to_fid_rif_update,
1075};
1076
1077#define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2)
1078#define MLXSW_SP_FID_RFID_MAX (11 * 1024)
1079
1080static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
1081 {
1082 .packet_type = MLXSW_SP_FLOOD_TYPE_UC,
1083 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
1084 .table_index = 0,
1085 },
1086 {
1087 .packet_type = MLXSW_SP_FLOOD_TYPE_MC,
1088 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
1089 .table_index = 1,
1090 },
1091 {
1092 .packet_type = MLXSW_SP_FLOOD_TYPE_BC,
1093 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
1094 .table_index = 2,
1095 },
1096};
1097
1098static bool
1099mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
1100{
1101 u16 vid = *(u16 *) arg;
1102
1103 return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
1104}
1105
1106static void
1107mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
1108 const struct net_device *nve_dev)
1109{
1110 br_fdb_clear_offload(dev: nve_dev, vid: mlxsw_sp_fid_8021q_vid(fid));
1111}
1112
1113static void mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid *fid, const void *arg)
1114{
1115 fid->fid_offset = 0;
1116}
1117
1118static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
1119{
1120 return mlxsw_sp_fid_op(fid, valid: true);
1121}
1122
1123static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
1124{
1125 mlxsw_sp_fid_op(fid, valid: false);
1126}
1127
1128static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
1129 const void *arg, u16 *p_fid_index)
1130{
1131 u16 rif_index = *(u16 *) arg;
1132
1133 *p_fid_index = fid->fid_family->start_index + rif_index;
1134
1135 return 0;
1136}
1137
1138static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
1139 const void *arg)
1140{
1141 u16 rif_index = *(u16 *) arg;
1142
1143 return fid->fid_index == rif_index + fid->fid_family->start_index;
1144}
1145
1146static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
1147 struct mlxsw_sp_port *mlxsw_sp_port,
1148 u16 vid)
1149{
1150 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1151 u16 local_port = mlxsw_sp_port->local_port;
1152 int err;
1153
1154 err = mlxsw_sp_fid_port_vid_list_add(fid, local_port: mlxsw_sp_port->local_port,
1155 vid);
1156 if (err)
1157 return err;
1158
1159 /* Using legacy bridge model, we only need to transition the port to
1160 * virtual mode since {Port, VID} => FID is done by the firmware upon
1161 * RIF creation. Using unified bridge model, we need to map
1162 * {Port, VID} => FID and map egress VID.
1163 */
1164 err = __mlxsw_sp_fid_port_vid_map(fid, local_port: mlxsw_sp_port->local_port, vid,
1165 valid: true);
1166 if (err)
1167 goto err_port_vid_map;
1168
1169 if (fid->rif) {
1170 err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port,
1171 vid, valid: true);
1172 if (err)
1173 goto err_erif_eport_to_vid_map_one;
1174 }
1175
1176 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
1177 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
1178 if (err)
1179 goto err_port_vp_mode_trans;
1180 }
1181
1182 return 0;
1183
1184err_port_vp_mode_trans:
1185 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
1186 if (fid->rif)
1187 mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
1188 valid: false);
1189err_erif_eport_to_vid_map_one:
1190 __mlxsw_sp_fid_port_vid_map(fid, local_port: mlxsw_sp_port->local_port, vid, valid: false);
1191err_port_vid_map:
1192 mlxsw_sp_fid_port_vid_list_del(fid, local_port: mlxsw_sp_port->local_port, vid);
1193 return err;
1194}
1195
1196static void
1197mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
1198 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
1199{
1200 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1201 u16 local_port = mlxsw_sp_port->local_port;
1202
1203 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
1204 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
1205 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
1206
1207 if (fid->rif)
1208 mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid,
1209 valid: false);
1210 __mlxsw_sp_fid_port_vid_map(fid, local_port: mlxsw_sp_port->local_port, vid, valid: false);
1211 mlxsw_sp_fid_port_vid_list_del(fid, local_port: mlxsw_sp_port->local_port, vid);
1212}
1213
1214static int mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid *fid)
1215{
1216 return -EOPNOTSUPP;
1217}
1218
1219static void mlxsw_sp_fid_rfid_vni_clear(struct mlxsw_sp_fid *fid)
1220{
1221 WARN_ON_ONCE(1);
1222}
1223
1224static int mlxsw_sp_fid_rfid_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1225{
1226 return -EOPNOTSUPP;
1227}
1228
1229static void mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1230{
1231 WARN_ON_ONCE(1);
1232}
1233
1234static int
1235mlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid,
1236 const struct mlxsw_sp_rif *rif)
1237{
1238 return 0;
1239}
1240
1241static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
1242 .setup = mlxsw_sp_fid_rfid_setup,
1243 .configure = mlxsw_sp_fid_rfid_configure,
1244 .deconfigure = mlxsw_sp_fid_rfid_deconfigure,
1245 .index_alloc = mlxsw_sp_fid_rfid_index_alloc,
1246 .compare = mlxsw_sp_fid_rfid_compare,
1247 .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map,
1248 .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap,
1249 .vni_set = mlxsw_sp_fid_rfid_vni_set,
1250 .vni_clear = mlxsw_sp_fid_rfid_vni_clear,
1251 .nve_flood_index_set = mlxsw_sp_fid_rfid_nve_flood_index_set,
1252 .nve_flood_index_clear = mlxsw_sp_fid_rfid_nve_flood_index_clear,
1253 .vid_to_fid_rif_update = mlxsw_sp_fid_rfid_vid_to_fid_rif_update,
1254};
1255
1256static void mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg)
1257{
1258 fid->fid_offset = 0;
1259}
1260
1261static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
1262{
1263 return mlxsw_sp_fid_op(fid, valid: true);
1264}
1265
1266static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
1267{
1268 mlxsw_sp_fid_op(fid, valid: false);
1269}
1270
1271static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
1272 const void *arg, u16 *p_fid_index)
1273{
1274 *p_fid_index = fid->fid_family->start_index;
1275
1276 return 0;
1277}
1278
1279static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
1280 const void *arg)
1281{
1282 return true;
1283}
1284
1285static int mlxsw_sp_fid_dummy_vni_set(struct mlxsw_sp_fid *fid)
1286{
1287 return -EOPNOTSUPP;
1288}
1289
1290static void mlxsw_sp_fid_dummy_vni_clear(struct mlxsw_sp_fid *fid)
1291{
1292 WARN_ON_ONCE(1);
1293}
1294
1295static int mlxsw_sp_fid_dummy_nve_flood_index_set(struct mlxsw_sp_fid *fid)
1296{
1297 return -EOPNOTSUPP;
1298}
1299
1300static void mlxsw_sp_fid_dummy_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
1301{
1302 WARN_ON_ONCE(1);
1303}
1304
1305static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
1306 .setup = mlxsw_sp_fid_dummy_setup,
1307 .configure = mlxsw_sp_fid_dummy_configure,
1308 .deconfigure = mlxsw_sp_fid_dummy_deconfigure,
1309 .index_alloc = mlxsw_sp_fid_dummy_index_alloc,
1310 .compare = mlxsw_sp_fid_dummy_compare,
1311 .vni_set = mlxsw_sp_fid_dummy_vni_set,
1312 .vni_clear = mlxsw_sp_fid_dummy_vni_clear,
1313 .nve_flood_index_set = mlxsw_sp_fid_dummy_nve_flood_index_set,
1314 .nve_flood_index_clear = mlxsw_sp_fid_dummy_nve_flood_index_clear,
1315};
1316
1317static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
1318{
1319 struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
1320 int err;
1321
1322 err = mlxsw_sp_fid_op(fid, valid: true);
1323 if (err)
1324 return err;
1325
1326 err = mlxsw_sp_fid_vid_to_fid_map(fid, vid: fid_8021q->vid, valid: true, rif: fid->rif);
1327 if (err)
1328 goto err_vid_to_fid_map;
1329
1330 return 0;
1331
1332err_vid_to_fid_map:
1333 mlxsw_sp_fid_op(fid, valid: false);
1334 return err;
1335}
1336
1337static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)
1338{
1339 struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
1340
1341 if (fid->vni_valid)
1342 mlxsw_sp_nve_fid_disable(mlxsw_sp: fid->fid_family->mlxsw_sp, fid);
1343
1344 mlxsw_sp_fid_vid_to_fid_map(fid, vid: fid_8021q->vid, valid: false, NULL);
1345 mlxsw_sp_fid_op(fid, valid: false);
1346}
1347
1348static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,
1349 struct mlxsw_sp_port *mlxsw_sp_port,
1350 u16 vid)
1351{
1352 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1353 u16 local_port = mlxsw_sp_port->local_port;
1354 int err;
1355
1356 /* In case there are no {Port, VID} => FID mappings on the port,
1357 * we can use the global VID => FID mapping we created when the
1358 * FID was configured, otherwise, configure new mapping.
1359 */
1360 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]) {
1361 err = __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, valid: true);
1362 if (err)
1363 return err;
1364 }
1365
1366 err = mlxsw_sp_fid_evid_map(fid, local_port, vid, valid: true);
1367 if (err)
1368 goto err_fid_evid_map;
1369
1370 err = mlxsw_sp_fid_port_vid_list_add(fid, local_port: mlxsw_sp_port->local_port,
1371 vid);
1372 if (err)
1373 goto err_port_vid_list_add;
1374
1375 return 0;
1376
1377err_port_vid_list_add:
1378 mlxsw_sp_fid_evid_map(fid, local_port, vid, valid: false);
1379err_fid_evid_map:
1380 if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
1381 __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, valid: false);
1382 return err;
1383}
1384
1385static void
1386mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
1387 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
1388{
1389 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1390 u16 local_port = mlxsw_sp_port->local_port;
1391
1392 mlxsw_sp_fid_port_vid_list_del(fid, local_port: mlxsw_sp_port->local_port, vid);
1393 mlxsw_sp_fid_evid_map(fid, local_port, vid, valid: false);
1394 if (mlxsw_sp->fid_core->port_fid_mappings[local_port])
1395 __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, valid: false);
1396}
1397
1398static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
1399 .setup = mlxsw_sp_fid_8021q_setup,
1400 .configure = mlxsw_sp_fid_8021q_configure,
1401 .deconfigure = mlxsw_sp_fid_8021q_deconfigure,
1402 .index_alloc = mlxsw_sp_fid_8021d_index_alloc,
1403 .compare = mlxsw_sp_fid_8021q_compare,
1404 .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map,
1405 .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap,
1406 .vni_set = mlxsw_sp_fid_8021d_vni_set,
1407 .vni_clear = mlxsw_sp_fid_8021d_vni_clear,
1408 .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set,
1409 .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear,
1410 .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload,
1411 .vid_to_fid_rif_update = mlxsw_sp_fid_8021q_vid_to_fid_rif_update,
1412};
1413
1414/* There are 4K-2 802.1Q FIDs */
1415#define MLXSW_SP_FID_8021Q_START 1 /* FID 0 is reserved. */
1416#define MLXSW_SP_FID_8021Q_END (MLXSW_SP_FID_8021Q_START + \
1417 MLXSW_SP_FID_8021Q_MAX - 1)
1418
1419/* There are 1K 802.1D FIDs */
1420#define MLXSW_SP_FID_8021D_START (MLXSW_SP_FID_8021Q_END + 1)
1421#define MLXSW_SP_FID_8021D_END (MLXSW_SP_FID_8021D_START + \
1422 MLXSW_SP_FID_8021D_MAX - 1)
1423
1424/* There is one dummy FID */
1425#define MLXSW_SP_FID_DUMMY (MLXSW_SP_FID_8021D_END + 1)
1426
1427/* There are 11K rFIDs */
1428#define MLXSW_SP_RFID_START (MLXSW_SP_FID_DUMMY + 1)
1429#define MLXSW_SP_RFID_END (MLXSW_SP_RFID_START + \
1430 MLXSW_SP_FID_RFID_MAX - 1)
1431
1432static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_family = {
1433 .type = MLXSW_SP_FID_TYPE_8021Q,
1434 .fid_size = sizeof(struct mlxsw_sp_fid_8021q),
1435 .start_index = MLXSW_SP_FID_8021Q_START,
1436 .end_index = MLXSW_SP_FID_8021Q_END,
1437 .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
1438 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1439 .rif_type = MLXSW_SP_RIF_TYPE_VLAN,
1440 .ops = &mlxsw_sp_fid_8021q_ops,
1441 .flood_rsp = false,
1442 .bridge_type = MLXSW_REG_BRIDGE_TYPE_0,
1443 .smpe_index_valid = false,
1444};
1445
1446static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_family = {
1447 .type = MLXSW_SP_FID_TYPE_8021D,
1448 .fid_size = sizeof(struct mlxsw_sp_fid_8021d),
1449 .start_index = MLXSW_SP_FID_8021D_START,
1450 .end_index = MLXSW_SP_FID_8021D_END,
1451 .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
1452 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1453 .rif_type = MLXSW_SP_RIF_TYPE_FID,
1454 .ops = &mlxsw_sp_fid_8021d_ops,
1455 .bridge_type = MLXSW_REG_BRIDGE_TYPE_1,
1456 .smpe_index_valid = false,
1457};
1458
1459static const struct mlxsw_sp_fid_family mlxsw_sp1_fid_dummy_family = {
1460 .type = MLXSW_SP_FID_TYPE_DUMMY,
1461 .fid_size = sizeof(struct mlxsw_sp_fid),
1462 .start_index = MLXSW_SP_FID_DUMMY,
1463 .end_index = MLXSW_SP_FID_DUMMY,
1464 .ops = &mlxsw_sp_fid_dummy_ops,
1465 .smpe_index_valid = false,
1466};
1467
1468static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
1469 .type = MLXSW_SP_FID_TYPE_RFID,
1470 .fid_size = sizeof(struct mlxsw_sp_fid),
1471 .start_index = MLXSW_SP_RFID_START,
1472 .end_index = MLXSW_SP_RFID_END,
1473 .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT,
1474 .ops = &mlxsw_sp_fid_rfid_ops,
1475 .flood_rsp = true,
1476 .smpe_index_valid = false,
1477};
1478
1479const struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = {
1480 [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp1_fid_8021q_family,
1481 [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp1_fid_8021d_family,
1482 [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp1_fid_dummy_family,
1483 [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family,
1484};
1485
1486static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family = {
1487 .type = MLXSW_SP_FID_TYPE_8021Q,
1488 .fid_size = sizeof(struct mlxsw_sp_fid_8021q),
1489 .start_index = MLXSW_SP_FID_8021Q_START,
1490 .end_index = MLXSW_SP_FID_8021Q_END,
1491 .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
1492 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1493 .rif_type = MLXSW_SP_RIF_TYPE_VLAN,
1494 .ops = &mlxsw_sp_fid_8021q_ops,
1495 .flood_rsp = false,
1496 .bridge_type = MLXSW_REG_BRIDGE_TYPE_0,
1497 .smpe_index_valid = true,
1498};
1499
1500static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family = {
1501 .type = MLXSW_SP_FID_TYPE_8021D,
1502 .fid_size = sizeof(struct mlxsw_sp_fid_8021d),
1503 .start_index = MLXSW_SP_FID_8021D_START,
1504 .end_index = MLXSW_SP_FID_8021D_END,
1505 .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
1506 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
1507 .rif_type = MLXSW_SP_RIF_TYPE_FID,
1508 .ops = &mlxsw_sp_fid_8021d_ops,
1509 .bridge_type = MLXSW_REG_BRIDGE_TYPE_1,
1510 .smpe_index_valid = true,
1511};
1512
1513static const struct mlxsw_sp_fid_family mlxsw_sp2_fid_dummy_family = {
1514 .type = MLXSW_SP_FID_TYPE_DUMMY,
1515 .fid_size = sizeof(struct mlxsw_sp_fid),
1516 .start_index = MLXSW_SP_FID_DUMMY,
1517 .end_index = MLXSW_SP_FID_DUMMY,
1518 .ops = &mlxsw_sp_fid_dummy_ops,
1519 .smpe_index_valid = false,
1520};
1521
1522const struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[] = {
1523 [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family,
1524 [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family,
1525 [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp2_fid_dummy_family,
1526 [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family,
1527};
1528
1529static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,
1530 enum mlxsw_sp_fid_type type,
1531 const void *arg)
1532{
1533 struct mlxsw_sp_fid_family *fid_family;
1534 struct mlxsw_sp_fid *fid;
1535
1536 fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
1537 list_for_each_entry(fid, &fid_family->fids_list, list) {
1538 if (!fid->fid_family->ops->compare(fid, arg))
1539 continue;
1540 refcount_inc(r: &fid->ref_count);
1541 return fid;
1542 }
1543
1544 return NULL;
1545}
1546
1547static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
1548 enum mlxsw_sp_fid_type type,
1549 const void *arg)
1550{
1551 struct mlxsw_sp_fid_family *fid_family;
1552 struct mlxsw_sp_fid *fid;
1553 u16 fid_index;
1554 int err;
1555
1556 fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg);
1557 if (fid)
1558 return fid;
1559
1560 fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
1561 fid = kzalloc(size: fid_family->fid_size, GFP_KERNEL);
1562 if (!fid)
1563 return ERR_PTR(error: -ENOMEM);
1564
1565 INIT_LIST_HEAD(list: &fid->port_vid_list);
1566 fid->fid_family = fid_family;
1567
1568 err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
1569 if (err)
1570 goto err_index_alloc;
1571 fid->fid_index = fid_index;
1572 __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
1573
1574 fid->fid_family->ops->setup(fid, arg);
1575
1576 err = fid->fid_family->ops->configure(fid);
1577 if (err)
1578 goto err_configure;
1579
1580 err = rhashtable_insert_fast(ht: &mlxsw_sp->fid_core->fid_ht, obj: &fid->ht_node,
1581 params: mlxsw_sp_fid_ht_params);
1582 if (err)
1583 goto err_rhashtable_insert;
1584
1585 list_add(new: &fid->list, head: &fid_family->fids_list);
1586 refcount_set(r: &fid->ref_count, n: 1);
1587 return fid;
1588
1589err_rhashtable_insert:
1590 fid->fid_family->ops->deconfigure(fid);
1591err_configure:
1592 __clear_bit(fid_index - fid_family->start_index,
1593 fid_family->fids_bitmap);
1594err_index_alloc:
1595 kfree(objp: fid);
1596 return ERR_PTR(error: err);
1597}
1598
1599void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
1600{
1601 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
1602 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1603
1604 if (!refcount_dec_and_test(r: &fid->ref_count))
1605 return;
1606
1607 list_del(entry: &fid->list);
1608 rhashtable_remove_fast(ht: &mlxsw_sp->fid_core->fid_ht,
1609 obj: &fid->ht_node, params: mlxsw_sp_fid_ht_params);
1610 fid->fid_family->ops->deconfigure(fid);
1611 __clear_bit(fid->fid_index - fid_family->start_index,
1612 fid_family->fids_bitmap);
1613 WARN_ON_ONCE(!list_empty(&fid->port_vid_list));
1614 kfree(objp: fid);
1615}
1616
1617struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
1618{
1619 return mlxsw_sp_fid_get(mlxsw_sp, type: MLXSW_SP_FID_TYPE_8021Q, arg: &vid);
1620}
1621
1622struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
1623 int br_ifindex)
1624{
1625 return mlxsw_sp_fid_get(mlxsw_sp, type: MLXSW_SP_FID_TYPE_8021D, arg: &br_ifindex);
1626}
1627
1628struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp,
1629 u16 vid)
1630{
1631 return mlxsw_sp_fid_lookup(mlxsw_sp, type: MLXSW_SP_FID_TYPE_8021Q, arg: &vid);
1632}
1633
1634struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
1635 int br_ifindex)
1636{
1637 return mlxsw_sp_fid_lookup(mlxsw_sp, type: MLXSW_SP_FID_TYPE_8021D,
1638 arg: &br_ifindex);
1639}
1640
1641struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
1642 u16 rif_index)
1643{
1644 return mlxsw_sp_fid_get(mlxsw_sp, type: MLXSW_SP_FID_TYPE_RFID, arg: &rif_index);
1645}
1646
1647struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
1648{
1649 return mlxsw_sp_fid_get(mlxsw_sp, type: MLXSW_SP_FID_TYPE_DUMMY, NULL);
1650}
1651
1652static int
1653mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
1654 const struct mlxsw_sp_flood_table *flood_table)
1655{
1656 enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
1657 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1658 const int *sfgc_packet_types;
1659 u16 mid_base;
1660 int err, i;
1661
1662 mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, fid_offset: 0);
1663
1664 sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
1665 for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
1666 char sfgc_pl[MLXSW_REG_SFGC_LEN];
1667
1668 if (!sfgc_packet_types[i])
1669 continue;
1670
1671 mlxsw_reg_sfgc_pack(payload: sfgc_pl, type: i, bridge_type: fid_family->bridge_type,
1672 table_type: flood_table->table_type, flood_table: 0, mid_base);
1673
1674 err = mlxsw_reg_write(mlxsw_core: mlxsw_sp->core, MLXSW_REG(sfgc), payload: sfgc_pl);
1675 if (err)
1676 return err;
1677 }
1678
1679 return 0;
1680}
1681
1682static int
1683mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
1684{
1685 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1686 u16 pgt_size;
1687 int err;
1688 int i;
1689
1690 if (!fid_family->nr_flood_tables)
1691 return 0;
1692
1693 pgt_size = mlxsw_sp_fid_family_pgt_size(fid_family);
1694 err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, mid_base: &fid_family->pgt_base,
1695 count: pgt_size);
1696 if (err)
1697 return err;
1698
1699 for (i = 0; i < fid_family->nr_flood_tables; i++) {
1700 const struct mlxsw_sp_flood_table *flood_table;
1701
1702 flood_table = &fid_family->flood_tables[i];
1703 err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
1704 if (err)
1705 goto err_flood_table_init;
1706 }
1707
1708 return 0;
1709
1710err_flood_table_init:
1711 mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base: fid_family->pgt_base, count: pgt_size);
1712 return err;
1713}
1714
1715static void
1716mlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family)
1717{
1718 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1719 u16 pgt_size;
1720
1721 if (!fid_family->nr_flood_tables)
1722 return;
1723
1724 pgt_size = mlxsw_sp_fid_family_pgt_size(fid_family);
1725 mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base: fid_family->pgt_base, count: pgt_size);
1726}
1727
1728static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
1729 const struct mlxsw_sp_fid_family *tmpl)
1730{
1731 u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
1732 struct mlxsw_sp_fid_family *fid_family;
1733 int err;
1734
1735 fid_family = kmemdup(p: tmpl, size: sizeof(*fid_family), GFP_KERNEL);
1736 if (!fid_family)
1737 return -ENOMEM;
1738
1739 fid_family->mlxsw_sp = mlxsw_sp;
1740 INIT_LIST_HEAD(list: &fid_family->fids_list);
1741 fid_family->fids_bitmap = bitmap_zalloc(nbits: nr_fids, GFP_KERNEL);
1742 if (!fid_family->fids_bitmap) {
1743 err = -ENOMEM;
1744 goto err_alloc_fids_bitmap;
1745 }
1746
1747 if (fid_family->flood_tables) {
1748 err = mlxsw_sp_fid_flood_tables_init(fid_family);
1749 if (err)
1750 goto err_fid_flood_tables_init;
1751 }
1752
1753 mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
1754
1755 return 0;
1756
1757err_fid_flood_tables_init:
1758 bitmap_free(bitmap: fid_family->fids_bitmap);
1759err_alloc_fids_bitmap:
1760 kfree(objp: fid_family);
1761 return err;
1762}
1763
1764static void
1765mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
1766 struct mlxsw_sp_fid_family *fid_family)
1767{
1768 mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
1769
1770 if (fid_family->flood_tables)
1771 mlxsw_sp_fid_flood_tables_fini(fid_family);
1772
1773 bitmap_free(bitmap: fid_family->fids_bitmap);
1774 WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
1775 kfree(objp: fid_family);
1776}
1777
1778int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
1779{
1780 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1781
1782 /* Track number of FIDs configured on the port with mapping type
1783 * PORT_VID_TO_FID, so that we know when to transition the port
1784 * back to non-virtual (VLAN) mode.
1785 */
1786 mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1787
1788 return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, enable: false);
1789}
1790
1791void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
1792{
1793 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1794
1795 mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1796}
1797
1798int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
1799{
1800 unsigned int max_ports = mlxsw_core_max_ports(mlxsw_core: mlxsw_sp->core);
1801 struct mlxsw_sp_fid_core *fid_core;
1802 int err, i;
1803
1804 fid_core = kzalloc(size: sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
1805 if (!fid_core)
1806 return -ENOMEM;
1807 mlxsw_sp->fid_core = fid_core;
1808
1809 err = rhashtable_init(ht: &fid_core->fid_ht, params: &mlxsw_sp_fid_ht_params);
1810 if (err)
1811 goto err_rhashtable_fid_init;
1812
1813 err = rhashtable_init(ht: &fid_core->vni_ht, params: &mlxsw_sp_fid_vni_ht_params);
1814 if (err)
1815 goto err_rhashtable_vni_init;
1816
1817 fid_core->port_fid_mappings = kcalloc(n: max_ports, size: sizeof(unsigned int),
1818 GFP_KERNEL);
1819 if (!fid_core->port_fid_mappings) {
1820 err = -ENOMEM;
1821 goto err_alloc_port_fid_mappings;
1822 }
1823
1824 for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
1825 err = mlxsw_sp_fid_family_register(mlxsw_sp,
1826 tmpl: mlxsw_sp->fid_family_arr[i]);
1827
1828 if (err)
1829 goto err_fid_ops_register;
1830 }
1831
1832 return 0;
1833
1834err_fid_ops_register:
1835 for (i--; i >= 0; i--) {
1836 struct mlxsw_sp_fid_family *fid_family;
1837
1838 fid_family = fid_core->fid_family_arr[i];
1839 mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
1840 }
1841 kfree(objp: fid_core->port_fid_mappings);
1842err_alloc_port_fid_mappings:
1843 rhashtable_destroy(ht: &fid_core->vni_ht);
1844err_rhashtable_vni_init:
1845 rhashtable_destroy(ht: &fid_core->fid_ht);
1846err_rhashtable_fid_init:
1847 kfree(objp: fid_core);
1848 return err;
1849}
1850
1851void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
1852{
1853 struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
1854 int i;
1855
1856 for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
1857 mlxsw_sp_fid_family_unregister(mlxsw_sp,
1858 fid_family: fid_core->fid_family_arr[i]);
1859 kfree(objp: fid_core->port_fid_mappings);
1860 rhashtable_destroy(ht: &fid_core->vni_ht);
1861 rhashtable_destroy(ht: &fid_core->fid_ht);
1862 kfree(objp: fid_core);
1863}
1864

source code of linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c