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/rtnetlink.h>
14 struct mlxsw_sp_fid_family;
16 struct mlxsw_sp_fid_core {
17 struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
18 unsigned int *port_fid_mappings;
22 struct list_head list;
23 struct mlxsw_sp_rif *rif;
24 unsigned int ref_count;
26 struct mlxsw_sp_fid_family *fid_family;
29 struct mlxsw_sp_fid_8021q {
30 struct mlxsw_sp_fid common;
34 struct mlxsw_sp_fid_8021d {
35 struct mlxsw_sp_fid common;
39 struct mlxsw_sp_flood_table {
40 enum mlxsw_sp_flood_type packet_type;
41 enum mlxsw_reg_sfgc_bridge_type bridge_type;
42 enum mlxsw_flood_table_type table_type;
46 struct mlxsw_sp_fid_ops {
47 void (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
48 int (*configure)(struct mlxsw_sp_fid *fid);
49 void (*deconfigure)(struct mlxsw_sp_fid *fid);
50 int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
52 bool (*compare)(const struct mlxsw_sp_fid *fid,
54 u16 (*flood_index)(const struct mlxsw_sp_fid *fid);
55 int (*port_vid_map)(struct mlxsw_sp_fid *fid,
56 struct mlxsw_sp_port *port, u16 vid);
57 void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
58 struct mlxsw_sp_port *port, u16 vid);
61 struct mlxsw_sp_fid_family {
62 enum mlxsw_sp_fid_type type;
66 struct list_head fids_list;
67 unsigned long *fids_bitmap;
68 const struct mlxsw_sp_flood_table *flood_tables;
70 enum mlxsw_sp_rif_type rif_type;
71 const struct mlxsw_sp_fid_ops *ops;
72 struct mlxsw_sp *mlxsw_sp;
75 static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
76 [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1,
79 static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
80 [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1,
81 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1,
82 [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1,
83 [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1,
84 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1,
87 static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
88 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
91 static const int *mlxsw_sp_packet_type_sfgc_types[] = {
92 [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types,
93 [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types,
94 [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types,
97 static const struct mlxsw_sp_flood_table *
98 mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
99 enum mlxsw_sp_flood_type packet_type)
101 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
104 for (i = 0; i < fid_family->nr_flood_tables; i++) {
105 if (fid_family->flood_tables[i].packet_type != packet_type)
107 return &fid_family->flood_tables[i];
113 int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
114 enum mlxsw_sp_flood_type packet_type, u8 local_port,
117 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
118 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
119 const struct mlxsw_sp_flood_table *flood_table;
123 if (WARN_ON(!fid_family->flood_tables || !ops->flood_index))
126 flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
130 sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
134 mlxsw_reg_sftr_pack(sftr_pl, flood_table->table_index,
135 ops->flood_index(fid), flood_table->table_type, 1,
137 err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr),
143 int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
144 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
146 if (WARN_ON(!fid->fid_family->ops->port_vid_map))
148 return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);
151 void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
152 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
154 fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
157 enum mlxsw_sp_rif_type mlxsw_sp_fid_rif_type(const struct mlxsw_sp_fid *fid)
159 return fid->fid_family->rif_type;
162 u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
164 return fid->fid_index;
167 enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
169 return fid->fid_family->type;
172 void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
177 enum mlxsw_sp_rif_type
178 mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
179 enum mlxsw_sp_fid_type type)
181 struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
183 return fid_core->fid_family_arr[type]->rif_type;
186 static struct mlxsw_sp_fid_8021q *
187 mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
189 return container_of(fid, struct mlxsw_sp_fid_8021q, common);
192 u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
194 return mlxsw_sp_fid_8021q_fid(fid)->vid;
197 static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
199 u16 vid = *(u16 *) arg;
201 mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
204 static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
206 return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
207 MLXSW_REG_SFMR_OP_DESTROY_FID;
210 static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
211 u16 fid_offset, bool valid)
213 char sfmr_pl[MLXSW_REG_SFMR_LEN];
215 mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index,
217 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
220 static int mlxsw_sp_fid_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
223 enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_VID_TO_FID;
224 char svfa_pl[MLXSW_REG_SVFA_LEN];
226 mlxsw_reg_svfa_pack(svfa_pl, 0, mt, valid, fid_index, vid);
227 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
230 static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
231 u8 local_port, u16 vid, bool valid)
233 enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
234 char svfa_pl[MLXSW_REG_SVFA_LEN];
236 mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid);
237 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
240 static int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid)
242 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
243 struct mlxsw_sp_fid_8021q *fid_8021q;
246 err = mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, fid->fid_index, true);
250 fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
251 err = mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid,
259 mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false);
263 static void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid)
265 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
266 struct mlxsw_sp_fid_8021q *fid_8021q;
268 fid_8021q = mlxsw_sp_fid_8021q_fid(fid);
269 mlxsw_sp_fid_vid_map(mlxsw_sp, fid->fid_index, fid_8021q->vid, false);
270 mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, false);
273 static int mlxsw_sp_fid_8021q_index_alloc(struct mlxsw_sp_fid *fid,
274 const void *arg, u16 *p_fid_index)
276 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
277 u16 vid = *(u16 *) arg;
279 /* Use 1:1 mapping for simplicity although not a must */
280 if (vid < fid_family->start_index || vid > fid_family->end_index)
288 mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
290 u16 vid = *(u16 *) arg;
292 return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
295 static u16 mlxsw_sp_fid_8021q_flood_index(const struct mlxsw_sp_fid *fid)
297 return fid->fid_index;
300 static int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid,
301 struct mlxsw_sp_port *mlxsw_sp_port,
304 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
305 u8 local_port = mlxsw_sp_port->local_port;
307 /* In case there are no {Port, VID} => FID mappings on the port,
308 * we can use the global VID => FID mapping we created when the
309 * FID was configured.
311 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0)
313 return __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port,
318 mlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid,
319 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
321 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
322 u8 local_port = mlxsw_sp_port->local_port;
324 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 0)
326 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, local_port, vid,
330 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = {
331 .setup = mlxsw_sp_fid_8021q_setup,
332 .configure = mlxsw_sp_fid_8021q_configure,
333 .deconfigure = mlxsw_sp_fid_8021q_deconfigure,
334 .index_alloc = mlxsw_sp_fid_8021q_index_alloc,
335 .compare = mlxsw_sp_fid_8021q_compare,
336 .flood_index = mlxsw_sp_fid_8021q_flood_index,
337 .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map,
338 .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap,
341 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021q_flood_tables[] = {
343 .packet_type = MLXSW_SP_FLOOD_TYPE_UC,
344 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
345 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
349 .packet_type = MLXSW_SP_FLOOD_TYPE_MC,
350 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
351 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
355 .packet_type = MLXSW_SP_FLOOD_TYPE_BC,
356 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_1Q_FID,
357 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET,
362 /* Range and flood configuration must match mlxsw_config_profile */
363 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_family = {
364 .type = MLXSW_SP_FID_TYPE_8021Q,
365 .fid_size = sizeof(struct mlxsw_sp_fid_8021q),
367 .end_index = VLAN_VID_MASK,
368 .flood_tables = mlxsw_sp_fid_8021q_flood_tables,
369 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021q_flood_tables),
370 .rif_type = MLXSW_SP_RIF_TYPE_VLAN,
371 .ops = &mlxsw_sp_fid_8021q_ops,
374 static struct mlxsw_sp_fid_8021d *
375 mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
377 return container_of(fid, struct mlxsw_sp_fid_8021d, common);
380 static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
382 int br_ifindex = *(int *) arg;
384 mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
387 static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
389 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
391 return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true);
394 static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
396 mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
399 static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
400 const void *arg, u16 *p_fid_index)
402 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
403 u16 nr_fids, fid_index;
405 nr_fids = fid_family->end_index - fid_family->start_index + 1;
406 fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);
407 if (fid_index == nr_fids)
409 *p_fid_index = fid_family->start_index + fid_index;
415 mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
417 int br_ifindex = *(int *) arg;
419 return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
422 static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid)
424 return fid->fid_index - fid->fid_family->start_index;
427 static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
429 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
430 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
433 list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
435 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
436 u16 vid = mlxsw_sp_port_vlan->vid;
441 err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
442 mlxsw_sp_port->local_port,
445 goto err_fid_port_vid_map;
448 err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
450 goto err_port_vp_mode_set;
454 err_port_vp_mode_set:
455 err_fid_port_vid_map:
456 list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
457 &mlxsw_sp_port->vlans_list, list) {
458 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
459 u16 vid = mlxsw_sp_port_vlan->vid;
464 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
465 mlxsw_sp_port->local_port, vid,
471 static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
473 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
474 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
476 mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
478 list_for_each_entry_reverse(mlxsw_sp_port_vlan,
479 &mlxsw_sp_port->vlans_list, list) {
480 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
481 u16 vid = mlxsw_sp_port_vlan->vid;
486 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
487 mlxsw_sp_port->local_port, vid,
492 static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
493 struct mlxsw_sp_port *mlxsw_sp_port,
496 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
497 u8 local_port = mlxsw_sp_port->local_port;
500 err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
501 mlxsw_sp_port->local_port, vid, true);
505 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
506 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
508 goto err_port_vp_mode_trans;
513 err_port_vp_mode_trans:
514 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
515 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
516 mlxsw_sp_port->local_port, vid, false);
521 mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
522 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
524 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
525 u8 local_port = mlxsw_sp_port->local_port;
527 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
528 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
529 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
530 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
531 mlxsw_sp_port->local_port, vid, false);
534 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
535 .setup = mlxsw_sp_fid_8021d_setup,
536 .configure = mlxsw_sp_fid_8021d_configure,
537 .deconfigure = mlxsw_sp_fid_8021d_deconfigure,
538 .index_alloc = mlxsw_sp_fid_8021d_index_alloc,
539 .compare = mlxsw_sp_fid_8021d_compare,
540 .flood_index = mlxsw_sp_fid_8021d_flood_index,
541 .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map,
542 .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap,
545 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
547 .packet_type = MLXSW_SP_FLOOD_TYPE_UC,
548 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
549 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID,
553 .packet_type = MLXSW_SP_FLOOD_TYPE_MC,
554 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
555 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID,
559 .packet_type = MLXSW_SP_FLOOD_TYPE_BC,
560 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
561 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID,
566 /* Range and flood configuration must match mlxsw_config_profile */
567 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = {
568 .type = MLXSW_SP_FID_TYPE_8021D,
569 .fid_size = sizeof(struct mlxsw_sp_fid_8021d),
570 .start_index = VLAN_N_VID,
571 .end_index = VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1,
572 .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
573 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
574 .rif_type = MLXSW_SP_RIF_TYPE_FID,
575 .ops = &mlxsw_sp_fid_8021d_ops,
578 static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
580 /* rFIDs are allocated by the device during init */
584 static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
588 static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
589 const void *arg, u16 *p_fid_index)
591 u16 rif_index = *(u16 *) arg;
593 *p_fid_index = fid->fid_family->start_index + rif_index;
598 static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
601 u16 rif_index = *(u16 *) arg;
603 return fid->fid_index == rif_index + fid->fid_family->start_index;
606 static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
607 struct mlxsw_sp_port *mlxsw_sp_port,
610 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
611 u8 local_port = mlxsw_sp_port->local_port;
614 /* We only need to transition the port to virtual mode since
615 * {Port, VID} => FID is done by the firmware upon RIF creation.
617 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
618 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
620 goto err_port_vp_mode_trans;
625 err_port_vp_mode_trans:
626 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
631 mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
632 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
634 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
635 u8 local_port = mlxsw_sp_port->local_port;
637 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
638 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
639 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
642 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
643 .configure = mlxsw_sp_fid_rfid_configure,
644 .deconfigure = mlxsw_sp_fid_rfid_deconfigure,
645 .index_alloc = mlxsw_sp_fid_rfid_index_alloc,
646 .compare = mlxsw_sp_fid_rfid_compare,
647 .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map,
648 .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap,
651 #define MLXSW_SP_RFID_BASE (15 * 1024)
652 #define MLXSW_SP_RFID_MAX 1024
654 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
655 .type = MLXSW_SP_FID_TYPE_RFID,
656 .fid_size = sizeof(struct mlxsw_sp_fid),
657 .start_index = MLXSW_SP_RFID_BASE,
658 .end_index = MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1,
659 .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT,
660 .ops = &mlxsw_sp_fid_rfid_ops,
663 static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
665 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
667 return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true);
670 static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
672 mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
675 static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
676 const void *arg, u16 *p_fid_index)
678 *p_fid_index = fid->fid_family->start_index;
683 static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
689 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
690 .configure = mlxsw_sp_fid_dummy_configure,
691 .deconfigure = mlxsw_sp_fid_dummy_deconfigure,
692 .index_alloc = mlxsw_sp_fid_dummy_index_alloc,
693 .compare = mlxsw_sp_fid_dummy_compare,
696 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = {
697 .type = MLXSW_SP_FID_TYPE_DUMMY,
698 .fid_size = sizeof(struct mlxsw_sp_fid),
699 .start_index = VLAN_N_VID - 1,
700 .end_index = VLAN_N_VID - 1,
701 .ops = &mlxsw_sp_fid_dummy_ops,
704 static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = {
705 [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp_fid_8021q_family,
706 [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp_fid_8021d_family,
707 [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family,
708 [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family,
711 static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
712 enum mlxsw_sp_fid_type type,
715 struct mlxsw_sp_fid_family *fid_family;
716 struct mlxsw_sp_fid *fid;
720 fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
721 list_for_each_entry(fid, &fid_family->fids_list, list) {
722 if (!fid->fid_family->ops->compare(fid, arg))
728 fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
730 return ERR_PTR(-ENOMEM);
731 fid->fid_family = fid_family;
733 err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
735 goto err_index_alloc;
736 fid->fid_index = fid_index;
737 __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
739 if (fid->fid_family->ops->setup)
740 fid->fid_family->ops->setup(fid, arg);
742 err = fid->fid_family->ops->configure(fid);
746 list_add(&fid->list, &fid_family->fids_list);
751 __clear_bit(fid_index - fid_family->start_index,
752 fid_family->fids_bitmap);
758 void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
760 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
762 if (--fid->ref_count == 1 && fid->rif) {
763 /* Destroy the associated RIF and let it drop the last
764 * reference on the FID.
766 return mlxsw_sp_rif_destroy(fid->rif);
767 } else if (fid->ref_count == 0) {
768 list_del(&fid->list);
769 fid->fid_family->ops->deconfigure(fid);
770 __clear_bit(fid->fid_index - fid_family->start_index,
771 fid_family->fids_bitmap);
776 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
778 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
781 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
784 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
787 struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
790 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);
793 struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
795 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);
799 mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
800 const struct mlxsw_sp_flood_table *flood_table)
802 enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
803 const int *sfgc_packet_types;
806 sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
807 for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
808 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
809 char sfgc_pl[MLXSW_REG_SFGC_LEN];
812 if (!sfgc_packet_types[i])
814 mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type,
815 flood_table->table_type,
816 flood_table->table_index);
817 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
826 mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
830 for (i = 0; i < fid_family->nr_flood_tables; i++) {
831 const struct mlxsw_sp_flood_table *flood_table;
834 flood_table = &fid_family->flood_tables[i];
835 err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
843 static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
844 const struct mlxsw_sp_fid_family *tmpl)
846 u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
847 struct mlxsw_sp_fid_family *fid_family;
850 fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);
854 fid_family->mlxsw_sp = mlxsw_sp;
855 INIT_LIST_HEAD(&fid_family->fids_list);
856 fid_family->fids_bitmap = kcalloc(BITS_TO_LONGS(nr_fids),
857 sizeof(unsigned long), GFP_KERNEL);
858 if (!fid_family->fids_bitmap) {
860 goto err_alloc_fids_bitmap;
863 if (fid_family->flood_tables) {
864 err = mlxsw_sp_fid_flood_tables_init(fid_family);
866 goto err_fid_flood_tables_init;
869 mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
873 err_fid_flood_tables_init:
874 kfree(fid_family->fids_bitmap);
875 err_alloc_fids_bitmap:
881 mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
882 struct mlxsw_sp_fid_family *fid_family)
884 mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
885 kfree(fid_family->fids_bitmap);
886 WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
890 int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
892 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
894 /* Track number of FIDs configured on the port with mapping type
895 * PORT_VID_TO_FID, so that we know when to transition the port
896 * back to non-virtual (VLAN) mode.
898 mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
900 return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
903 void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
905 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
907 mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
910 int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
912 unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
913 struct mlxsw_sp_fid_core *fid_core;
916 fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
919 mlxsw_sp->fid_core = fid_core;
921 fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
923 if (!fid_core->port_fid_mappings) {
925 goto err_alloc_port_fid_mappings;
928 for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
929 err = mlxsw_sp_fid_family_register(mlxsw_sp,
930 mlxsw_sp_fid_family_arr[i]);
933 goto err_fid_ops_register;
938 err_fid_ops_register:
939 for (i--; i >= 0; i--) {
940 struct mlxsw_sp_fid_family *fid_family;
942 fid_family = fid_core->fid_family_arr[i];
943 mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
945 kfree(fid_core->port_fid_mappings);
946 err_alloc_port_fid_mappings:
951 void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
953 struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
956 for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
957 mlxsw_sp_fid_family_unregister(mlxsw_sp,
958 fid_core->fid_family_arr[i]);
959 kfree(fid_core->port_fid_mappings);