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