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