2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2017 Ido Schimmel <idosch@mellanox.com>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the names of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
35 #include <linux/kernel.h>
36 #include <linux/bitops.h>
37 #include <linux/if_vlan.h>
38 #include <linux/if_bridge.h>
39 #include <linux/netdevice.h>
40 #include <linux/rtnetlink.h>
45 struct mlxsw_sp_fid_family
;
47 struct mlxsw_sp_fid_core
{
48 struct mlxsw_sp_fid_family
*fid_family_arr
[MLXSW_SP_FID_TYPE_MAX
];
49 unsigned int *port_fid_mappings
;
53 struct list_head list
;
54 struct mlxsw_sp_rif
*rif
;
55 unsigned int ref_count
;
57 struct mlxsw_sp_fid_family
*fid_family
;
60 struct mlxsw_sp_fid_8021q
{
61 struct mlxsw_sp_fid common
;
65 struct mlxsw_sp_fid_8021d
{
66 struct mlxsw_sp_fid common
;
70 struct mlxsw_sp_flood_table
{
71 enum mlxsw_sp_flood_type packet_type
;
72 enum mlxsw_reg_sfgc_bridge_type bridge_type
;
73 enum mlxsw_flood_table_type table_type
;
77 struct mlxsw_sp_fid_ops
{
78 void (*setup
)(struct mlxsw_sp_fid
*fid
, const void *arg
);
79 int (*configure
)(struct mlxsw_sp_fid
*fid
);
80 void (*deconfigure
)(struct mlxsw_sp_fid
*fid
);
81 int (*index_alloc
)(struct mlxsw_sp_fid
*fid
, const void *arg
,
83 bool (*compare
)(const struct mlxsw_sp_fid
*fid
,
85 u16 (*flood_index
)(const struct mlxsw_sp_fid
*fid
);
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
);
92 struct mlxsw_sp_fid_family
{
93 enum mlxsw_sp_fid_type type
;
97 struct list_head fids_list
;
98 unsigned long *fids_bitmap
;
99 const struct mlxsw_sp_flood_table
*flood_tables
;
101 enum mlxsw_sp_rif_type rif_type
;
102 const struct mlxsw_sp_fid_ops
*ops
;
103 struct mlxsw_sp
*mlxsw_sp
;
106 static const int mlxsw_sp_sfgc_uc_packet_types
[MLXSW_REG_SFGC_TYPE_MAX
] = {
107 [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST
] = 1,
110 static const int mlxsw_sp_sfgc_bc_packet_types
[MLXSW_REG_SFGC_TYPE_MAX
] = {
111 [MLXSW_REG_SFGC_TYPE_BROADCAST
] = 1,
112 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP
] = 1,
113 [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL
] = 1,
114 [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST
] = 1,
115 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6
] = 1,
118 static const int mlxsw_sp_sfgc_mc_packet_types
[MLXSW_REG_SFGC_TYPE_MAX
] = {
119 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4
] = 1,
122 static const int *mlxsw_sp_packet_type_sfgc_types
[] = {
123 [MLXSW_SP_FLOOD_TYPE_UC
] = mlxsw_sp_sfgc_uc_packet_types
,
124 [MLXSW_SP_FLOOD_TYPE_BC
] = mlxsw_sp_sfgc_bc_packet_types
,
125 [MLXSW_SP_FLOOD_TYPE_MC
] = mlxsw_sp_sfgc_mc_packet_types
,
128 static const struct mlxsw_sp_flood_table
*
129 mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid
*fid
,
130 enum mlxsw_sp_flood_type packet_type
)
132 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
135 for (i
= 0; i
< fid_family
->nr_flood_tables
; i
++) {
136 if (fid_family
->flood_tables
[i
].packet_type
!= packet_type
)
138 return &fid_family
->flood_tables
[i
];
144 int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid
*fid
,
145 enum mlxsw_sp_flood_type packet_type
, u8 local_port
,
148 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
149 const struct mlxsw_sp_fid_ops
*ops
= fid_family
->ops
;
150 const struct mlxsw_sp_flood_table
*flood_table
;
154 if (WARN_ON(!fid_family
->flood_tables
|| !ops
->flood_index
))
157 flood_table
= mlxsw_sp_fid_flood_table_lookup(fid
, packet_type
);
161 sftr_pl
= kmalloc(MLXSW_REG_SFTR_LEN
, GFP_KERNEL
);
165 mlxsw_reg_sftr_pack(sftr_pl
, flood_table
->table_index
,
166 ops
->flood_index(fid
), flood_table
->table_type
, 1,
168 err
= mlxsw_reg_write(fid_family
->mlxsw_sp
->core
, MLXSW_REG(sftr
),
174 int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid
*fid
,
175 struct mlxsw_sp_port
*mlxsw_sp_port
, u16 vid
)
177 if (WARN_ON(!fid
->fid_family
->ops
->port_vid_map
))
179 return fid
->fid_family
->ops
->port_vid_map(fid
, mlxsw_sp_port
, vid
);
182 void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid
*fid
,
183 struct mlxsw_sp_port
*mlxsw_sp_port
, u16 vid
)
185 fid
->fid_family
->ops
->port_vid_unmap(fid
, mlxsw_sp_port
, vid
);
188 enum mlxsw_sp_rif_type
mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid
*fid
)
190 return fid
->fid_family
->rif_type
;
193 u16
mlxsw_sp_fid_index(const struct mlxsw_sp_fid
*fid
)
195 return fid
->fid_index
;
198 enum mlxsw_sp_fid_type
mlxsw_sp_fid_type(const struct mlxsw_sp_fid
*fid
)
200 return fid
->fid_family
->type
;
203 void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid
*fid
, struct mlxsw_sp_rif
*rif
)
208 enum mlxsw_sp_rif_type
209 mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp
*mlxsw_sp
,
210 enum mlxsw_sp_fid_type type
)
212 struct mlxsw_sp_fid_core
*fid_core
= mlxsw_sp
->fid_core
;
214 return fid_core
->fid_family_arr
[type
]->rif_type
;
217 static struct mlxsw_sp_fid_8021q
*
218 mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid
*fid
)
220 return container_of(fid
, struct mlxsw_sp_fid_8021q
, common
);
223 u16
mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid
*fid
)
225 return mlxsw_sp_fid_8021q_fid(fid
)->vid
;
228 static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid
*fid
, const void *arg
)
230 u16 vid
= *(u16
*) arg
;
232 mlxsw_sp_fid_8021q_fid(fid
)->vid
= vid
;
235 static enum mlxsw_reg_sfmr_op
mlxsw_sp_sfmr_op(bool valid
)
237 return valid
? MLXSW_REG_SFMR_OP_CREATE_FID
:
238 MLXSW_REG_SFMR_OP_DESTROY_FID
;
241 static int mlxsw_sp_fid_op(struct mlxsw_sp
*mlxsw_sp
, u16 fid_index
,
242 u16 fid_offset
, bool valid
)
244 char sfmr_pl
[MLXSW_REG_SFMR_LEN
];
246 mlxsw_reg_sfmr_pack(sfmr_pl
, mlxsw_sp_sfmr_op(valid
), fid_index
,
248 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(sfmr
), sfmr_pl
);
251 static int mlxsw_sp_fid_vid_map(struct mlxsw_sp
*mlxsw_sp
, u16 fid_index
,
254 enum mlxsw_reg_svfa_mt mt
= MLXSW_REG_SVFA_MT_VID_TO_FID
;
255 char svfa_pl
[MLXSW_REG_SVFA_LEN
];
257 mlxsw_reg_svfa_pack(svfa_pl
, 0, mt
, valid
, fid_index
, vid
);
258 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(svfa
), svfa_pl
);
261 static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp
*mlxsw_sp
, u16 fid_index
,
262 u8 local_port
, u16 vid
, bool valid
)
264 enum mlxsw_reg_svfa_mt mt
= MLXSW_REG_SVFA_MT_PORT_VID_TO_FID
;
265 char svfa_pl
[MLXSW_REG_SVFA_LEN
];
267 mlxsw_reg_svfa_pack(svfa_pl
, local_port
, mt
, valid
, fid_index
, vid
);
268 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(svfa
), svfa_pl
);
271 static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid
*fid
)
273 struct mlxsw_sp
*mlxsw_sp
= fid
->fid_family
->mlxsw_sp
;
274 struct mlxsw_sp_fid_8021q
*fid_8021q
;
277 err
= mlxsw_sp_fid_op(mlxsw_sp
, fid
->fid_index
, fid
->fid_index
, true);
281 fid_8021q
= mlxsw_sp_fid_8021q_fid(fid
);
282 err
= mlxsw_sp_fid_vid_map(mlxsw_sp
, fid
->fid_index
, fid_8021q
->vid
,
290 mlxsw_sp_fid_op(mlxsw_sp
, fid
->fid_index
, 0, false);
294 static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid
*fid
)
296 struct mlxsw_sp
*mlxsw_sp
= fid
->fid_family
->mlxsw_sp
;
297 struct mlxsw_sp_fid_8021q
*fid_8021q
;
299 fid_8021q
= mlxsw_sp_fid_8021q_fid(fid
);
300 mlxsw_sp_fid_vid_map(mlxsw_sp
, fid
->fid_index
, fid_8021q
->vid
, false);
301 mlxsw_sp_fid_op(mlxsw_sp
, fid
->fid_index
, 0, false);
304 static int mlxsw_sp_fid_8021q_index_alloc(struct mlxsw_sp_fid
*fid
,
305 const void *arg
, u16
*p_fid_index
)
307 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
308 u16 vid
= *(u16
*) arg
;
310 /* Use 1:1 mapping for simplicity although not a must */
311 if (vid
< fid_family
->start_index
|| vid
> fid_family
->end_index
)
319 mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid
*fid
, const void *arg
)
321 u16 vid
= *(u16
*) arg
;
323 return mlxsw_sp_fid_8021q_fid(fid
)->vid
== vid
;
326 static u16
mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid
*fid
)
328 return fid
->fid_index
;
331 static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid
*fid
,
332 struct mlxsw_sp_port
*mlxsw_sp_port
,
335 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
336 u8 local_port
= mlxsw_sp_port
->local_port
;
338 /* In case there are no {Port, VID} => FID mappings on the port,
339 * we can use the global VID => FID mapping we created when the
340 * FID was configured.
342 if (mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
] == 0)
344 return __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
, local_port
,
349 mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid
*fid
,
350 struct mlxsw_sp_port
*mlxsw_sp_port
, u16 vid
)
352 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
353 u8 local_port
= mlxsw_sp_port
->local_port
;
355 if (mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
] == 0)
357 __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
, local_port
, vid
,
361 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops
= {
362 .setup
= mlxsw_sp_fid_8021q_setup
,
363 .configure
= mlxsw_sp_fid_8021q_configure
,
364 .deconfigure
= mlxsw_sp_fid_8021q_deconfigure
,
365 .index_alloc
= mlxsw_sp_fid_8021q_index_alloc
,
366 .compare
= mlxsw_sp_fid_8021q_compare
,
367 .flood_index
= mlxsw_sp_fid_8021q_flood_index
,
368 .port_vid_map
= mlxsw_sp_fid_8021q_port_vid_map
,
369 .port_vid_unmap
= mlxsw_sp_fid_8021q_port_vid_unmap
,
372 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021q_flood_tables
[] = {
374 .packet_type
= MLXSW_SP_FLOOD_TYPE_UC
,
375 .bridge_type
= MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID
,
376 .table_type
= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET
,
380 .packet_type
= MLXSW_SP_FLOOD_TYPE_MC
,
381 .bridge_type
= MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID
,
382 .table_type
= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET
,
386 .packet_type
= MLXSW_SP_FLOOD_TYPE_BC
,
387 .bridge_type
= MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID
,
388 .table_type
= MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET
,
393 /* Range and flood configuration must match mlxsw_config_profile */
394 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_family
= {
395 .type
= MLXSW_SP_FID_TYPE_8021Q
,
396 .fid_size
= sizeof(struct mlxsw_sp_fid_8021q
),
398 .end_index
= VLAN_VID_MASK
,
399 .flood_tables
= mlxsw_sp_fid_8021q_flood_tables
,
400 .nr_flood_tables
= ARRAY_SIZE(mlxsw_sp_fid_8021q_flood_tables
),
401 .rif_type
= MLXSW_SP_RIF_TYPE_VLAN
,
402 .ops
= &mlxsw_sp_fid_8021q_ops
,
405 static struct mlxsw_sp_fid_8021d
*
406 mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid
*fid
)
408 return container_of(fid
, struct mlxsw_sp_fid_8021d
, common
);
411 static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid
*fid
, const void *arg
)
413 int br_ifindex
= *(int *) arg
;
415 mlxsw_sp_fid_8021d_fid(fid
)->br_ifindex
= br_ifindex
;
418 static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid
*fid
)
420 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
422 return mlxsw_sp_fid_op(fid_family
->mlxsw_sp
, fid
->fid_index
, 0, true);
425 static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid
*fid
)
427 mlxsw_sp_fid_op(fid
->fid_family
->mlxsw_sp
, fid
->fid_index
, 0, false);
430 static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid
*fid
,
431 const void *arg
, u16
*p_fid_index
)
433 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
434 u16 nr_fids
, fid_index
;
436 nr_fids
= fid_family
->end_index
- fid_family
->start_index
+ 1;
437 fid_index
= find_first_zero_bit(fid_family
->fids_bitmap
, nr_fids
);
438 if (fid_index
== nr_fids
)
440 *p_fid_index
= fid_family
->start_index
+ fid_index
;
446 mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid
*fid
, const void *arg
)
448 int br_ifindex
= *(int *) arg
;
450 return mlxsw_sp_fid_8021d_fid(fid
)->br_ifindex
== br_ifindex
;
453 static u16
mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid
*fid
)
455 return fid
->fid_index
- fid
->fid_family
->start_index
;
458 static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port
*mlxsw_sp_port
)
460 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
461 struct mlxsw_sp_port_vlan
*mlxsw_sp_port_vlan
;
464 list_for_each_entry(mlxsw_sp_port_vlan
, &mlxsw_sp_port
->vlans_list
,
466 struct mlxsw_sp_fid
*fid
= mlxsw_sp_port_vlan
->fid
;
467 u16 vid
= mlxsw_sp_port_vlan
->vid
;
472 err
= __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
,
473 mlxsw_sp_port
->local_port
,
476 goto err_fid_port_vid_map
;
479 err
= mlxsw_sp_port_vp_mode_set(mlxsw_sp_port
, true);
481 goto err_port_vp_mode_set
;
485 err_port_vp_mode_set
:
486 err_fid_port_vid_map
:
487 list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan
,
488 &mlxsw_sp_port
->vlans_list
, list
) {
489 struct mlxsw_sp_fid
*fid
= mlxsw_sp_port_vlan
->fid
;
490 u16 vid
= mlxsw_sp_port_vlan
->vid
;
495 __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
,
496 mlxsw_sp_port
->local_port
, vid
,
502 static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port
*mlxsw_sp_port
)
504 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
505 struct mlxsw_sp_port_vlan
*mlxsw_sp_port_vlan
;
507 mlxsw_sp_port_vp_mode_set(mlxsw_sp_port
, false);
509 list_for_each_entry_reverse(mlxsw_sp_port_vlan
,
510 &mlxsw_sp_port
->vlans_list
, list
) {
511 struct mlxsw_sp_fid
*fid
= mlxsw_sp_port_vlan
->fid
;
512 u16 vid
= mlxsw_sp_port_vlan
->vid
;
517 __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
,
518 mlxsw_sp_port
->local_port
, vid
,
523 static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid
*fid
,
524 struct mlxsw_sp_port
*mlxsw_sp_port
,
527 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
528 u8 local_port
= mlxsw_sp_port
->local_port
;
531 err
= __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
,
532 mlxsw_sp_port
->local_port
, vid
, true);
536 if (mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
]++ == 0) {
537 err
= mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port
);
539 goto err_port_vp_mode_trans
;
544 err_port_vp_mode_trans
:
545 mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
]--;
546 __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
,
547 mlxsw_sp_port
->local_port
, vid
, false);
552 mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid
*fid
,
553 struct mlxsw_sp_port
*mlxsw_sp_port
, u16 vid
)
555 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
556 u8 local_port
= mlxsw_sp_port
->local_port
;
558 if (mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
] == 1)
559 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port
);
560 mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
]--;
561 __mlxsw_sp_fid_port_vid_map(mlxsw_sp
, fid
->fid_index
,
562 mlxsw_sp_port
->local_port
, vid
, false);
565 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops
= {
566 .setup
= mlxsw_sp_fid_8021d_setup
,
567 .configure
= mlxsw_sp_fid_8021d_configure
,
568 .deconfigure
= mlxsw_sp_fid_8021d_deconfigure
,
569 .index_alloc
= mlxsw_sp_fid_8021d_index_alloc
,
570 .compare
= mlxsw_sp_fid_8021d_compare
,
571 .flood_index
= mlxsw_sp_fid_8021d_flood_index
,
572 .port_vid_map
= mlxsw_sp_fid_8021d_port_vid_map
,
573 .port_vid_unmap
= mlxsw_sp_fid_8021d_port_vid_unmap
,
576 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables
[] = {
578 .packet_type
= MLXSW_SP_FLOOD_TYPE_UC
,
579 .bridge_type
= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID
,
580 .table_type
= MLXSW_REG_SFGC_TABLE_TYPE_FID
,
584 .packet_type
= MLXSW_SP_FLOOD_TYPE_MC
,
585 .bridge_type
= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID
,
586 .table_type
= MLXSW_REG_SFGC_TABLE_TYPE_FID
,
590 .packet_type
= MLXSW_SP_FLOOD_TYPE_BC
,
591 .bridge_type
= MLXSW_REG_SFGC_BRIDGE_TYPE_VFID
,
592 .table_type
= MLXSW_REG_SFGC_TABLE_TYPE_FID
,
597 /* Range and flood configuration must match mlxsw_config_profile */
598 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family
= {
599 .type
= MLXSW_SP_FID_TYPE_8021D
,
600 .fid_size
= sizeof(struct mlxsw_sp_fid_8021d
),
601 .start_index
= VLAN_N_VID
,
602 .end_index
= VLAN_N_VID
+ MLXSW_SP_FID_8021D_MAX
- 1,
603 .flood_tables
= mlxsw_sp_fid_8021d_flood_tables
,
604 .nr_flood_tables
= ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables
),
605 .rif_type
= MLXSW_SP_RIF_TYPE_FID
,
606 .ops
= &mlxsw_sp_fid_8021d_ops
,
609 static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid
*fid
)
611 /* rFIDs are allocated by the device during init */
615 static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid
*fid
)
619 static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid
*fid
,
620 const void *arg
, u16
*p_fid_index
)
622 u16 rif_index
= *(u16
*) arg
;
624 *p_fid_index
= fid
->fid_family
->start_index
+ rif_index
;
629 static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid
*fid
,
632 u16 rif_index
= *(u16
*) arg
;
634 return fid
->fid_index
== rif_index
+ fid
->fid_family
->start_index
;
637 static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid
*fid
,
638 struct mlxsw_sp_port
*mlxsw_sp_port
,
641 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
642 u8 local_port
= mlxsw_sp_port
->local_port
;
645 /* We only need to transition the port to virtual mode since
646 * {Port, VID} => FID is done by the firmware upon RIF creation.
648 if (mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
]++ == 0) {
649 err
= mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port
);
651 goto err_port_vp_mode_trans
;
656 err_port_vp_mode_trans
:
657 mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
]--;
662 mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid
*fid
,
663 struct mlxsw_sp_port
*mlxsw_sp_port
, u16 vid
)
665 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
666 u8 local_port
= mlxsw_sp_port
->local_port
;
668 if (mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
] == 1)
669 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port
);
670 mlxsw_sp
->fid_core
->port_fid_mappings
[local_port
]--;
673 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops
= {
674 .configure
= mlxsw_sp_fid_rfid_configure
,
675 .deconfigure
= mlxsw_sp_fid_rfid_deconfigure
,
676 .index_alloc
= mlxsw_sp_fid_rfid_index_alloc
,
677 .compare
= mlxsw_sp_fid_rfid_compare
,
678 .port_vid_map
= mlxsw_sp_fid_rfid_port_vid_map
,
679 .port_vid_unmap
= mlxsw_sp_fid_rfid_port_vid_unmap
,
682 #define MLXSW_SP_RFID_BASE (15 * 1024)
683 #define MLXSW_SP_RFID_MAX 1024
685 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family
= {
686 .type
= MLXSW_SP_FID_TYPE_RFID
,
687 .fid_size
= sizeof(struct mlxsw_sp_fid
),
688 .start_index
= MLXSW_SP_RFID_BASE
,
689 .end_index
= MLXSW_SP_RFID_BASE
+ MLXSW_SP_RFID_MAX
- 1,
690 .rif_type
= MLXSW_SP_RIF_TYPE_SUBPORT
,
691 .ops
= &mlxsw_sp_fid_rfid_ops
,
694 static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid
*fid
)
696 struct mlxsw_sp
*mlxsw_sp
= fid
->fid_family
->mlxsw_sp
;
698 return mlxsw_sp_fid_op(mlxsw_sp
, fid
->fid_index
, 0, true);
701 static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid
*fid
)
703 mlxsw_sp_fid_op(fid
->fid_family
->mlxsw_sp
, fid
->fid_index
, 0, false);
706 static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid
*fid
,
707 const void *arg
, u16
*p_fid_index
)
709 *p_fid_index
= fid
->fid_family
->start_index
;
714 static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid
*fid
,
720 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops
= {
721 .configure
= mlxsw_sp_fid_dummy_configure
,
722 .deconfigure
= mlxsw_sp_fid_dummy_deconfigure
,
723 .index_alloc
= mlxsw_sp_fid_dummy_index_alloc
,
724 .compare
= mlxsw_sp_fid_dummy_compare
,
727 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family
= {
728 .type
= MLXSW_SP_FID_TYPE_DUMMY
,
729 .fid_size
= sizeof(struct mlxsw_sp_fid
),
730 .start_index
= MLXSW_SP_RFID_BASE
- 1,
731 .end_index
= MLXSW_SP_RFID_BASE
- 1,
732 .ops
= &mlxsw_sp_fid_dummy_ops
,
735 static const struct mlxsw_sp_fid_family
*mlxsw_sp_fid_family_arr
[] = {
736 [MLXSW_SP_FID_TYPE_8021Q
] = &mlxsw_sp_fid_8021q_family
,
737 [MLXSW_SP_FID_TYPE_8021D
] = &mlxsw_sp_fid_8021d_family
,
738 [MLXSW_SP_FID_TYPE_RFID
] = &mlxsw_sp_fid_rfid_family
,
739 [MLXSW_SP_FID_TYPE_DUMMY
] = &mlxsw_sp_fid_dummy_family
,
742 static struct mlxsw_sp_fid
*mlxsw_sp_fid_get(struct mlxsw_sp
*mlxsw_sp
,
743 enum mlxsw_sp_fid_type type
,
746 struct mlxsw_sp_fid_family
*fid_family
;
747 struct mlxsw_sp_fid
*fid
;
751 fid_family
= mlxsw_sp
->fid_core
->fid_family_arr
[type
];
752 list_for_each_entry(fid
, &fid_family
->fids_list
, list
) {
753 if (!fid
->fid_family
->ops
->compare(fid
, arg
))
759 fid
= kzalloc(fid_family
->fid_size
, GFP_KERNEL
);
761 return ERR_PTR(-ENOMEM
);
762 fid
->fid_family
= fid_family
;
764 err
= fid
->fid_family
->ops
->index_alloc(fid
, arg
, &fid_index
);
766 goto err_index_alloc
;
767 fid
->fid_index
= fid_index
;
768 __set_bit(fid_index
- fid_family
->start_index
, fid_family
->fids_bitmap
);
770 if (fid
->fid_family
->ops
->setup
)
771 fid
->fid_family
->ops
->setup(fid
, arg
);
773 err
= fid
->fid_family
->ops
->configure(fid
);
777 list_add(&fid
->list
, &fid_family
->fids_list
);
782 __clear_bit(fid_index
- fid_family
->start_index
,
783 fid_family
->fids_bitmap
);
789 void mlxsw_sp_fid_put(struct mlxsw_sp_fid
*fid
)
791 struct mlxsw_sp_fid_family
*fid_family
= fid
->fid_family
;
793 if (--fid
->ref_count
== 1 && fid
->rif
) {
794 /* Destroy the associated RIF and let it drop the last
795 * reference on the FID.
797 return mlxsw_sp_rif_destroy(fid
->rif
);
798 } else if (fid
->ref_count
== 0) {
799 list_del(&fid
->list
);
800 fid
->fid_family
->ops
->deconfigure(fid
);
801 __clear_bit(fid
->fid_index
- fid_family
->start_index
,
802 fid_family
->fids_bitmap
);
807 struct mlxsw_sp_fid
*mlxsw_sp_fid_8021q_get(struct mlxsw_sp
*mlxsw_sp
, u16 vid
)
809 return mlxsw_sp_fid_get(mlxsw_sp
, MLXSW_SP_FID_TYPE_8021Q
, &vid
);
812 struct mlxsw_sp_fid
*mlxsw_sp_fid_8021d_get(struct mlxsw_sp
*mlxsw_sp
,
815 return mlxsw_sp_fid_get(mlxsw_sp
, MLXSW_SP_FID_TYPE_8021D
, &br_ifindex
);
818 struct mlxsw_sp_fid
*mlxsw_sp_fid_rfid_get(struct mlxsw_sp
*mlxsw_sp
,
821 return mlxsw_sp_fid_get(mlxsw_sp
, MLXSW_SP_FID_TYPE_RFID
, &rif_index
);
824 struct mlxsw_sp_fid
*mlxsw_sp_fid_dummy_get(struct mlxsw_sp
*mlxsw_sp
)
826 return mlxsw_sp_fid_get(mlxsw_sp
, MLXSW_SP_FID_TYPE_DUMMY
, NULL
);
830 mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family
*fid_family
,
831 const struct mlxsw_sp_flood_table
*flood_table
)
833 enum mlxsw_sp_flood_type packet_type
= flood_table
->packet_type
;
834 const int *sfgc_packet_types
;
837 sfgc_packet_types
= mlxsw_sp_packet_type_sfgc_types
[packet_type
];
838 for (i
= 0; i
< MLXSW_REG_SFGC_TYPE_MAX
; i
++) {
839 struct mlxsw_sp
*mlxsw_sp
= fid_family
->mlxsw_sp
;
840 char sfgc_pl
[MLXSW_REG_SFGC_LEN
];
843 if (!sfgc_packet_types
[i
])
845 mlxsw_reg_sfgc_pack(sfgc_pl
, i
, flood_table
->bridge_type
,
846 flood_table
->table_type
,
847 flood_table
->table_index
);
848 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(sfgc
), sfgc_pl
);
857 mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family
*fid_family
)
861 for (i
= 0; i
< fid_family
->nr_flood_tables
; i
++) {
862 const struct mlxsw_sp_flood_table
*flood_table
;
865 flood_table
= &fid_family
->flood_tables
[i
];
866 err
= mlxsw_sp_fid_flood_table_init(fid_family
, flood_table
);
874 static int mlxsw_sp_fid_family_register(struct mlxsw_sp
*mlxsw_sp
,
875 const struct mlxsw_sp_fid_family
*tmpl
)
877 u16 nr_fids
= tmpl
->end_index
- tmpl
->start_index
+ 1;
878 struct mlxsw_sp_fid_family
*fid_family
;
881 fid_family
= kmemdup(tmpl
, sizeof(*fid_family
), GFP_KERNEL
);
885 fid_family
->mlxsw_sp
= mlxsw_sp
;
886 INIT_LIST_HEAD(&fid_family
->fids_list
);
887 fid_family
->fids_bitmap
= kcalloc(BITS_TO_LONGS(nr_fids
),
888 sizeof(unsigned long), GFP_KERNEL
);
889 if (!fid_family
->fids_bitmap
) {
891 goto err_alloc_fids_bitmap
;
894 if (fid_family
->flood_tables
) {
895 err
= mlxsw_sp_fid_flood_tables_init(fid_family
);
897 goto err_fid_flood_tables_init
;
900 mlxsw_sp
->fid_core
->fid_family_arr
[tmpl
->type
] = fid_family
;
904 err_fid_flood_tables_init
:
905 kfree(fid_family
->fids_bitmap
);
906 err_alloc_fids_bitmap
:
912 mlxsw_sp_fid_family_unregister(struct mlxsw_sp
*mlxsw_sp
,
913 struct mlxsw_sp_fid_family
*fid_family
)
915 mlxsw_sp
->fid_core
->fid_family_arr
[fid_family
->type
] = NULL
;
916 kfree(fid_family
->fids_bitmap
);
917 WARN_ON_ONCE(!list_empty(&fid_family
->fids_list
));
921 int mlxsw_sp_port_fids_init(struct mlxsw_sp_port
*mlxsw_sp_port
)
923 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
925 /* Track number of FIDs configured on the port with mapping type
926 * PORT_VID_TO_FID, so that we know when to transition the port
927 * back to non-virtual (VLAN) mode.
929 mlxsw_sp
->fid_core
->port_fid_mappings
[mlxsw_sp_port
->local_port
] = 0;
931 return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port
, false);
934 void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port
*mlxsw_sp_port
)
936 struct mlxsw_sp
*mlxsw_sp
= mlxsw_sp_port
->mlxsw_sp
;
938 mlxsw_sp
->fid_core
->port_fid_mappings
[mlxsw_sp_port
->local_port
] = 0;
941 int mlxsw_sp_fids_init(struct mlxsw_sp
*mlxsw_sp
)
943 unsigned int max_ports
= mlxsw_core_max_ports(mlxsw_sp
->core
);
944 struct mlxsw_sp_fid_core
*fid_core
;
947 fid_core
= kzalloc(sizeof(*mlxsw_sp
->fid_core
), GFP_KERNEL
);
950 mlxsw_sp
->fid_core
= fid_core
;
952 fid_core
->port_fid_mappings
= kcalloc(max_ports
, sizeof(unsigned int),
954 if (!fid_core
->port_fid_mappings
) {
956 goto err_alloc_port_fid_mappings
;
959 for (i
= 0; i
< MLXSW_SP_FID_TYPE_MAX
; i
++) {
960 err
= mlxsw_sp_fid_family_register(mlxsw_sp
,
961 mlxsw_sp_fid_family_arr
[i
]);
964 goto err_fid_ops_register
;
969 err_fid_ops_register
:
970 for (i
--; i
>= 0; i
--) {
971 struct mlxsw_sp_fid_family
*fid_family
;
973 fid_family
= fid_core
->fid_family_arr
[i
];
974 mlxsw_sp_fid_family_unregister(mlxsw_sp
, fid_family
);
976 kfree(fid_core
->port_fid_mappings
);
977 err_alloc_port_fid_mappings
:
982 void mlxsw_sp_fids_fini(struct mlxsw_sp
*mlxsw_sp
)
984 struct mlxsw_sp_fid_core
*fid_core
= mlxsw_sp
->fid_core
;
987 for (i
= 0; i
< MLXSW_SP_FID_TYPE_MAX
; i
++)
988 mlxsw_sp_fid_family_unregister(mlxsw_sp
,
989 fid_core
->fid_family_arr
[i
]);
990 kfree(fid_core
->port_fid_mappings
);