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>
11 #include <linux/refcount.h>
16 struct mlxsw_sp_fid_family;
18 struct mlxsw_sp_fid_core {
19 struct rhashtable fid_ht;
20 struct rhashtable vni_ht;
21 struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX];
22 unsigned int *port_fid_mappings;
26 struct list_head list;
27 struct mlxsw_sp_rif *rif;
30 struct mlxsw_sp_fid_family *fid_family;
31 struct rhash_head ht_node;
33 struct rhash_head vni_ht_node;
34 enum mlxsw_sp_nve_type nve_type;
39 nve_flood_index_valid:1;
42 struct mlxsw_sp_fid_8021q {
43 struct mlxsw_sp_fid common;
47 struct mlxsw_sp_fid_8021d {
48 struct mlxsw_sp_fid common;
52 static const struct rhashtable_params mlxsw_sp_fid_ht_params = {
53 .key_len = sizeof_field(struct mlxsw_sp_fid, fid_index),
54 .key_offset = offsetof(struct mlxsw_sp_fid, fid_index),
55 .head_offset = offsetof(struct mlxsw_sp_fid, ht_node),
58 static const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = {
59 .key_len = sizeof_field(struct mlxsw_sp_fid, vni),
60 .key_offset = offsetof(struct mlxsw_sp_fid, vni),
61 .head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node),
64 struct mlxsw_sp_flood_table {
65 enum mlxsw_sp_flood_type packet_type;
66 enum mlxsw_reg_sfgc_bridge_type bridge_type;
67 enum mlxsw_flood_table_type table_type;
71 struct mlxsw_sp_fid_ops {
72 void (*setup)(struct mlxsw_sp_fid *fid, const void *arg);
73 int (*configure)(struct mlxsw_sp_fid *fid);
74 void (*deconfigure)(struct mlxsw_sp_fid *fid);
75 int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg,
77 bool (*compare)(const struct mlxsw_sp_fid *fid,
79 u16 (*flood_index)(const struct mlxsw_sp_fid *fid);
80 int (*port_vid_map)(struct mlxsw_sp_fid *fid,
81 struct mlxsw_sp_port *port, u16 vid);
82 void (*port_vid_unmap)(struct mlxsw_sp_fid *fid,
83 struct mlxsw_sp_port *port, u16 vid);
84 int (*vni_set)(struct mlxsw_sp_fid *fid, __be32 vni);
85 void (*vni_clear)(struct mlxsw_sp_fid *fid);
86 int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid,
88 void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid);
89 void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid,
90 const struct net_device *nve_dev);
93 struct mlxsw_sp_fid_family {
94 enum mlxsw_sp_fid_type type;
98 struct list_head fids_list;
99 unsigned long *fids_bitmap;
100 const struct mlxsw_sp_flood_table *flood_tables;
102 enum mlxsw_sp_rif_type rif_type;
103 const struct mlxsw_sp_fid_ops *ops;
104 struct mlxsw_sp *mlxsw_sp;
108 static const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
109 [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1,
112 static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
113 [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1,
114 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1,
115 [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1,
116 [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1,
117 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1,
120 static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
121 [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1,
124 static const int *mlxsw_sp_packet_type_sfgc_types[] = {
125 [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types,
126 [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types,
127 [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types,
130 bool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index)
132 enum mlxsw_sp_fid_type fid_type = MLXSW_SP_FID_TYPE_DUMMY;
133 struct mlxsw_sp_fid_family *fid_family;
135 fid_family = mlxsw_sp->fid_core->fid_family_arr[fid_type];
137 return fid_family->start_index == fid_index;
140 bool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid)
142 return fid->fid_family->lag_vid_valid;
145 struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp,
148 struct mlxsw_sp_fid *fid;
150 fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index,
151 mlxsw_sp_fid_ht_params);
153 refcount_inc(&fid->ref_count);
158 int mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex)
163 *nve_ifindex = fid->nve_ifindex;
168 int mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid,
169 enum mlxsw_sp_nve_type *p_type)
174 *p_type = fid->nve_type;
179 struct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp,
182 struct mlxsw_sp_fid *fid;
184 fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni,
185 mlxsw_sp_fid_vni_ht_params);
187 refcount_inc(&fid->ref_count);
192 int mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni)
202 int mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid,
205 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
206 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
209 if (WARN_ON(!ops->nve_flood_index_set || fid->nve_flood_index_valid))
212 err = ops->nve_flood_index_set(fid, nve_flood_index);
216 fid->nve_flood_index = nve_flood_index;
217 fid->nve_flood_index_valid = true;
222 void mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
224 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
225 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
227 if (WARN_ON(!ops->nve_flood_index_clear || !fid->nve_flood_index_valid))
230 fid->nve_flood_index_valid = false;
231 ops->nve_flood_index_clear(fid);
234 bool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid)
236 return fid->nve_flood_index_valid;
239 int mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type,
240 __be32 vni, int nve_ifindex)
242 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
243 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
244 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
247 if (WARN_ON(!ops->vni_set || fid->vni_valid))
250 fid->nve_type = type;
251 fid->nve_ifindex = nve_ifindex;
253 err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht,
255 mlxsw_sp_fid_vni_ht_params);
259 err = ops->vni_set(fid, vni);
263 fid->vni_valid = true;
268 rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
269 mlxsw_sp_fid_vni_ht_params);
273 void mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid)
275 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
276 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
277 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
279 if (WARN_ON(!ops->vni_clear || !fid->vni_valid))
282 fid->vni_valid = false;
284 rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node,
285 mlxsw_sp_fid_vni_ht_params);
288 bool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid)
290 return fid->vni_valid;
293 void mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
294 const struct net_device *nve_dev)
296 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
297 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
299 if (ops->fdb_clear_offload)
300 ops->fdb_clear_offload(fid, nve_dev);
303 static const struct mlxsw_sp_flood_table *
304 mlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid,
305 enum mlxsw_sp_flood_type packet_type)
307 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
310 for (i = 0; i < fid_family->nr_flood_tables; i++) {
311 if (fid_family->flood_tables[i].packet_type != packet_type)
313 return &fid_family->flood_tables[i];
319 int mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid,
320 enum mlxsw_sp_flood_type packet_type, u8 local_port,
323 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
324 const struct mlxsw_sp_fid_ops *ops = fid_family->ops;
325 const struct mlxsw_sp_flood_table *flood_table;
329 if (WARN_ON(!fid_family->flood_tables || !ops->flood_index))
332 flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type);
336 sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL);
340 mlxsw_reg_sftr_pack(sftr_pl, flood_table->table_index,
341 ops->flood_index(fid), flood_table->table_type, 1,
343 err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr),
349 int mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid,
350 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
352 if (WARN_ON(!fid->fid_family->ops->port_vid_map))
354 return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid);
357 void mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid,
358 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
360 fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid);
363 u16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid)
365 return fid->fid_index;
368 enum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid)
370 return fid->fid_family->type;
373 void mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif)
378 struct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid)
383 enum mlxsw_sp_rif_type
384 mlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp,
385 enum mlxsw_sp_fid_type type)
387 struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
389 return fid_core->fid_family_arr[type]->rif_type;
392 static struct mlxsw_sp_fid_8021q *
393 mlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid)
395 return container_of(fid, struct mlxsw_sp_fid_8021q, common);
398 u16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid)
400 return mlxsw_sp_fid_8021q_fid(fid)->vid;
403 static void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg)
405 u16 vid = *(u16 *) arg;
407 mlxsw_sp_fid_8021q_fid(fid)->vid = vid;
410 static enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid)
412 return valid ? MLXSW_REG_SFMR_OP_CREATE_FID :
413 MLXSW_REG_SFMR_OP_DESTROY_FID;
416 static int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
417 u16 fid_offset, bool valid)
419 char sfmr_pl[MLXSW_REG_SFMR_LEN];
421 mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index,
423 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
426 static int mlxsw_sp_fid_vni_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
427 __be32 vni, bool vni_valid, u32 nve_flood_index,
428 bool nve_flood_index_valid)
430 char sfmr_pl[MLXSW_REG_SFMR_LEN];
432 mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, fid_index,
434 mlxsw_reg_sfmr_vv_set(sfmr_pl, vni_valid);
435 mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(vni));
436 mlxsw_reg_sfmr_vtfp_set(sfmr_pl, nve_flood_index_valid);
437 mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, nve_flood_index);
438 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl);
441 static int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index,
442 u8 local_port, u16 vid, bool valid)
444 enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID;
445 char svfa_pl[MLXSW_REG_SVFA_LEN];
447 mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid);
448 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl);
451 static struct mlxsw_sp_fid_8021d *
452 mlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid)
454 return container_of(fid, struct mlxsw_sp_fid_8021d, common);
457 static void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg)
459 int br_ifindex = *(int *) arg;
461 mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex;
464 static int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid)
466 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
468 return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true);
471 static void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid)
474 mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid);
475 mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
478 static int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid,
479 const void *arg, u16 *p_fid_index)
481 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
482 u16 nr_fids, fid_index;
484 nr_fids = fid_family->end_index - fid_family->start_index + 1;
485 fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids);
486 if (fid_index == nr_fids)
488 *p_fid_index = fid_family->start_index + fid_index;
494 mlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg)
496 int br_ifindex = *(int *) arg;
498 return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex;
501 static u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid)
503 return fid->fid_index - VLAN_N_VID;
506 static int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
508 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
509 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
512 list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list,
514 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
515 u16 vid = mlxsw_sp_port_vlan->vid;
520 err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
521 mlxsw_sp_port->local_port,
524 goto err_fid_port_vid_map;
527 err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true);
529 goto err_port_vp_mode_set;
533 err_port_vp_mode_set:
534 err_fid_port_vid_map:
535 list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan,
536 &mlxsw_sp_port->vlans_list, list) {
537 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
538 u16 vid = mlxsw_sp_port_vlan->vid;
543 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
544 mlxsw_sp_port->local_port, vid,
550 static void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port)
552 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
553 struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
555 mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
557 list_for_each_entry_reverse(mlxsw_sp_port_vlan,
558 &mlxsw_sp_port->vlans_list, list) {
559 struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
560 u16 vid = mlxsw_sp_port_vlan->vid;
565 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
566 mlxsw_sp_port->local_port, vid,
571 static int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid,
572 struct mlxsw_sp_port *mlxsw_sp_port,
575 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
576 u8 local_port = mlxsw_sp_port->local_port;
579 err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
580 mlxsw_sp_port->local_port, vid, true);
584 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
585 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
587 goto err_port_vp_mode_trans;
592 err_port_vp_mode_trans:
593 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
594 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
595 mlxsw_sp_port->local_port, vid, false);
600 mlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid,
601 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
603 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
604 u8 local_port = mlxsw_sp_port->local_port;
606 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
607 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
608 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
609 __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index,
610 mlxsw_sp_port->local_port, vid, false);
613 static int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid, __be32 vni)
615 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
617 return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, vni,
618 true, fid->nve_flood_index,
619 fid->nve_flood_index_valid);
622 static void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid)
624 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
626 mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, 0, false,
627 fid->nve_flood_index, fid->nve_flood_index_valid);
630 static int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid,
633 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
635 return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index,
636 fid->vni, fid->vni_valid, nve_flood_index,
640 static void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid)
642 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
644 mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, fid->vni,
645 fid->vni_valid, 0, false);
649 mlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
650 const struct net_device *nve_dev)
652 br_fdb_clear_offload(nve_dev, 0);
655 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = {
656 .setup = mlxsw_sp_fid_8021d_setup,
657 .configure = mlxsw_sp_fid_8021d_configure,
658 .deconfigure = mlxsw_sp_fid_8021d_deconfigure,
659 .index_alloc = mlxsw_sp_fid_8021d_index_alloc,
660 .compare = mlxsw_sp_fid_8021d_compare,
661 .flood_index = mlxsw_sp_fid_8021d_flood_index,
662 .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map,
663 .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap,
664 .vni_set = mlxsw_sp_fid_8021d_vni_set,
665 .vni_clear = mlxsw_sp_fid_8021d_vni_clear,
666 .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set,
667 .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear,
668 .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload,
671 static const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = {
673 .packet_type = MLXSW_SP_FLOOD_TYPE_UC,
674 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
675 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID,
679 .packet_type = MLXSW_SP_FLOOD_TYPE_MC,
680 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
681 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID,
685 .packet_type = MLXSW_SP_FLOOD_TYPE_BC,
686 .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID,
687 .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID,
692 /* Range and flood configuration must match mlxsw_config_profile */
693 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = {
694 .type = MLXSW_SP_FID_TYPE_8021D,
695 .fid_size = sizeof(struct mlxsw_sp_fid_8021d),
696 .start_index = VLAN_N_VID,
697 .end_index = VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1,
698 .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
699 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
700 .rif_type = MLXSW_SP_RIF_TYPE_FID,
701 .ops = &mlxsw_sp_fid_8021d_ops,
706 mlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg)
708 u16 vid = *(u16 *) arg;
710 return mlxsw_sp_fid_8021q_fid(fid)->vid == vid;
714 mlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid,
715 const struct net_device *nve_dev)
717 br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid));
720 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_emu_ops = {
721 .setup = mlxsw_sp_fid_8021q_setup,
722 .configure = mlxsw_sp_fid_8021d_configure,
723 .deconfigure = mlxsw_sp_fid_8021d_deconfigure,
724 .index_alloc = mlxsw_sp_fid_8021d_index_alloc,
725 .compare = mlxsw_sp_fid_8021q_compare,
726 .flood_index = mlxsw_sp_fid_8021d_flood_index,
727 .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map,
728 .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap,
729 .vni_set = mlxsw_sp_fid_8021d_vni_set,
730 .vni_clear = mlxsw_sp_fid_8021d_vni_clear,
731 .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set,
732 .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear,
733 .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload,
736 /* There are 4K-2 emulated 802.1Q FIDs, starting right after the 802.1D FIDs */
737 #define MLXSW_SP_FID_8021Q_EMU_START (VLAN_N_VID + MLXSW_SP_FID_8021D_MAX)
738 #define MLXSW_SP_FID_8021Q_EMU_END (MLXSW_SP_FID_8021Q_EMU_START + \
741 /* Range and flood configuration must match mlxsw_config_profile */
742 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_emu_family = {
743 .type = MLXSW_SP_FID_TYPE_8021Q,
744 .fid_size = sizeof(struct mlxsw_sp_fid_8021q),
745 .start_index = MLXSW_SP_FID_8021Q_EMU_START,
746 .end_index = MLXSW_SP_FID_8021Q_EMU_END,
747 .flood_tables = mlxsw_sp_fid_8021d_flood_tables,
748 .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables),
749 .rif_type = MLXSW_SP_RIF_TYPE_VLAN,
750 .ops = &mlxsw_sp_fid_8021q_emu_ops,
754 static int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid)
756 /* rFIDs are allocated by the device during init */
760 static void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid)
764 static int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid,
765 const void *arg, u16 *p_fid_index)
767 u16 rif_index = *(u16 *) arg;
769 *p_fid_index = fid->fid_family->start_index + rif_index;
774 static bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid,
777 u16 rif_index = *(u16 *) arg;
779 return fid->fid_index == rif_index + fid->fid_family->start_index;
782 static int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid,
783 struct mlxsw_sp_port *mlxsw_sp_port,
786 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
787 u8 local_port = mlxsw_sp_port->local_port;
790 /* We only need to transition the port to virtual mode since
791 * {Port, VID} => FID is done by the firmware upon RIF creation.
793 if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) {
794 err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port);
796 goto err_port_vp_mode_trans;
801 err_port_vp_mode_trans:
802 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
807 mlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid,
808 struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
810 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
811 u8 local_port = mlxsw_sp_port->local_port;
813 if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1)
814 mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port);
815 mlxsw_sp->fid_core->port_fid_mappings[local_port]--;
818 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = {
819 .configure = mlxsw_sp_fid_rfid_configure,
820 .deconfigure = mlxsw_sp_fid_rfid_deconfigure,
821 .index_alloc = mlxsw_sp_fid_rfid_index_alloc,
822 .compare = mlxsw_sp_fid_rfid_compare,
823 .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map,
824 .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap,
827 #define MLXSW_SP_RFID_BASE (15 * 1024)
828 #define MLXSW_SP_RFID_MAX 1024
830 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = {
831 .type = MLXSW_SP_FID_TYPE_RFID,
832 .fid_size = sizeof(struct mlxsw_sp_fid),
833 .start_index = MLXSW_SP_RFID_BASE,
834 .end_index = MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1,
835 .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT,
836 .ops = &mlxsw_sp_fid_rfid_ops,
839 static int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid)
841 struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp;
843 return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true);
846 static void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid)
848 mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false);
851 static int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid,
852 const void *arg, u16 *p_fid_index)
854 *p_fid_index = fid->fid_family->start_index;
859 static bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid,
865 static const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = {
866 .configure = mlxsw_sp_fid_dummy_configure,
867 .deconfigure = mlxsw_sp_fid_dummy_deconfigure,
868 .index_alloc = mlxsw_sp_fid_dummy_index_alloc,
869 .compare = mlxsw_sp_fid_dummy_compare,
872 static const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = {
873 .type = MLXSW_SP_FID_TYPE_DUMMY,
874 .fid_size = sizeof(struct mlxsw_sp_fid),
875 .start_index = VLAN_N_VID - 1,
876 .end_index = VLAN_N_VID - 1,
877 .ops = &mlxsw_sp_fid_dummy_ops,
880 static const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = {
881 [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp_fid_8021q_emu_family,
882 [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp_fid_8021d_family,
883 [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family,
884 [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family,
887 static struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp,
888 enum mlxsw_sp_fid_type type,
891 struct mlxsw_sp_fid_family *fid_family;
892 struct mlxsw_sp_fid *fid;
894 fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
895 list_for_each_entry(fid, &fid_family->fids_list, list) {
896 if (!fid->fid_family->ops->compare(fid, arg))
898 refcount_inc(&fid->ref_count);
905 static struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp,
906 enum mlxsw_sp_fid_type type,
909 struct mlxsw_sp_fid_family *fid_family;
910 struct mlxsw_sp_fid *fid;
914 fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg);
918 fid_family = mlxsw_sp->fid_core->fid_family_arr[type];
919 fid = kzalloc(fid_family->fid_size, GFP_KERNEL);
921 return ERR_PTR(-ENOMEM);
922 fid->fid_family = fid_family;
924 err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index);
926 goto err_index_alloc;
927 fid->fid_index = fid_index;
928 __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap);
930 if (fid->fid_family->ops->setup)
931 fid->fid_family->ops->setup(fid, arg);
933 err = fid->fid_family->ops->configure(fid);
937 err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node,
938 mlxsw_sp_fid_ht_params);
940 goto err_rhashtable_insert;
942 list_add(&fid->list, &fid_family->fids_list);
943 refcount_set(&fid->ref_count, 1);
946 err_rhashtable_insert:
947 fid->fid_family->ops->deconfigure(fid);
949 __clear_bit(fid_index - fid_family->start_index,
950 fid_family->fids_bitmap);
956 void mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid)
958 struct mlxsw_sp_fid_family *fid_family = fid->fid_family;
959 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
961 if (!refcount_dec_and_test(&fid->ref_count))
964 list_del(&fid->list);
965 rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht,
966 &fid->ht_node, mlxsw_sp_fid_ht_params);
967 fid->fid_family->ops->deconfigure(fid);
968 __clear_bit(fid->fid_index - fid_family->start_index,
969 fid_family->fids_bitmap);
973 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid)
975 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
978 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp,
981 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex);
984 struct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp,
987 return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid);
990 struct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp,
993 return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D,
997 struct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp,
1000 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index);
1003 struct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp)
1005 return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL);
1009 mlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family,
1010 const struct mlxsw_sp_flood_table *flood_table)
1012 enum mlxsw_sp_flood_type packet_type = flood_table->packet_type;
1013 const int *sfgc_packet_types;
1016 sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type];
1017 for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) {
1018 struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp;
1019 char sfgc_pl[MLXSW_REG_SFGC_LEN];
1022 if (!sfgc_packet_types[i])
1024 mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type,
1025 flood_table->table_type,
1026 flood_table->table_index);
1027 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl);
1036 mlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family)
1040 for (i = 0; i < fid_family->nr_flood_tables; i++) {
1041 const struct mlxsw_sp_flood_table *flood_table;
1044 flood_table = &fid_family->flood_tables[i];
1045 err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table);
1053 static int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp,
1054 const struct mlxsw_sp_fid_family *tmpl)
1056 u16 nr_fids = tmpl->end_index - tmpl->start_index + 1;
1057 struct mlxsw_sp_fid_family *fid_family;
1060 fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL);
1064 fid_family->mlxsw_sp = mlxsw_sp;
1065 INIT_LIST_HEAD(&fid_family->fids_list);
1066 fid_family->fids_bitmap = bitmap_zalloc(nr_fids, GFP_KERNEL);
1067 if (!fid_family->fids_bitmap) {
1069 goto err_alloc_fids_bitmap;
1072 if (fid_family->flood_tables) {
1073 err = mlxsw_sp_fid_flood_tables_init(fid_family);
1075 goto err_fid_flood_tables_init;
1078 mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family;
1082 err_fid_flood_tables_init:
1083 bitmap_free(fid_family->fids_bitmap);
1084 err_alloc_fids_bitmap:
1090 mlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp,
1091 struct mlxsw_sp_fid_family *fid_family)
1093 mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL;
1094 bitmap_free(fid_family->fids_bitmap);
1095 WARN_ON_ONCE(!list_empty(&fid_family->fids_list));
1099 int mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port)
1101 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1103 /* Track number of FIDs configured on the port with mapping type
1104 * PORT_VID_TO_FID, so that we know when to transition the port
1105 * back to non-virtual (VLAN) mode.
1107 mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1109 return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false);
1112 void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port)
1114 struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
1116 mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0;
1119 int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp)
1121 unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core);
1122 struct mlxsw_sp_fid_core *fid_core;
1125 fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL);
1128 mlxsw_sp->fid_core = fid_core;
1130 err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params);
1132 goto err_rhashtable_fid_init;
1134 err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params);
1136 goto err_rhashtable_vni_init;
1138 fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int),
1140 if (!fid_core->port_fid_mappings) {
1142 goto err_alloc_port_fid_mappings;
1145 for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) {
1146 err = mlxsw_sp_fid_family_register(mlxsw_sp,
1147 mlxsw_sp_fid_family_arr[i]);
1150 goto err_fid_ops_register;
1155 err_fid_ops_register:
1156 for (i--; i >= 0; i--) {
1157 struct mlxsw_sp_fid_family *fid_family;
1159 fid_family = fid_core->fid_family_arr[i];
1160 mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family);
1162 kfree(fid_core->port_fid_mappings);
1163 err_alloc_port_fid_mappings:
1164 rhashtable_destroy(&fid_core->vni_ht);
1165 err_rhashtable_vni_init:
1166 rhashtable_destroy(&fid_core->fid_ht);
1167 err_rhashtable_fid_init:
1172 void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp)
1174 struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core;
1177 for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++)
1178 mlxsw_sp_fid_family_unregister(mlxsw_sp,
1179 fid_core->fid_family_arr[i]);
1180 kfree(fid_core->port_fid_mappings);
1181 rhashtable_destroy(&fid_core->vni_ht);
1182 rhashtable_destroy(&fid_core->fid_ht);