1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
4 #include <linux/kernel.h>
5 #include <linux/bitops.h>
6 #include <linux/if_vlan.h>
7 #include <linux/if_bridge.h>
8 #include <linux/netdevice.h>
9 #include <linux/rhashtable.h>
10 #include <linux/rtnetlink.h>
15 struct mlxsw_sp_fid_family
;
17 struct mlxsw_sp_fid_core
{
18 struct rhashtable vni_ht
;
19 struct mlxsw_sp_fid_family
*fid_family_arr
[MLXSW_SP_FID_TYPE_MAX
];
20 unsigned int *port_fid_mappings
;
24 struct list_head list
;
25 struct mlxsw_sp_rif
*rif
;
26 unsigned int ref_count
;
28 struct mlxsw_sp_fid_family
*fid_family
;
30 struct rhash_head vni_ht_node
;
34 nve_flood_index_valid
:1;
37 struct mlxsw_sp_fid_8021q
{
38 struct mlxsw_sp_fid common
;
42 struct mlxsw_sp_fid_8021d
{
43 struct mlxsw_sp_fid common
;
47 static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params
= {
48 .key_len
= sizeof_field(struct mlxsw_sp_fid
, vni
),
49 .key_offset
= offsetof(struct mlxsw_sp_fid
, vni
),
50 .head_offset
= offsetof(struct mlxsw_sp_fid
, vni_ht_node
),
53 struct mlxsw_sp_flood_table
{
54 enum mlxsw_sp_flood_type packet_type
;
55 enum mlxsw_reg_sfgc_bridge_type bridge_type
;
56 enum mlxsw_flood_table_type table_type
;
60 struct mlxsw_sp_fid_ops
{
61 void (*setup
)(struct mlxsw_sp_fid
*fid
, const void *arg
);
62 int (*configure
)(struct mlxsw_sp_fid
*fid
);
63 void (*deconfigure
)(struct mlxsw_sp_fid
*fid
);
64 int (*index_alloc
)(struct mlxsw_sp_fid
*fid
, const void *arg
,
66 bool (*compare
)(const struct mlxsw_sp_fid
*fid
,
68 u16 (*flood_index
)(const struct mlxsw_sp_fid
*fid
);
69 int (*port_vid_map
)(struct mlxsw_sp_fid
*fid
,
70 struct mlxsw_sp_port
*port
, u16 vid
);
71 void (*port_vid_unmap
)(struct mlxsw_sp_fid
*fid
,
72 struct mlxsw_sp_port
*port
, u16 vid
);
73 int (*vni_set
)(struct mlxsw_sp_fid
*fid
, __be32 vni
);
74 void (*vni_clear
)(struct mlxsw_sp_fid
*fid
);
75 int (*nve_flood_index_set
)(struct mlxsw_sp_fid
*fid
,
77 void (*nve_flood_index_clear
)(struct mlxsw_sp_fid
*fid
);
80 struct mlxsw_sp_fid_family
{
81 enum mlxsw_sp_fid_type type
;
85 struct list_head fids_list
;
86 unsigned long *fids_bitmap
;
87 const struct mlxsw_sp_flood_table
*flood_tables
;
89 enum mlxsw_sp_rif_type rif_type
;
90 const struct mlxsw_sp_fid_ops
*ops
;
91 struct mlxsw_sp
*mlxsw_sp
;
94 static const int mlxsw_sp_sfgc_uc_packet_types
[MLXSW_REG_SFGC_TYPE_MAX
] = {
95 [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST
] = 1,
98 static const int mlxsw_sp_sfgc_bc_packet_types
[MLXSW_REG_SFGC_TYPE_MAX
] = {
99 [MLXSW_REG_SFGC_TYPE_BROADCAST
] = 1,
100 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP
] = 1,
101 [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL
] = 1,
102 [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST
] = 1,
103 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6
] = 1,
106 static const int mlxsw_sp_sfgc_mc_packet_types
[MLXSW_REG_SFGC_TYPE_MAX
] = {
107 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4
] = 1,
110 static const int *mlxsw_sp_packet_type_sfgc_types
[] = {
111 [MLXSW_SP_FLOOD_TYPE_UC
] = mlxsw_sp_sfgc_uc_packet_types
,
112 [MLXSW_SP_FLOOD_TYPE_BC
] = mlxsw_sp_sfgc_bc_packet_types
,
113 [MLXSW_SP_FLOOD_TYPE_MC
] = mlxsw_sp_sfgc_mc_packet_types
,
116 int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid
*fid
, __be32
*vni
)
126 int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid
*fid
,
129 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
130 const struct mlxsw_sp_fid_ops
*ops
= fid_family
->ops
;
133 if (WARN_ON(!ops
->nve_flood_index_set
|| fid
->nve_flood_index_valid
))
136 err
= ops
->nve_flood_index_set(fid
, nve_flood_index
);
140 fid
->nve_flood_index
= nve_flood_index
;
141 fid
->nve_flood_index_valid
= true;
146 void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid
*fid
)
148 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
149 const struct mlxsw_sp_fid_ops
*ops
= fid_family
->ops
;
151 if (WARN_ON(!ops
->nve_flood_index_clear
|| !fid
->nve_flood_index_valid
))
154 fid
->nve_flood_index_valid
= false;
155 ops
->nve_flood_index_clear(fid
);
158 bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid
*fid
)
160 return fid
->nve_flood_index_valid
;
163 int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid
*fid
, __be32 vni
)
165 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
166 const struct mlxsw_sp_fid_ops
*ops
= fid_family
->ops
;
167 struct mlxsw_sp
*mlxsw_sp
= fid_family
->mlxsw_sp
;
170 if (WARN_ON(!ops
->vni_set
|| fid
->vni_valid
))
174 err
= rhashtable_lookup_insert_fast(&mlxsw_sp
->fid_core
->vni_ht
,
176 mlxsw_sp_fid_vni_ht_params
);
180 err
= ops
->vni_set(fid
, vni
);
184 fid
->vni_valid
= true;
189 rhashtable_remove_fast(&mlxsw_sp
->fid_core
->vni_ht
, &fid
->vni_ht_node
,
190 mlxsw_sp_fid_vni_ht_params
);
194 void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid
*fid
)
196 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
197 const struct mlxsw_sp_fid_ops
*ops
= fid_family
->ops
;
198 struct mlxsw_sp
*mlxsw_sp
= fid_family
->mlxsw_sp
;
200 if (WARN_ON(!ops
->vni_clear
|| !fid
->vni_valid
))
203 fid
->vni_valid
= false;
205 rhashtable_remove_fast(&mlxsw_sp
->fid_core
->vni_ht
, &fid
->vni_ht_node
,
206 mlxsw_sp_fid_vni_ht_params
);
209 bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid
*fid
)
211 return fid
->vni_valid
;
214 static const struct mlxsw_sp_flood_table
*
215 mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid
*fid
,
216 enum mlxsw_sp_flood_type packet_type
)
218 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
221 for (i
= 0; i
< fid_family
->nr_flood_tables
; i
++) {
222 if (fid_family
->flood_tables
[i
].packet_type
!= packet_type
)
224 return &fid_family
->flood_tables
[i
];
230 int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid
*fid
,
231 enum mlxsw_sp_flood_type packet_type
, u8 local_port
,
234 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
235 const struct mlxsw_sp_fid_ops
*ops
= fid_family
->ops
;
236 const struct mlxsw_sp_flood_table
*flood_table
;
240 if (WARN_ON(!fid_family
->flood_tables
|| !ops
->flood_index
))
243 flood_table
= mlxsw_sp_fid_flood_table_lookup(fid
, packet_type
);
247 sftr_pl
= kmalloc(MLXSW_REG_SFTR_LEN
, GFP_KERNEL
);
251 mlxsw_reg_sftr_pack(sftr_pl
, flood_table
->table_index
,
252 ops
->flood_index(fid
), flood_table
->table_type
, 1,
254 err
= mlxsw_reg_write(fid_family
->mlxsw_sp
->core
, MLXSW_REG(sftr
),
260 int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid
*fid
,
261 struct mlxsw_sp_port
*mlxsw_sp_port
, u16 vid
)
263 if (WARN_ON(!fid
->fid_family
->ops
->port_vid_map
))
265 return fid
->fid_family
->ops
->port_vid_map(fid
, mlxsw_sp_port
, vid
);
268 void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid
*fid
,
269 struct mlxsw_sp_port
*mlxsw_sp_port
, u16 vid
)
271 fid
->fid_family
->ops
->port_vid_unmap(fid
, mlxsw_sp_port
, vid
);
274 enum mlxsw_sp_rif_type
mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid
*fid
)
276 return fid
->fid_family
->rif_type
;
279 u16
mlxsw_sp_fid_index(const struct mlxsw_sp_fid
*fid
)
281 return fid
->fid_index
;
284 enum mlxsw_sp_fid_type
mlxsw_sp_fid_type(const struct mlxsw_sp_fid
*fid
)
286 return fid
->fid_family
->type
;
289 void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid
*fid
, struct mlxsw_sp_rif
*rif
)
294 enum mlxsw_sp_rif_type
295 mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp
*mlxsw_sp
,
296 enum mlxsw_sp_fid_type type
)
298 struct mlxsw_sp_fid_core
*fid_core
= mlxsw_sp
->fid_core
;
300 return fid_core
->fid_family_arr
[type
]->rif_type
;
303 static struct mlxsw_sp_fid_8021q
*
304 mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid
*fid
)
306 return container_of(fid
, struct mlxsw_sp_fid_8021q
, common
);
309 u16
mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid
*fid
)
311 return mlxsw_sp_fid_8021q_fid(fid
)->vid
;
314 static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid
*fid
, const void *arg
)
316 u16 vid
= *(u16
*) arg
;
318 mlxsw_sp_fid_8021q_fid(fid
)->vid
= vid
;
321 static enum mlxsw_reg_sfmr_op
mlxsw_sp_sfmr_op(bool valid
)
323 return valid
? MLXSW_REG_SFMR_OP_CREATE_FID
:
324 MLXSW_REG_SFMR_OP_DESTROY_FID
;
327 static int mlxsw_sp_fid_op(struct mlxsw_sp
*mlxsw_sp
, u16 fid_index
,
328 u16 fid_offset
, bool valid
)
330 char sfmr_pl
[MLXSW_REG_SFMR_LEN
];
332 mlxsw_reg_sfmr_pack(sfmr_pl
, mlxsw_sp_sfmr_op(valid
), fid_index
,
334 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(sfmr
), sfmr_pl
);
337 static int mlxsw_sp_fid_vni_op(struct mlxsw_sp
*mlxsw_sp
, u16 fid_index
,
338 __be32 vni
, bool vni_valid
, u32 nve_flood_index
,
339 bool nve_flood_index_valid
)
341 char sfmr_pl
[MLXSW_REG_SFMR_LEN
];
343 mlxsw_reg_sfmr_pack(sfmr_pl
, MLXSW_REG_SFMR_OP_CREATE_FID
, fid_index
,
345 mlxsw_reg_sfmr_vv_set(sfmr_pl
, vni_valid
);
346 mlxsw_reg_sfmr_vni_set(sfmr_pl
, be32_to_cpu(vni
));
347 mlxsw_reg_sfmr_vtfp_set(sfmr_pl
, nve_flood_index_valid
);
348 mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl
, nve_flood_index
);
349 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(sfmr
), sfmr_pl
);
352 static int mlxsw_sp_fid_vid_map(struct mlxsw_sp
*mlxsw_sp
, u16 fid_index
,
355 enum mlxsw_reg_svfa_mt mt
= MLXSW_REG_SVFA_MT_VID_TO_FID
;
356 char svfa_pl
[MLXSW_REG_SVFA_LEN
];
358 mlxsw_reg_svfa_pack(svfa_pl
, 0, mt
, valid
, fid_index
, vid
);
359 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(svfa
), svfa_pl
);
362 static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp
*mlxsw_sp
, u16 fid_index
,
363 u8 local_port
, u16 vid
, bool valid
)
365 enum mlxsw_reg_svfa_mt mt
= MLXSW_REG_SVFA_MT_PORT_VID_TO_FID
;
366 char svfa_pl
[MLXSW_REG_SVFA_LEN
];
368 mlxsw_reg_svfa_pack(svfa_pl
, local_port
, mt
, valid
, fid_index
, vid
);
369 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(svfa
), svfa_pl
);
372 static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid
*fid
)
374 struct mlxsw_sp
*mlxsw_sp
= fid
->fid_family
->mlxsw_sp
;
375 struct mlxsw_sp_fid_8021q
*fid_8021q
;
378 err
= mlxsw_sp_fid_op(mlxsw_sp
, fid
->fid_index
, fid
->fid_index
, true);
382 fid_8021q
= mlxsw_sp_fid_8021q_fid(fid
);
383 err
= mlxsw_sp_fid_vid_map(mlxsw_sp
, fid
->fid_index
, fid_8021q
->vid
,
391 mlxsw_sp_fid_op(mlxsw_sp
, fid
->fid_index
, 0, false);
395 static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid
*fid
)
397 struct mlxsw_sp
*mlxsw_sp
= fid
->fid_family
->mlxsw_sp
;
398 struct mlxsw_sp_fid_8021q
*fid_8021q
;
400 fid_8021q
= mlxsw_sp_fid_8021q_fid(fid
);
401 mlxsw_sp_fid_vid_map(mlxsw_sp
, fid
->fid_index
, fid_8021q
->vid
, false);
402 mlxsw_sp_fid_op(mlxsw_sp
, fid
->fid_index
, 0, false);
405 static int mlxsw_sp_fid_8021q_index_alloc(struct mlxsw_sp_fid
*fid
,
406 const void *arg
, u16
*p_fid_index
)
408 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
409 u16 vid
= *(u16
*) arg
;
411 /* Use 1:1 mapping for simplicity although not a must */
412 if (vid
< fid_family
->start_index
|| vid
> fid_family
->end_index
)
420 mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid
*fid
, const void *arg
)
422 u16 vid
= *(u16
*) arg
;
424 return mlxsw_sp_fid_8021q_fid(fid
)->vid
== vid
;
427 static u16
mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid
*fid
)
429 return fid
->fid_index
;
432 static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid
*fid
,
433 struct mlxsw_sp_port
*mlxsw_sp_port
,
436 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
437 u8 local_port
= mlxsw_sp_port
->local_port
;
439 /* In case there are no {Port, VID} => FID mappings on the port,
440 * we can use the global VID => FID mapping we created when the
441 * FID was configured.
443 if (mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
] == 0)
445 return __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
, local_port
,
450 mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid
*fid
,
451 struct mlxsw_sp_port
*mlxsw_sp_port
, u16 vid
)
453 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
454 u8 local_port
= mlxsw_sp_port
->local_port
;
456 if (mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
] == 0)
458 __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
, local_port
, vid
,
462 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops
= {
463 .setup
= mlxsw_sp_fid_8021q_setup
,
464 .configure
= mlxsw_sp_fid_8021q_configure
,
465 .deconfigure
= mlxsw_sp_fid_8021q_deconfigure
,
466 .index_alloc
= mlxsw_sp_fid_8021q_index_alloc
,
467 .compare
= mlxsw_sp_fid_8021q_compare
,
468 .flood_index
= mlxsw_sp_fid_8021q_flood_index
,
469 .port_vid_map
= mlxsw_sp_fid_8021q_port_vid_map
,
470 .port_vid_unmap
= mlxsw_sp_fid_8021q_port_vid_unmap
,
473 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021q_flood_tables
[] = {
475 .packet_type
= MLXSW_SP_FLOOD_TYPE_UC
,
476 .bridge_type
= MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID
,
477 .table_type
= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET
,
481 .packet_type
= MLXSW_SP_FLOOD_TYPE_MC
,
482 .bridge_type
= MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID
,
483 .table_type
= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET
,
487 .packet_type
= MLXSW_SP_FLOOD_TYPE_BC
,
488 .bridge_type
= MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID
,
489 .table_type
= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET
,
494 /* Range and flood configuration must match mlxsw_config_profile */
495 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_family
= {
496 .type
= MLXSW_SP_FID_TYPE_8021Q
,
497 .fid_size
= sizeof(struct mlxsw_sp_fid_8021q
),
499 .end_index
= VLAN_VID_MASK
,
500 .flood_tables
= mlxsw_sp_fid_8021q_flood_tables
,
501 .nr_flood_tables
= ARRAY_SIZE(mlxsw_sp_fid_8021q_flood_tables
),
502 .rif_type
= MLXSW_SP_RIF_TYPE_VLAN
,
503 .ops
= &mlxsw_sp_fid_8021q_ops
,
506 static struct mlxsw_sp_fid_8021d
*
507 mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid
*fid
)
509 return container_of(fid
, struct mlxsw_sp_fid_8021d
, common
);
512 static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid
*fid
, const void *arg
)
514 int br_ifindex
= *(int *) arg
;
516 mlxsw_sp_fid_8021d_fid(fid
)->br_ifindex
= br_ifindex
;
519 static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid
*fid
)
521 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
523 return mlxsw_sp_fid_op(fid_family
->mlxsw_sp
, fid
->fid_index
, 0, true);
526 static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid
*fid
)
528 mlxsw_sp_fid_op(fid
->fid_family
->mlxsw_sp
, fid
->fid_index
, 0, false);
531 static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid
*fid
,
532 const void *arg
, u16
*p_fid_index
)
534 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
535 u16 nr_fids
, fid_index
;
537 nr_fids
= fid_family
->end_index
- fid_family
->start_index
+ 1;
538 fid_index
= find_first_zero_bit(fid_family
->fids_bitmap
, nr_fids
);
539 if (fid_index
== nr_fids
)
541 *p_fid_index
= fid_family
->start_index
+ fid_index
;
547 mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid
*fid
, const void *arg
)
549 int br_ifindex
= *(int *) arg
;
551 return mlxsw_sp_fid_8021d_fid(fid
)->br_ifindex
== br_ifindex
;
554 static u16
mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid
*fid
)
556 return fid
->fid_index
- fid
->fid_family
->start_index
;
559 static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port
*mlxsw_sp_port
)
561 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
562 struct mlxsw_sp_port_vlan
*mlxsw_sp_port_vlan
;
565 list_for_each_entry(mlxsw_sp_port_vlan
, &mlxsw_sp_port
->vlans_list
,
567 struct mlxsw_sp_fid
*fid
= mlxsw_sp_port_vlan
->fid
;
568 u16 vid
= mlxsw_sp_port_vlan
->vid
;
573 err
= __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
,
574 mlxsw_sp_port
->local_port
,
577 goto err_fid_port_vid_map
;
580 err
= mlxsw_sp_port_vp_mode_set(mlxsw_sp_port
, true);
582 goto err_port_vp_mode_set
;
586 err_port_vp_mode_set
:
587 err_fid_port_vid_map
:
588 list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan
,
589 &mlxsw_sp_port
->vlans_list
, list
) {
590 struct mlxsw_sp_fid
*fid
= mlxsw_sp_port_vlan
->fid
;
591 u16 vid
= mlxsw_sp_port_vlan
->vid
;
596 __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
,
597 mlxsw_sp_port
->local_port
, vid
,
603 static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port
*mlxsw_sp_port
)
605 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
606 struct mlxsw_sp_port_vlan
*mlxsw_sp_port_vlan
;
608 mlxsw_sp_port_vp_mode_set(mlxsw_sp_port
, false);
610 list_for_each_entry_reverse(mlxsw_sp_port_vlan
,
611 &mlxsw_sp_port
->vlans_list
, list
) {
612 struct mlxsw_sp_fid
*fid
= mlxsw_sp_port_vlan
->fid
;
613 u16 vid
= mlxsw_sp_port_vlan
->vid
;
618 __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
,
619 mlxsw_sp_port
->local_port
, vid
,
624 static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid
*fid
,
625 struct mlxsw_sp_port
*mlxsw_sp_port
,
628 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
629 u8 local_port
= mlxsw_sp_port
->local_port
;
632 err
= __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
,
633 mlxsw_sp_port
->local_port
, vid
, true);
637 if (mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
]++ == 0) {
638 err
= mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port
);
640 goto err_port_vp_mode_trans
;
645 err_port_vp_mode_trans
:
646 mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
]--;
647 __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
,
648 mlxsw_sp_port
->local_port
, vid
, false);
653 mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid
*fid
,
654 struct mlxsw_sp_port
*mlxsw_sp_port
, u16 vid
)
656 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
657 u8 local_port
= mlxsw_sp_port
->local_port
;
659 if (mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
] == 1)
660 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port
);
661 mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
]--;
662 __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
,
663 mlxsw_sp_port
->local_port
, vid
, false);
666 static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid
*fid
, __be32 vni
)
668 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
670 return mlxsw_sp_fid_vni_op(fid_family
->mlxsw_sp
, fid
->fid_index
, vni
,
671 true, fid
->nve_flood_index
,
672 fid
->nve_flood_index_valid
);
675 static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid
*fid
)
677 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
679 mlxsw_sp_fid_vni_op(fid_family
->mlxsw_sp
, fid
->fid_index
, 0, false,
680 fid
->nve_flood_index
, fid
->nve_flood_index_valid
);
683 static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid
*fid
,
686 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
688 return mlxsw_sp_fid_vni_op(fid_family
->mlxsw_sp
, fid
->fid_index
,
689 fid
->vni
, fid
->vni_valid
, nve_flood_index
,
693 static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid
*fid
)
695 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
697 mlxsw_sp_fid_vni_op(fid_family
->mlxsw_sp
, fid
->fid_index
, fid
->vni
,
698 fid
->vni_valid
, 0, false);
701 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops
= {
702 .setup
= mlxsw_sp_fid_8021d_setup
,
703 .configure
= mlxsw_sp_fid_8021d_configure
,
704 .deconfigure
= mlxsw_sp_fid_8021d_deconfigure
,
705 .index_alloc
= mlxsw_sp_fid_8021d_index_alloc
,
706 .compare
= mlxsw_sp_fid_8021d_compare
,
707 .flood_index
= mlxsw_sp_fid_8021d_flood_index
,
708 .port_vid_map
= mlxsw_sp_fid_8021d_port_vid_map
,
709 .port_vid_unmap
= mlxsw_sp_fid_8021d_port_vid_unmap
,
710 .vni_set
= mlxsw_sp_fid_8021d_vni_set
,
711 .vni_clear
= mlxsw_sp_fid_8021d_vni_clear
,
712 .nve_flood_index_set
= mlxsw_sp_fid_8021d_nve_flood_index_set
,
713 .nve_flood_index_clear
= mlxsw_sp_fid_8021d_nve_flood_index_clear
,
716 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables
[] = {
718 .packet_type
= MLXSW_SP_FLOOD_TYPE_UC
,
719 .bridge_type
= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID
,
720 .table_type
= MLXSW_REG_SFGC_TABLE_TYPE_FID
,
724 .packet_type
= MLXSW_SP_FLOOD_TYPE_MC
,
725 .bridge_type
= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID
,
726 .table_type
= MLXSW_REG_SFGC_TABLE_TYPE_FID
,
730 .packet_type
= MLXSW_SP_FLOOD_TYPE_BC
,
731 .bridge_type
= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID
,
732 .table_type
= MLXSW_REG_SFGC_TABLE_TYPE_FID
,
737 /* Range and flood configuration must match mlxsw_config_profile */
738 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family
= {
739 .type
= MLXSW_SP_FID_TYPE_8021D
,
740 .fid_size
= sizeof(struct mlxsw_sp_fid_8021d
),
741 .start_index
= VLAN_N_VID
,
742 .end_index
= VLAN_N_VID
+ MLXSW_SP_FID_8021D_MAX
- 1,
743 .flood_tables
= mlxsw_sp_fid_8021d_flood_tables
,
744 .nr_flood_tables
= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables
),
745 .rif_type
= MLXSW_SP_RIF_TYPE_FID
,
746 .ops
= &mlxsw_sp_fid_8021d_ops
,
749 static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid
*fid
)
751 /* rFIDs are allocated by the device during init */
755 static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid
*fid
)
759 static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid
*fid
,
760 const void *arg
, u16
*p_fid_index
)
762 u16 rif_index
= *(u16
*) arg
;
764 *p_fid_index
= fid
->fid_family
->start_index
+ rif_index
;
769 static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid
*fid
,
772 u16 rif_index
= *(u16
*) arg
;
774 return fid
->fid_index
== rif_index
+ fid
->fid_family
->start_index
;
777 static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid
*fid
,
778 struct mlxsw_sp_port
*mlxsw_sp_port
,
781 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
782 u8 local_port
= mlxsw_sp_port
->local_port
;
785 /* We only need to transition the port to virtual mode since
786 * {Port, VID} => FID is done by the firmware upon RIF creation.
788 if (mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
]++ == 0) {
789 err
= mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port
);
791 goto err_port_vp_mode_trans
;
796 err_port_vp_mode_trans
:
797 mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
]--;
802 mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid
*fid
,
803 struct mlxsw_sp_port
*mlxsw_sp_port
, u16 vid
)
805 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
806 u8 local_port
= mlxsw_sp_port
->local_port
;
808 if (mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
] == 1)
809 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port
);
810 mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
]--;
813 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops
= {
814 .configure
= mlxsw_sp_fid_rfid_configure
,
815 .deconfigure
= mlxsw_sp_fid_rfid_deconfigure
,
816 .index_alloc
= mlxsw_sp_fid_rfid_index_alloc
,
817 .compare
= mlxsw_sp_fid_rfid_compare
,
818 .port_vid_map
= mlxsw_sp_fid_rfid_port_vid_map
,
819 .port_vid_unmap
= mlxsw_sp_fid_rfid_port_vid_unmap
,
822 #define MLXSW_SP_RFID_BASE (15 * 1024)
823 #define MLXSW_SP_RFID_MAX 1024
825 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family
= {
826 .type
= MLXSW_SP_FID_TYPE_RFID
,
827 .fid_size
= sizeof(struct mlxsw_sp_fid
),
828 .start_index
= MLXSW_SP_RFID_BASE
,
829 .end_index
= MLXSW_SP_RFID_BASE
+ MLXSW_SP_RFID_MAX
- 1,
830 .rif_type
= MLXSW_SP_RIF_TYPE_SUBPORT
,
831 .ops
= &mlxsw_sp_fid_rfid_ops
,
834 static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid
*fid
)
836 struct mlxsw_sp
*mlxsw_sp
= fid
->fid_family
->mlxsw_sp
;
838 return mlxsw_sp_fid_op(mlxsw_sp
, fid
->fid_index
, 0, true);
841 static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid
*fid
)
843 mlxsw_sp_fid_op(fid
->fid_family
->mlxsw_sp
, fid
->fid_index
, 0, false);
846 static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid
*fid
,
847 const void *arg
, u16
*p_fid_index
)
849 *p_fid_index
= fid
->fid_family
->start_index
;
854 static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid
*fid
,
860 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops
= {
861 .configure
= mlxsw_sp_fid_dummy_configure
,
862 .deconfigure
= mlxsw_sp_fid_dummy_deconfigure
,
863 .index_alloc
= mlxsw_sp_fid_dummy_index_alloc
,
864 .compare
= mlxsw_sp_fid_dummy_compare
,
867 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family
= {
868 .type
= MLXSW_SP_FID_TYPE_DUMMY
,
869 .fid_size
= sizeof(struct mlxsw_sp_fid
),
870 .start_index
= MLXSW_SP_RFID_BASE
- 1,
871 .end_index
= MLXSW_SP_RFID_BASE
- 1,
872 .ops
= &mlxsw_sp_fid_dummy_ops
,
875 static const struct mlxsw_sp_fid_family
*mlxsw_sp_fid_family_arr
[] = {
876 [MLXSW_SP_FID_TYPE_8021Q
] = &mlxsw_sp_fid_8021q_family
,
877 [MLXSW_SP_FID_TYPE_8021D
] = &mlxsw_sp_fid_8021d_family
,
878 [MLXSW_SP_FID_TYPE_RFID
] = &mlxsw_sp_fid_rfid_family
,
879 [MLXSW_SP_FID_TYPE_DUMMY
] = &mlxsw_sp_fid_dummy_family
,
882 static struct mlxsw_sp_fid
*mlxsw_sp_fid_get(struct mlxsw_sp
*mlxsw_sp
,
883 enum mlxsw_sp_fid_type type
,
886 struct mlxsw_sp_fid_family
*fid_family
;
887 struct mlxsw_sp_fid
*fid
;
891 fid_family
= mlxsw_sp
->fid_core
->fid_family_arr
[type
];
892 list_for_each_entry(fid
, &fid_family
->fids_list
, list
) {
893 if (!fid
->fid_family
->ops
->compare(fid
, arg
))
899 fid
= kzalloc(fid_family
->fid_size
, GFP_KERNEL
);
901 return ERR_PTR(-ENOMEM
);
902 fid
->fid_family
= fid_family
;
904 err
= fid
->fid_family
->ops
->index_alloc(fid
, arg
, &fid_index
);
906 goto err_index_alloc
;
907 fid
->fid_index
= fid_index
;
908 __set_bit(fid_index
- fid_family
->start_index
, fid_family
->fids_bitmap
);
910 if (fid
->fid_family
->ops
->setup
)
911 fid
->fid_family
->ops
->setup(fid
, arg
);
913 err
= fid
->fid_family
->ops
->configure(fid
);
917 list_add(&fid
->list
, &fid_family
->fids_list
);
922 __clear_bit(fid_index
- fid_family
->start_index
,
923 fid_family
->fids_bitmap
);
929 void mlxsw_sp_fid_put(struct mlxsw_sp_fid
*fid
)
931 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
933 if (--fid
->ref_count
== 1 && fid
->rif
) {
934 /* Destroy the associated RIF and let it drop the last
935 * reference on the FID.
937 return mlxsw_sp_rif_destroy(fid
->rif
);
938 } else if (fid
->ref_count
== 0) {
939 list_del(&fid
->list
);
940 fid
->fid_family
->ops
->deconfigure(fid
);
941 __clear_bit(fid
->fid_index
- fid_family
->start_index
,
942 fid_family
->fids_bitmap
);
947 struct mlxsw_sp_fid
*mlxsw_sp_fid_8021q_get(struct mlxsw_sp
*mlxsw_sp
, u16 vid
)
949 return mlxsw_sp_fid_get(mlxsw_sp
, MLXSW_SP_FID_TYPE_8021Q
, &vid
);
952 struct mlxsw_sp_fid
*mlxsw_sp_fid_8021d_get(struct mlxsw_sp
*mlxsw_sp
,
955 return mlxsw_sp_fid_get(mlxsw_sp
, MLXSW_SP_FID_TYPE_8021D
, &br_ifindex
);
958 struct mlxsw_sp_fid
*mlxsw_sp_fid_rfid_get(struct mlxsw_sp
*mlxsw_sp
,
961 return mlxsw_sp_fid_get(mlxsw_sp
, MLXSW_SP_FID_TYPE_RFID
, &rif_index
);
964 struct mlxsw_sp_fid
*mlxsw_sp_fid_dummy_get(struct mlxsw_sp
*mlxsw_sp
)
966 return mlxsw_sp_fid_get(mlxsw_sp
, MLXSW_SP_FID_TYPE_DUMMY
, NULL
);
970 mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family
*fid_family
,
971 const struct mlxsw_sp_flood_table
*flood_table
)
973 enum mlxsw_sp_flood_type packet_type
= flood_table
->packet_type
;
974 const int *sfgc_packet_types
;
977 sfgc_packet_types
= mlxsw_sp_packet_type_sfgc_types
[packet_type
];
978 for (i
= 0; i
< MLXSW_REG_SFGC_TYPE_MAX
; i
++) {
979 struct mlxsw_sp
*mlxsw_sp
= fid_family
->mlxsw_sp
;
980 char sfgc_pl
[MLXSW_REG_SFGC_LEN
];
983 if (!sfgc_packet_types
[i
])
985 mlxsw_reg_sfgc_pack(sfgc_pl
, i
, flood_table
->bridge_type
,
986 flood_table
->table_type
,
987 flood_table
->table_index
);
988 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(sfgc
), sfgc_pl
);
997 mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family
*fid_family
)
1001 for (i
= 0; i
< fid_family
->nr_flood_tables
; i
++) {
1002 const struct mlxsw_sp_flood_table
*flood_table
;
1005 flood_table
= &fid_family
->flood_tables
[i
];
1006 err
= mlxsw_sp_fid_flood_table_init(fid_family
, flood_table
);
1014 static int mlxsw_sp_fid_family_register(struct mlxsw_sp
*mlxsw_sp
,
1015 const struct mlxsw_sp_fid_family
*tmpl
)
1017 u16 nr_fids
= tmpl
->end_index
- tmpl
->start_index
+ 1;
1018 struct mlxsw_sp_fid_family
*fid_family
;
1021 fid_family
= kmemdup(tmpl
, sizeof(*fid_family
), GFP_KERNEL
);
1025 fid_family
->mlxsw_sp
= mlxsw_sp
;
1026 INIT_LIST_HEAD(&fid_family
->fids_list
);
1027 fid_family
->fids_bitmap
= kcalloc(BITS_TO_LONGS(nr_fids
),
1028 sizeof(unsigned long), GFP_KERNEL
);
1029 if (!fid_family
->fids_bitmap
) {
1031 goto err_alloc_fids_bitmap
;
1034 if (fid_family
->flood_tables
) {
1035 err
= mlxsw_sp_fid_flood_tables_init(fid_family
);
1037 goto err_fid_flood_tables_init
;
1040 mlxsw_sp
->fid_core
->fid_family_arr
[tmpl
->type
] = fid_family
;
1044 err_fid_flood_tables_init
:
1045 kfree(fid_family
->fids_bitmap
);
1046 err_alloc_fids_bitmap
:
1052 mlxsw_sp_fid_family_unregister(struct mlxsw_sp
*mlxsw_sp
,
1053 struct mlxsw_sp_fid_family
*fid_family
)
1055 mlxsw_sp
->fid_core
->fid_family_arr
[fid_family
->type
] = NULL
;
1056 kfree(fid_family
->fids_bitmap
);
1057 WARN_ON_ONCE(!list_empty(&fid_family
->fids_list
));
1061 int mlxsw_sp_port_fids_init(struct mlxsw_sp_port
*mlxsw_sp_port
)
1063 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
1065 /* Track number of FIDs configured on the port with mapping type
1066 * PORT_VID_TO_FID, so that we know when to transition the port
1067 * back to non-virtual (VLAN) mode.
1069 mlxsw_sp
->fid_core
->port_fid_mappings
[mlxsw_sp_port
->local_port
] = 0;
1071 return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port
, false);
1074 void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port
*mlxsw_sp_port
)
1076 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
1078 mlxsw_sp
->fid_core
->port_fid_mappings
[mlxsw_sp_port
->local_port
] = 0;
1081 int mlxsw_sp_fids_init(struct mlxsw_sp
*mlxsw_sp
)
1083 unsigned int max_ports
= mlxsw_core_max_ports(mlxsw_sp
->core
);
1084 struct mlxsw_sp_fid_core
*fid_core
;
1087 fid_core
= kzalloc(sizeof(*mlxsw_sp
->fid_core
), GFP_KERNEL
);
1090 mlxsw_sp
->fid_core
= fid_core
;
1092 err
= rhashtable_init(&fid_core
->vni_ht
, &mlxsw_sp_fid_vni_ht_params
);
1094 goto err_rhashtable_init
;
1096 fid_core
->port_fid_mappings
= kcalloc(max_ports
, sizeof(unsigned int),
1098 if (!fid_core
->port_fid_mappings
) {
1100 goto err_alloc_port_fid_mappings
;
1103 for (i
= 0; i
< MLXSW_SP_FID_TYPE_MAX
; i
++) {
1104 err
= mlxsw_sp_fid_family_register(mlxsw_sp
,
1105 mlxsw_sp_fid_family_arr
[i
]);
1108 goto err_fid_ops_register
;
1113 err_fid_ops_register
:
1114 for (i
--; i
>= 0; i
--) {
1115 struct mlxsw_sp_fid_family
*fid_family
;
1117 fid_family
= fid_core
->fid_family_arr
[i
];
1118 mlxsw_sp_fid_family_unregister(mlxsw_sp
, fid_family
);
1120 kfree(fid_core
->port_fid_mappings
);
1121 err_alloc_port_fid_mappings
:
1122 rhashtable_destroy(&fid_core
->vni_ht
);
1123 err_rhashtable_init
:
1128 void mlxsw_sp_fids_fini(struct mlxsw_sp
*mlxsw_sp
)
1130 struct mlxsw_sp_fid_core
*fid_core
= mlxsw_sp
->fid_core
;
1133 for (i
= 0; i
< MLXSW_SP_FID_TYPE_MAX
; i
++)
1134 mlxsw_sp_fid_family_unregister(mlxsw_sp
,
1135 fid_core
->fid_family_arr
[i
]);
1136 kfree(fid_core
->port_fid_mappings
);
1137 rhashtable_destroy(&fid_core
->vni_ht
);