162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/kernel.h> 562306a36Sopenharmony_ci#include <linux/bitops.h> 662306a36Sopenharmony_ci#include <linux/if_vlan.h> 762306a36Sopenharmony_ci#include <linux/if_bridge.h> 862306a36Sopenharmony_ci#include <linux/netdevice.h> 962306a36Sopenharmony_ci#include <linux/rhashtable.h> 1062306a36Sopenharmony_ci#include <linux/rtnetlink.h> 1162306a36Sopenharmony_ci#include <linux/refcount.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "spectrum.h" 1462306a36Sopenharmony_ci#include "reg.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistruct mlxsw_sp_fid_family; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistruct mlxsw_sp_fid_core { 1962306a36Sopenharmony_ci struct rhashtable fid_ht; 2062306a36Sopenharmony_ci struct rhashtable vni_ht; 2162306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX]; 2262306a36Sopenharmony_ci unsigned int *port_fid_mappings; 2362306a36Sopenharmony_ci}; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct mlxsw_sp_fid_port_vid { 2662306a36Sopenharmony_ci struct list_head list; 2762306a36Sopenharmony_ci u16 local_port; 2862306a36Sopenharmony_ci u16 vid; 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistruct mlxsw_sp_fid { 3262306a36Sopenharmony_ci struct list_head list; 3362306a36Sopenharmony_ci struct mlxsw_sp_rif *rif; 3462306a36Sopenharmony_ci refcount_t ref_count; 3562306a36Sopenharmony_ci u16 fid_index; 3662306a36Sopenharmony_ci u16 fid_offset; 3762306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family; 3862306a36Sopenharmony_ci struct rhash_head ht_node; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci struct rhash_head vni_ht_node; 4162306a36Sopenharmony_ci enum mlxsw_sp_nve_type nve_type; 4262306a36Sopenharmony_ci __be32 vni; 4362306a36Sopenharmony_ci u32 nve_flood_index; 4462306a36Sopenharmony_ci int nve_ifindex; 4562306a36Sopenharmony_ci u8 vni_valid:1, 4662306a36Sopenharmony_ci nve_flood_index_valid:1; 4762306a36Sopenharmony_ci struct list_head port_vid_list; /* Ordered by local port. */ 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistruct mlxsw_sp_fid_8021q { 5162306a36Sopenharmony_ci struct mlxsw_sp_fid common; 5262306a36Sopenharmony_ci u16 vid; 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistruct mlxsw_sp_fid_8021d { 5662306a36Sopenharmony_ci struct mlxsw_sp_fid common; 5762306a36Sopenharmony_ci int br_ifindex; 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic const struct rhashtable_params mlxsw_sp_fid_ht_params = { 6162306a36Sopenharmony_ci .key_len = sizeof_field(struct mlxsw_sp_fid, fid_index), 6262306a36Sopenharmony_ci .key_offset = offsetof(struct mlxsw_sp_fid, fid_index), 6362306a36Sopenharmony_ci .head_offset = offsetof(struct mlxsw_sp_fid, ht_node), 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = { 6762306a36Sopenharmony_ci .key_len = sizeof_field(struct mlxsw_sp_fid, vni), 6862306a36Sopenharmony_ci .key_offset = offsetof(struct mlxsw_sp_fid, vni), 6962306a36Sopenharmony_ci .head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node), 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistruct mlxsw_sp_flood_table { 7362306a36Sopenharmony_ci enum mlxsw_sp_flood_type packet_type; 7462306a36Sopenharmony_ci enum mlxsw_flood_table_type table_type; 7562306a36Sopenharmony_ci int table_index; 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistruct mlxsw_sp_fid_ops { 7962306a36Sopenharmony_ci void (*setup)(struct mlxsw_sp_fid *fid, const void *arg); 8062306a36Sopenharmony_ci int (*configure)(struct mlxsw_sp_fid *fid); 8162306a36Sopenharmony_ci void (*deconfigure)(struct mlxsw_sp_fid *fid); 8262306a36Sopenharmony_ci int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg, 8362306a36Sopenharmony_ci u16 *p_fid_index); 8462306a36Sopenharmony_ci bool (*compare)(const struct mlxsw_sp_fid *fid, 8562306a36Sopenharmony_ci const void *arg); 8662306a36Sopenharmony_ci int (*port_vid_map)(struct mlxsw_sp_fid *fid, 8762306a36Sopenharmony_ci struct mlxsw_sp_port *port, u16 vid); 8862306a36Sopenharmony_ci void (*port_vid_unmap)(struct mlxsw_sp_fid *fid, 8962306a36Sopenharmony_ci struct mlxsw_sp_port *port, u16 vid); 9062306a36Sopenharmony_ci int (*vni_set)(struct mlxsw_sp_fid *fid); 9162306a36Sopenharmony_ci void (*vni_clear)(struct mlxsw_sp_fid *fid); 9262306a36Sopenharmony_ci int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid); 9362306a36Sopenharmony_ci void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid); 9462306a36Sopenharmony_ci void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid, 9562306a36Sopenharmony_ci const struct net_device *nve_dev); 9662306a36Sopenharmony_ci int (*vid_to_fid_rif_update)(const struct mlxsw_sp_fid *fid, 9762306a36Sopenharmony_ci const struct mlxsw_sp_rif *rif); 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistruct mlxsw_sp_fid_family { 10162306a36Sopenharmony_ci enum mlxsw_sp_fid_type type; 10262306a36Sopenharmony_ci size_t fid_size; 10362306a36Sopenharmony_ci u16 start_index; 10462306a36Sopenharmony_ci u16 end_index; 10562306a36Sopenharmony_ci struct list_head fids_list; 10662306a36Sopenharmony_ci unsigned long *fids_bitmap; 10762306a36Sopenharmony_ci const struct mlxsw_sp_flood_table *flood_tables; 10862306a36Sopenharmony_ci int nr_flood_tables; 10962306a36Sopenharmony_ci enum mlxsw_sp_rif_type rif_type; 11062306a36Sopenharmony_ci const struct mlxsw_sp_fid_ops *ops; 11162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp; 11262306a36Sopenharmony_ci bool flood_rsp; 11362306a36Sopenharmony_ci enum mlxsw_reg_bridge_type bridge_type; 11462306a36Sopenharmony_ci u16 pgt_base; 11562306a36Sopenharmony_ci bool smpe_index_valid; 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { 11962306a36Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1, 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { 12362306a36Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1, 12462306a36Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1, 12562306a36Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1, 12662306a36Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1, 12762306a36Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistatic const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { 13162306a36Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, 13262306a36Sopenharmony_ci}; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic const int *mlxsw_sp_packet_type_sfgc_types[] = { 13562306a36Sopenharmony_ci [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types, 13662306a36Sopenharmony_ci [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types, 13762306a36Sopenharmony_ci [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types, 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp, 14162306a36Sopenharmony_ci u16 fid_index) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct mlxsw_sp_fid *fid; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index, 14662306a36Sopenharmony_ci mlxsw_sp_fid_ht_params); 14762306a36Sopenharmony_ci if (fid) 14862306a36Sopenharmony_ci refcount_inc(&fid->ref_count); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return fid; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ciint mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci if (!fid->vni_valid) 15662306a36Sopenharmony_ci return -EINVAL; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci *nve_ifindex = fid->nve_ifindex; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci return 0; 16162306a36Sopenharmony_ci} 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ciint mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid, 16462306a36Sopenharmony_ci enum mlxsw_sp_nve_type *p_type) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci if (!fid->vni_valid) 16762306a36Sopenharmony_ci return -EINVAL; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci *p_type = fid->nve_type; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp, 17562306a36Sopenharmony_ci __be32 vni) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci struct mlxsw_sp_fid *fid; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni, 18062306a36Sopenharmony_ci mlxsw_sp_fid_vni_ht_params); 18162306a36Sopenharmony_ci if (fid) 18262306a36Sopenharmony_ci refcount_inc(&fid->ref_count); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci return fid; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ciint mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci if (!fid->vni_valid) 19062306a36Sopenharmony_ci return -EINVAL; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci *vni = fid->vni; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ciint mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid, 19862306a36Sopenharmony_ci u32 nve_flood_index) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 20162306a36Sopenharmony_ci const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 20262306a36Sopenharmony_ci int err; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (WARN_ON(fid->nve_flood_index_valid)) 20562306a36Sopenharmony_ci return -EINVAL; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci fid->nve_flood_index = nve_flood_index; 20862306a36Sopenharmony_ci fid->nve_flood_index_valid = true; 20962306a36Sopenharmony_ci err = ops->nve_flood_index_set(fid); 21062306a36Sopenharmony_ci if (err) 21162306a36Sopenharmony_ci goto err_nve_flood_index_set; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return 0; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cierr_nve_flood_index_set: 21662306a36Sopenharmony_ci fid->nve_flood_index_valid = false; 21762306a36Sopenharmony_ci return err; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_civoid mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 22362306a36Sopenharmony_ci const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (WARN_ON(!fid->nve_flood_index_valid)) 22662306a36Sopenharmony_ci return; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci fid->nve_flood_index_valid = false; 22962306a36Sopenharmony_ci ops->nve_flood_index_clear(fid); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cibool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci return fid->nve_flood_index_valid; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ciint mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type, 23862306a36Sopenharmony_ci __be32 vni, int nve_ifindex) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 24162306a36Sopenharmony_ci const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 24262306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 24362306a36Sopenharmony_ci int err; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (WARN_ON(fid->vni_valid)) 24662306a36Sopenharmony_ci return -EINVAL; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci fid->nve_type = type; 24962306a36Sopenharmony_ci fid->nve_ifindex = nve_ifindex; 25062306a36Sopenharmony_ci fid->vni = vni; 25162306a36Sopenharmony_ci err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht, 25262306a36Sopenharmony_ci &fid->vni_ht_node, 25362306a36Sopenharmony_ci mlxsw_sp_fid_vni_ht_params); 25462306a36Sopenharmony_ci if (err) 25562306a36Sopenharmony_ci return err; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci fid->vni_valid = true; 25862306a36Sopenharmony_ci err = ops->vni_set(fid); 25962306a36Sopenharmony_ci if (err) 26062306a36Sopenharmony_ci goto err_vni_set; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci return 0; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cierr_vni_set: 26562306a36Sopenharmony_ci fid->vni_valid = false; 26662306a36Sopenharmony_ci rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node, 26762306a36Sopenharmony_ci mlxsw_sp_fid_vni_ht_params); 26862306a36Sopenharmony_ci return err; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_civoid mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 27462306a36Sopenharmony_ci const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 27562306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (WARN_ON(!fid->vni_valid)) 27862306a36Sopenharmony_ci return; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci fid->vni_valid = false; 28162306a36Sopenharmony_ci ops->vni_clear(fid); 28262306a36Sopenharmony_ci rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node, 28362306a36Sopenharmony_ci mlxsw_sp_fid_vni_ht_params); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cibool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci return fid->vni_valid; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_civoid mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid, 29262306a36Sopenharmony_ci const struct net_device *nve_dev) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 29562306a36Sopenharmony_ci const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (ops->fdb_clear_offload) 29862306a36Sopenharmony_ci ops->fdb_clear_offload(fid, nve_dev); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_cistatic const struct mlxsw_sp_flood_table * 30262306a36Sopenharmony_cimlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid, 30362306a36Sopenharmony_ci enum mlxsw_sp_flood_type packet_type) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 30662306a36Sopenharmony_ci int i; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci for (i = 0; i < fid_family->nr_flood_tables; i++) { 30962306a36Sopenharmony_ci if (fid_family->flood_tables[i].packet_type != packet_type) 31062306a36Sopenharmony_ci continue; 31162306a36Sopenharmony_ci return &fid_family->flood_tables[i]; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return NULL; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic u16 31862306a36Sopenharmony_cimlxsw_sp_fid_family_num_fids(const struct mlxsw_sp_fid_family *fid_family) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci return fid_family->end_index - fid_family->start_index + 1; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic u16 32462306a36Sopenharmony_cimlxsw_sp_fid_flood_table_mid(const struct mlxsw_sp_fid_family *fid_family, 32562306a36Sopenharmony_ci const struct mlxsw_sp_flood_table *flood_table, 32662306a36Sopenharmony_ci u16 fid_offset) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci u16 num_fids; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci num_fids = mlxsw_sp_fid_family_num_fids(fid_family); 33162306a36Sopenharmony_ci return fid_family->pgt_base + num_fids * flood_table->table_index + 33262306a36Sopenharmony_ci fid_offset; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ciint mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, 33662306a36Sopenharmony_ci enum mlxsw_sp_flood_type packet_type, u16 local_port, 33762306a36Sopenharmony_ci bool member) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 34062306a36Sopenharmony_ci const struct mlxsw_sp_flood_table *flood_table; 34162306a36Sopenharmony_ci u16 mid_index; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (WARN_ON(!fid_family->flood_tables)) 34462306a36Sopenharmony_ci return -EINVAL; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type); 34762306a36Sopenharmony_ci if (!flood_table) 34862306a36Sopenharmony_ci return -ESRCH; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci mid_index = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 35162306a36Sopenharmony_ci fid->fid_offset); 35262306a36Sopenharmony_ci return mlxsw_sp_pgt_entry_port_set(fid_family->mlxsw_sp, mid_index, 35362306a36Sopenharmony_ci fid->fid_index, local_port, member); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ciint mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid, 35762306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci if (WARN_ON(!fid->fid_family->ops->port_vid_map)) 36062306a36Sopenharmony_ci return -EINVAL; 36162306a36Sopenharmony_ci return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_civoid mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid, 36562306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ciu16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci return fid->fid_index; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cienum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci return fid->fid_family->type; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistruct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci return fid->rif; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cienum mlxsw_sp_rif_type 38662306a36Sopenharmony_cimlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp, 38762306a36Sopenharmony_ci enum mlxsw_sp_fid_type type) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return fid_core->fid_family_arr[type]->rif_type; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic struct mlxsw_sp_fid_8021q * 39562306a36Sopenharmony_cimlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci return container_of(fid, struct mlxsw_sp_fid_8021q, common); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ciu16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci return mlxsw_sp_fid_8021q_fid(fid)->vid; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci u16 vid = *(u16 *) arg; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci mlxsw_sp_fid_8021q_fid(fid)->vid = vid; 41062306a36Sopenharmony_ci fid->fid_offset = fid->fid_index - fid->fid_family->start_index; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci return valid ? MLXSW_REG_SFMR_OP_CREATE_FID : 41662306a36Sopenharmony_ci MLXSW_REG_SFMR_OP_DESTROY_FID; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic int mlxsw_sp_fid_op(const struct mlxsw_sp_fid *fid, bool valid) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 42262306a36Sopenharmony_ci char sfmr_pl[MLXSW_REG_SFMR_LEN]; 42362306a36Sopenharmony_ci u16 smpe; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid->fid_index, 42862306a36Sopenharmony_ci fid->fid_offset, fid->fid_family->flood_rsp, 42962306a36Sopenharmony_ci fid->fid_family->bridge_type, 43062306a36Sopenharmony_ci fid->fid_family->smpe_index_valid, smpe); 43162306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic int mlxsw_sp_fid_edit_op(const struct mlxsw_sp_fid *fid, 43562306a36Sopenharmony_ci const struct mlxsw_sp_rif *rif) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 43862306a36Sopenharmony_ci char sfmr_pl[MLXSW_REG_SFMR_LEN]; 43962306a36Sopenharmony_ci u16 smpe; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci smpe = fid->fid_family->smpe_index_valid ? fid->fid_index : 0; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, 44462306a36Sopenharmony_ci fid->fid_index, fid->fid_offset, 44562306a36Sopenharmony_ci fid->fid_family->flood_rsp, 44662306a36Sopenharmony_ci fid->fid_family->bridge_type, 44762306a36Sopenharmony_ci fid->fid_family->smpe_index_valid, smpe); 44862306a36Sopenharmony_ci mlxsw_reg_sfmr_vv_set(sfmr_pl, fid->vni_valid); 44962306a36Sopenharmony_ci mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(fid->vni)); 45062306a36Sopenharmony_ci mlxsw_reg_sfmr_vtfp_set(sfmr_pl, fid->nve_flood_index_valid); 45162306a36Sopenharmony_ci mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, fid->nve_flood_index); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (rif) { 45462306a36Sopenharmony_ci mlxsw_reg_sfmr_irif_v_set(sfmr_pl, true); 45562306a36Sopenharmony_ci mlxsw_reg_sfmr_irif_set(sfmr_pl, mlxsw_sp_rif_index(rif)); 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic int mlxsw_sp_fid_vni_to_fid_map(const struct mlxsw_sp_fid *fid, 46262306a36Sopenharmony_ci const struct mlxsw_sp_rif *rif, 46362306a36Sopenharmony_ci bool valid) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 46662306a36Sopenharmony_ci char svfa_pl[MLXSW_REG_SVFA_LEN]; 46762306a36Sopenharmony_ci bool irif_valid; 46862306a36Sopenharmony_ci u16 irif_index; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci irif_valid = !!rif; 47162306a36Sopenharmony_ci irif_index = rif ? mlxsw_sp_rif_index(rif) : 0; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci mlxsw_reg_svfa_vni_pack(svfa_pl, valid, fid->fid_index, 47462306a36Sopenharmony_ci be32_to_cpu(fid->vni), irif_valid, irif_index); 47562306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic int mlxsw_sp_fid_to_fid_rif_update(const struct mlxsw_sp_fid *fid, 47962306a36Sopenharmony_ci const struct mlxsw_sp_rif *rif) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci return mlxsw_sp_fid_edit_op(fid, rif); 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic int mlxsw_sp_fid_vni_to_fid_rif_update(const struct mlxsw_sp_fid *fid, 48562306a36Sopenharmony_ci const struct mlxsw_sp_rif *rif) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci if (!fid->vni_valid) 48862306a36Sopenharmony_ci return 0; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci return mlxsw_sp_fid_vni_to_fid_map(fid, rif, fid->vni_valid); 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic int 49462306a36Sopenharmony_cimlxsw_sp_fid_vid_to_fid_map(const struct mlxsw_sp_fid *fid, u16 vid, bool valid, 49562306a36Sopenharmony_ci const struct mlxsw_sp_rif *rif) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 49862306a36Sopenharmony_ci char svfa_pl[MLXSW_REG_SVFA_LEN]; 49962306a36Sopenharmony_ci bool irif_valid; 50062306a36Sopenharmony_ci u16 irif_index; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci irif_valid = !!rif; 50362306a36Sopenharmony_ci irif_index = rif ? mlxsw_sp_rif_index(rif) : 0; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci mlxsw_reg_svfa_vid_pack(svfa_pl, valid, fid->fid_index, vid, irif_valid, 50662306a36Sopenharmony_ci irif_index); 50762306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); 50862306a36Sopenharmony_ci} 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic int 51162306a36Sopenharmony_cimlxsw_sp_fid_8021q_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid, 51262306a36Sopenharmony_ci const struct mlxsw_sp_rif *rif) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* Update the global VID => FID mapping we created when the FID was 51762306a36Sopenharmony_ci * configured. 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_ci return mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, rif); 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_cistatic int 52362306a36Sopenharmony_cimlxsw_sp_fid_port_vid_to_fid_rif_update_one(const struct mlxsw_sp_fid *fid, 52462306a36Sopenharmony_ci struct mlxsw_sp_fid_port_vid *pv, 52562306a36Sopenharmony_ci bool irif_valid, u16 irif_index) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 52862306a36Sopenharmony_ci char svfa_pl[MLXSW_REG_SVFA_LEN]; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci mlxsw_reg_svfa_port_vid_pack(svfa_pl, pv->local_port, true, 53162306a36Sopenharmony_ci fid->fid_index, pv->vid, irif_valid, 53262306a36Sopenharmony_ci irif_index); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic int mlxsw_sp_fid_vid_to_fid_rif_set(const struct mlxsw_sp_fid *fid, 53862306a36Sopenharmony_ci const struct mlxsw_sp_rif *rif) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 54162306a36Sopenharmony_ci struct mlxsw_sp_fid_port_vid *pv; 54262306a36Sopenharmony_ci u16 irif_index; 54362306a36Sopenharmony_ci int err; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci err = fid->fid_family->ops->vid_to_fid_rif_update(fid, rif); 54662306a36Sopenharmony_ci if (err) 54762306a36Sopenharmony_ci return err; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci irif_index = mlxsw_sp_rif_index(rif); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci list_for_each_entry(pv, &fid->port_vid_list, list) { 55262306a36Sopenharmony_ci /* If port is not in virtual mode, then it does not have any 55362306a36Sopenharmony_ci * {Port, VID}->FID mappings that need to be updated with the 55462306a36Sopenharmony_ci * ingress RIF. 55562306a36Sopenharmony_ci */ 55662306a36Sopenharmony_ci if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port]) 55762306a36Sopenharmony_ci continue; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci err = mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, 56062306a36Sopenharmony_ci true, 56162306a36Sopenharmony_ci irif_index); 56262306a36Sopenharmony_ci if (err) 56362306a36Sopenharmony_ci goto err_port_vid_to_fid_rif_update_one; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci return 0; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_cierr_port_vid_to_fid_rif_update_one: 56962306a36Sopenharmony_ci list_for_each_entry_continue_reverse(pv, &fid->port_vid_list, list) { 57062306a36Sopenharmony_ci if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port]) 57162306a36Sopenharmony_ci continue; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0); 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL); 57762306a36Sopenharmony_ci return err; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic void mlxsw_sp_fid_vid_to_fid_rif_unset(const struct mlxsw_sp_fid *fid) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 58362306a36Sopenharmony_ci struct mlxsw_sp_fid_port_vid *pv; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci list_for_each_entry(pv, &fid->port_vid_list, list) { 58662306a36Sopenharmony_ci /* If port is not in virtual mode, then it does not have any 58762306a36Sopenharmony_ci * {Port, VID}->FID mappings that need to be updated. 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_ci if (!mlxsw_sp->fid_core->port_fid_mappings[pv->local_port]) 59062306a36Sopenharmony_ci continue; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci mlxsw_sp_fid_port_vid_to_fid_rif_update_one(fid, pv, false, 0); 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci fid->fid_family->ops->vid_to_fid_rif_update(fid, NULL); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic int mlxsw_sp_fid_reiv_handle(struct mlxsw_sp_fid *fid, u16 rif_index, 59962306a36Sopenharmony_ci bool valid, u8 port_page) 60062306a36Sopenharmony_ci{ 60162306a36Sopenharmony_ci u16 local_port_end = (port_page + 1) * MLXSW_REG_REIV_REC_MAX_COUNT - 1; 60262306a36Sopenharmony_ci u16 local_port_start = port_page * MLXSW_REG_REIV_REC_MAX_COUNT; 60362306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 60462306a36Sopenharmony_ci struct mlxsw_sp_fid_port_vid *port_vid; 60562306a36Sopenharmony_ci u8 rec_num, entries_num = 0; 60662306a36Sopenharmony_ci char *reiv_pl; 60762306a36Sopenharmony_ci int err; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL); 61062306a36Sopenharmony_ci if (!reiv_pl) 61162306a36Sopenharmony_ci return -ENOMEM; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci list_for_each_entry(port_vid, &fid->port_vid_list, list) { 61662306a36Sopenharmony_ci /* port_vid_list is sorted by local_port. */ 61762306a36Sopenharmony_ci if (port_vid->local_port < local_port_start) 61862306a36Sopenharmony_ci continue; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (port_vid->local_port > local_port_end) 62162306a36Sopenharmony_ci break; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci rec_num = port_vid->local_port % MLXSW_REG_REIV_REC_MAX_COUNT; 62462306a36Sopenharmony_ci mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true); 62562306a36Sopenharmony_ci mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num, 62662306a36Sopenharmony_ci valid ? port_vid->vid : 0); 62762306a36Sopenharmony_ci entries_num++; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (!entries_num) { 63162306a36Sopenharmony_ci kfree(reiv_pl); 63262306a36Sopenharmony_ci return 0; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl); 63662306a36Sopenharmony_ci if (err) 63762306a36Sopenharmony_ci goto err_reg_write; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci kfree(reiv_pl); 64062306a36Sopenharmony_ci return 0; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cierr_reg_write: 64362306a36Sopenharmony_ci kfree(reiv_pl); 64462306a36Sopenharmony_ci return err; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic int mlxsw_sp_fid_erif_eport_to_vid_map(struct mlxsw_sp_fid *fid, 64862306a36Sopenharmony_ci u16 rif_index, bool valid) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 65162306a36Sopenharmony_ci u8 num_port_pages; 65262306a36Sopenharmony_ci int err, i; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci num_port_pages = mlxsw_core_max_ports(mlxsw_sp->core) / 65562306a36Sopenharmony_ci MLXSW_REG_REIV_REC_MAX_COUNT + 1; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci for (i = 0; i < num_port_pages; i++) { 65862306a36Sopenharmony_ci err = mlxsw_sp_fid_reiv_handle(fid, rif_index, valid, i); 65962306a36Sopenharmony_ci if (err) 66062306a36Sopenharmony_ci goto err_reiv_handle; 66162306a36Sopenharmony_ci } 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci return 0; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cierr_reiv_handle: 66662306a36Sopenharmony_ci for (; i >= 0; i--) 66762306a36Sopenharmony_ci mlxsw_sp_fid_reiv_handle(fid, rif_index, !valid, i); 66862306a36Sopenharmony_ci return err; 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ciint mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci u16 rif_index = mlxsw_sp_rif_index(rif); 67462306a36Sopenharmony_ci int err; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci err = mlxsw_sp_fid_to_fid_rif_update(fid, rif); 67762306a36Sopenharmony_ci if (err) 67862306a36Sopenharmony_ci return err; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci err = mlxsw_sp_fid_vni_to_fid_rif_update(fid, rif); 68162306a36Sopenharmony_ci if (err) 68262306a36Sopenharmony_ci goto err_vni_to_fid_rif_update; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci err = mlxsw_sp_fid_vid_to_fid_rif_set(fid, rif); 68562306a36Sopenharmony_ci if (err) 68662306a36Sopenharmony_ci goto err_vid_to_fid_rif_set; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci err = mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, true); 68962306a36Sopenharmony_ci if (err) 69062306a36Sopenharmony_ci goto err_erif_eport_to_vid_map; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci fid->rif = rif; 69362306a36Sopenharmony_ci return 0; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cierr_erif_eport_to_vid_map: 69662306a36Sopenharmony_ci mlxsw_sp_fid_vid_to_fid_rif_unset(fid); 69762306a36Sopenharmony_cierr_vid_to_fid_rif_set: 69862306a36Sopenharmony_ci mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL); 69962306a36Sopenharmony_cierr_vni_to_fid_rif_update: 70062306a36Sopenharmony_ci mlxsw_sp_fid_to_fid_rif_update(fid, NULL); 70162306a36Sopenharmony_ci return err; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_civoid mlxsw_sp_fid_rif_unset(struct mlxsw_sp_fid *fid) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci u16 rif_index; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci if (!fid->rif) 70962306a36Sopenharmony_ci return; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci rif_index = mlxsw_sp_rif_index(fid->rif); 71262306a36Sopenharmony_ci fid->rif = NULL; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci mlxsw_sp_fid_erif_eport_to_vid_map(fid, rif_index, false); 71562306a36Sopenharmony_ci mlxsw_sp_fid_vid_to_fid_rif_unset(fid); 71662306a36Sopenharmony_ci mlxsw_sp_fid_vni_to_fid_rif_update(fid, NULL); 71762306a36Sopenharmony_ci mlxsw_sp_fid_to_fid_rif_update(fid, NULL); 71862306a36Sopenharmony_ci} 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic int mlxsw_sp_fid_vni_op(const struct mlxsw_sp_fid *fid) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci int err; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci err = mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, fid->vni_valid); 72562306a36Sopenharmony_ci if (err) 72662306a36Sopenharmony_ci return err; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci err = mlxsw_sp_fid_edit_op(fid, fid->rif); 72962306a36Sopenharmony_ci if (err) 73062306a36Sopenharmony_ci goto err_fid_edit_op; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci return 0; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cierr_fid_edit_op: 73562306a36Sopenharmony_ci mlxsw_sp_fid_vni_to_fid_map(fid, fid->rif, !fid->vni_valid); 73662306a36Sopenharmony_ci return err; 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic int __mlxsw_sp_fid_port_vid_map(const struct mlxsw_sp_fid *fid, 74062306a36Sopenharmony_ci u16 local_port, u16 vid, bool valid) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 74362306a36Sopenharmony_ci char svfa_pl[MLXSW_REG_SVFA_LEN]; 74462306a36Sopenharmony_ci bool irif_valid = false; 74562306a36Sopenharmony_ci u16 irif_index = 0; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (fid->rif) { 74862306a36Sopenharmony_ci irif_valid = true; 74962306a36Sopenharmony_ci irif_index = mlxsw_sp_rif_index(fid->rif); 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci mlxsw_reg_svfa_port_vid_pack(svfa_pl, local_port, valid, fid->fid_index, 75362306a36Sopenharmony_ci vid, irif_valid, irif_index); 75462306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic struct mlxsw_sp_fid_8021d * 75862306a36Sopenharmony_cimlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci return container_of(fid, struct mlxsw_sp_fid_8021d, common); 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_cistatic void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci int br_ifindex = *(int *) arg; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex; 76862306a36Sopenharmony_ci fid->fid_offset = fid->fid_index - fid->fid_family->start_index; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid) 77262306a36Sopenharmony_ci{ 77362306a36Sopenharmony_ci return mlxsw_sp_fid_op(fid, true); 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci if (fid->vni_valid) 77962306a36Sopenharmony_ci mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid); 78062306a36Sopenharmony_ci mlxsw_sp_fid_op(fid, false); 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid, 78462306a36Sopenharmony_ci const void *arg, u16 *p_fid_index) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 78762306a36Sopenharmony_ci u16 nr_fids, fid_index; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci nr_fids = fid_family->end_index - fid_family->start_index + 1; 79062306a36Sopenharmony_ci fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids); 79162306a36Sopenharmony_ci if (fid_index == nr_fids) 79262306a36Sopenharmony_ci return -ENOBUFS; 79362306a36Sopenharmony_ci *p_fid_index = fid_family->start_index + fid_index; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci return 0; 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic bool 79962306a36Sopenharmony_cimlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci int br_ifindex = *(int *) arg; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_cistatic int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 80962306a36Sopenharmony_ci int err; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, 81262306a36Sopenharmony_ci list) { 81362306a36Sopenharmony_ci struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; 81462306a36Sopenharmony_ci u16 vid = mlxsw_sp_port_vlan->vid; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (!fid) 81762306a36Sopenharmony_ci continue; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci err = __mlxsw_sp_fid_port_vid_map(fid, 82062306a36Sopenharmony_ci mlxsw_sp_port->local_port, 82162306a36Sopenharmony_ci vid, true); 82262306a36Sopenharmony_ci if (err) 82362306a36Sopenharmony_ci goto err_fid_port_vid_map; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); 82762306a36Sopenharmony_ci if (err) 82862306a36Sopenharmony_ci goto err_port_vp_mode_set; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci return 0; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cierr_port_vp_mode_set: 83362306a36Sopenharmony_cierr_fid_port_vid_map: 83462306a36Sopenharmony_ci list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan, 83562306a36Sopenharmony_ci &mlxsw_sp_port->vlans_list, list) { 83662306a36Sopenharmony_ci struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; 83762306a36Sopenharmony_ci u16 vid = mlxsw_sp_port_vlan->vid; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (!fid) 84062306a36Sopenharmony_ci continue; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, 84362306a36Sopenharmony_ci false); 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci return err; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) 84962306a36Sopenharmony_ci{ 85062306a36Sopenharmony_ci struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci list_for_each_entry_reverse(mlxsw_sp_port_vlan, 85562306a36Sopenharmony_ci &mlxsw_sp_port->vlans_list, list) { 85662306a36Sopenharmony_ci struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; 85762306a36Sopenharmony_ci u16 vid = mlxsw_sp_port_vlan->vid; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (!fid) 86062306a36Sopenharmony_ci continue; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, 86362306a36Sopenharmony_ci false); 86462306a36Sopenharmony_ci } 86562306a36Sopenharmony_ci} 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_cistatic int 86862306a36Sopenharmony_cimlxsw_sp_fid_port_vid_list_add(struct mlxsw_sp_fid *fid, u16 local_port, 86962306a36Sopenharmony_ci u16 vid) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci struct mlxsw_sp_fid_port_vid *port_vid, *tmp_port_vid; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci port_vid = kzalloc(sizeof(*port_vid), GFP_KERNEL); 87462306a36Sopenharmony_ci if (!port_vid) 87562306a36Sopenharmony_ci return -ENOMEM; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci port_vid->local_port = local_port; 87862306a36Sopenharmony_ci port_vid->vid = vid; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci list_for_each_entry(tmp_port_vid, &fid->port_vid_list, list) { 88162306a36Sopenharmony_ci if (tmp_port_vid->local_port > local_port) 88262306a36Sopenharmony_ci break; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci list_add_tail(&port_vid->list, &tmp_port_vid->list); 88662306a36Sopenharmony_ci return 0; 88762306a36Sopenharmony_ci} 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_cistatic void 89062306a36Sopenharmony_cimlxsw_sp_fid_port_vid_list_del(struct mlxsw_sp_fid *fid, u16 local_port, 89162306a36Sopenharmony_ci u16 vid) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci struct mlxsw_sp_fid_port_vid *port_vid, *tmp; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci list_for_each_entry_safe(port_vid, tmp, &fid->port_vid_list, list) { 89662306a36Sopenharmony_ci if (port_vid->local_port != local_port || port_vid->vid != vid) 89762306a36Sopenharmony_ci continue; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci list_del(&port_vid->list); 90062306a36Sopenharmony_ci kfree(port_vid); 90162306a36Sopenharmony_ci return; 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_cistatic int 90662306a36Sopenharmony_cimlxsw_sp_fid_mpe_table_map(const struct mlxsw_sp_fid *fid, u16 local_port, 90762306a36Sopenharmony_ci u16 vid, bool valid) 90862306a36Sopenharmony_ci{ 90962306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 91062306a36Sopenharmony_ci char smpe_pl[MLXSW_REG_SMPE_LEN]; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci mlxsw_reg_smpe_pack(smpe_pl, local_port, fid->fid_index, 91362306a36Sopenharmony_ci valid ? vid : 0); 91462306a36Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(smpe), smpe_pl); 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cistatic int 91862306a36Sopenharmony_cimlxsw_sp_fid_erif_eport_to_vid_map_one(const struct mlxsw_sp_fid *fid, 91962306a36Sopenharmony_ci u16 local_port, u16 vid, bool valid) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci u8 port_page = local_port / MLXSW_REG_REIV_REC_MAX_COUNT; 92262306a36Sopenharmony_ci u8 rec_num = local_port % MLXSW_REG_REIV_REC_MAX_COUNT; 92362306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 92462306a36Sopenharmony_ci u16 rif_index = mlxsw_sp_rif_index(fid->rif); 92562306a36Sopenharmony_ci char *reiv_pl; 92662306a36Sopenharmony_ci int err; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci reiv_pl = kmalloc(MLXSW_REG_REIV_LEN, GFP_KERNEL); 92962306a36Sopenharmony_ci if (!reiv_pl) 93062306a36Sopenharmony_ci return -ENOMEM; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci mlxsw_reg_reiv_pack(reiv_pl, port_page, rif_index); 93362306a36Sopenharmony_ci mlxsw_reg_reiv_rec_update_set(reiv_pl, rec_num, true); 93462306a36Sopenharmony_ci mlxsw_reg_reiv_rec_evid_set(reiv_pl, rec_num, valid ? vid : 0); 93562306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(reiv), reiv_pl); 93662306a36Sopenharmony_ci kfree(reiv_pl); 93762306a36Sopenharmony_ci return err; 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_cistatic int mlxsw_sp_fid_evid_map(const struct mlxsw_sp_fid *fid, u16 local_port, 94162306a36Sopenharmony_ci u16 vid, bool valid) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci int err; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci err = mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, valid); 94662306a36Sopenharmony_ci if (err) 94762306a36Sopenharmony_ci return err; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci if (!fid->rif) 95062306a36Sopenharmony_ci return 0; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid, 95362306a36Sopenharmony_ci valid); 95462306a36Sopenharmony_ci if (err) 95562306a36Sopenharmony_ci goto err_erif_eport_to_vid_map_one; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci return 0; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cierr_erif_eport_to_vid_map_one: 96062306a36Sopenharmony_ci mlxsw_sp_fid_mpe_table_map(fid, local_port, vid, !valid); 96162306a36Sopenharmony_ci return err; 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid, 96562306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, 96662306a36Sopenharmony_ci u16 vid) 96762306a36Sopenharmony_ci{ 96862306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 96962306a36Sopenharmony_ci u16 local_port = mlxsw_sp_port->local_port; 97062306a36Sopenharmony_ci int err; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, 97362306a36Sopenharmony_ci true); 97462306a36Sopenharmony_ci if (err) 97562306a36Sopenharmony_ci return err; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true); 97862306a36Sopenharmony_ci if (err) 97962306a36Sopenharmony_ci goto err_fid_evid_map; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port, 98262306a36Sopenharmony_ci vid); 98362306a36Sopenharmony_ci if (err) 98462306a36Sopenharmony_ci goto err_port_vid_list_add; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { 98762306a36Sopenharmony_ci err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); 98862306a36Sopenharmony_ci if (err) 98962306a36Sopenharmony_ci goto err_port_vp_mode_trans; 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci return 0; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_cierr_port_vp_mode_trans: 99562306a36Sopenharmony_ci mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 99662306a36Sopenharmony_ci mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid); 99762306a36Sopenharmony_cierr_port_vid_list_add: 99862306a36Sopenharmony_ci mlxsw_sp_fid_evid_map(fid, local_port, vid, false); 99962306a36Sopenharmony_cierr_fid_evid_map: 100062306a36Sopenharmony_ci __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false); 100162306a36Sopenharmony_ci return err; 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_cistatic void 100562306a36Sopenharmony_cimlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid, 100662306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 100762306a36Sopenharmony_ci{ 100862306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 100962306a36Sopenharmony_ci u16 local_port = mlxsw_sp_port->local_port; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) 101262306a36Sopenharmony_ci mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); 101362306a36Sopenharmony_ci mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 101462306a36Sopenharmony_ci mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid); 101562306a36Sopenharmony_ci mlxsw_sp_fid_evid_map(fid, local_port, vid, false); 101662306a36Sopenharmony_ci __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false); 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci return mlxsw_sp_fid_vni_op(fid); 102262306a36Sopenharmony_ci} 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_cistatic void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid) 102562306a36Sopenharmony_ci{ 102662306a36Sopenharmony_ci mlxsw_sp_fid_vni_op(fid); 102762306a36Sopenharmony_ci} 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci return mlxsw_sp_fid_edit_op(fid, fid->rif); 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_cistatic void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid) 103562306a36Sopenharmony_ci{ 103662306a36Sopenharmony_ci mlxsw_sp_fid_edit_op(fid, fid->rif); 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_cistatic void 104062306a36Sopenharmony_cimlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid, 104162306a36Sopenharmony_ci const struct net_device *nve_dev) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci br_fdb_clear_offload(nve_dev, 0); 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_cistatic int 104762306a36Sopenharmony_cimlxsw_sp_fid_8021d_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid, 104862306a36Sopenharmony_ci const struct mlxsw_sp_rif *rif) 104962306a36Sopenharmony_ci{ 105062306a36Sopenharmony_ci return 0; 105162306a36Sopenharmony_ci} 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { 105462306a36Sopenharmony_ci .setup = mlxsw_sp_fid_8021d_setup, 105562306a36Sopenharmony_ci .configure = mlxsw_sp_fid_8021d_configure, 105662306a36Sopenharmony_ci .deconfigure = mlxsw_sp_fid_8021d_deconfigure, 105762306a36Sopenharmony_ci .index_alloc = mlxsw_sp_fid_8021d_index_alloc, 105862306a36Sopenharmony_ci .compare = mlxsw_sp_fid_8021d_compare, 105962306a36Sopenharmony_ci .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, 106062306a36Sopenharmony_ci .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, 106162306a36Sopenharmony_ci .vni_set = mlxsw_sp_fid_8021d_vni_set, 106262306a36Sopenharmony_ci .vni_clear = mlxsw_sp_fid_8021d_vni_clear, 106362306a36Sopenharmony_ci .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set, 106462306a36Sopenharmony_ci .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, 106562306a36Sopenharmony_ci .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload, 106662306a36Sopenharmony_ci .vid_to_fid_rif_update = mlxsw_sp_fid_8021d_vid_to_fid_rif_update, 106762306a36Sopenharmony_ci}; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci#define MLXSW_SP_FID_8021Q_MAX (VLAN_N_VID - 2) 107062306a36Sopenharmony_ci#define MLXSW_SP_FID_RFID_MAX (11 * 1024) 107162306a36Sopenharmony_ci#define MLXSW_SP_FID_8021Q_PGT_BASE 0 107262306a36Sopenharmony_ci#define MLXSW_SP_FID_8021D_PGT_BASE (3 * MLXSW_SP_FID_8021Q_MAX) 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_cistatic const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { 107562306a36Sopenharmony_ci { 107662306a36Sopenharmony_ci .packet_type = MLXSW_SP_FLOOD_TYPE_UC, 107762306a36Sopenharmony_ci .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, 107862306a36Sopenharmony_ci .table_index = 0, 107962306a36Sopenharmony_ci }, 108062306a36Sopenharmony_ci { 108162306a36Sopenharmony_ci .packet_type = MLXSW_SP_FLOOD_TYPE_MC, 108262306a36Sopenharmony_ci .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, 108362306a36Sopenharmony_ci .table_index = 1, 108462306a36Sopenharmony_ci }, 108562306a36Sopenharmony_ci { 108662306a36Sopenharmony_ci .packet_type = MLXSW_SP_FLOOD_TYPE_BC, 108762306a36Sopenharmony_ci .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID_OFFSET, 108862306a36Sopenharmony_ci .table_index = 2, 108962306a36Sopenharmony_ci }, 109062306a36Sopenharmony_ci}; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_cistatic bool 109362306a36Sopenharmony_cimlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg) 109462306a36Sopenharmony_ci{ 109562306a36Sopenharmony_ci u16 vid = *(u16 *) arg; 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci return mlxsw_sp_fid_8021q_fid(fid)->vid == vid; 109862306a36Sopenharmony_ci} 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_cistatic void 110162306a36Sopenharmony_cimlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid, 110262306a36Sopenharmony_ci const struct net_device *nve_dev) 110362306a36Sopenharmony_ci{ 110462306a36Sopenharmony_ci br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid)); 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_cistatic void mlxsw_sp_fid_rfid_setup(struct mlxsw_sp_fid *fid, const void *arg) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci fid->fid_offset = 0; 111062306a36Sopenharmony_ci} 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_cistatic int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid) 111362306a36Sopenharmony_ci{ 111462306a36Sopenharmony_ci return mlxsw_sp_fid_op(fid, true); 111562306a36Sopenharmony_ci} 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cistatic void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid) 111862306a36Sopenharmony_ci{ 111962306a36Sopenharmony_ci mlxsw_sp_fid_op(fid, false); 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_cistatic int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid, 112362306a36Sopenharmony_ci const void *arg, u16 *p_fid_index) 112462306a36Sopenharmony_ci{ 112562306a36Sopenharmony_ci u16 rif_index = *(u16 *) arg; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci *p_fid_index = fid->fid_family->start_index + rif_index; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci return 0; 113062306a36Sopenharmony_ci} 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_cistatic bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid, 113362306a36Sopenharmony_ci const void *arg) 113462306a36Sopenharmony_ci{ 113562306a36Sopenharmony_ci u16 rif_index = *(u16 *) arg; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci return fid->fid_index == rif_index + fid->fid_family->start_index; 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_cistatic int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid, 114162306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, 114262306a36Sopenharmony_ci u16 vid) 114362306a36Sopenharmony_ci{ 114462306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 114562306a36Sopenharmony_ci u16 local_port = mlxsw_sp_port->local_port; 114662306a36Sopenharmony_ci int err; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port, 114962306a36Sopenharmony_ci vid); 115062306a36Sopenharmony_ci if (err) 115162306a36Sopenharmony_ci return err; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci /* Using legacy bridge model, we only need to transition the port to 115462306a36Sopenharmony_ci * virtual mode since {Port, VID} => FID is done by the firmware upon 115562306a36Sopenharmony_ci * RIF creation. Using unified bridge model, we need to map 115662306a36Sopenharmony_ci * {Port, VID} => FID and map egress VID. 115762306a36Sopenharmony_ci */ 115862306a36Sopenharmony_ci err = __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, 115962306a36Sopenharmony_ci true); 116062306a36Sopenharmony_ci if (err) 116162306a36Sopenharmony_ci goto err_port_vid_map; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci if (fid->rif) { 116462306a36Sopenharmony_ci err = mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, 116562306a36Sopenharmony_ci vid, true); 116662306a36Sopenharmony_ci if (err) 116762306a36Sopenharmony_ci goto err_erif_eport_to_vid_map_one; 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { 117162306a36Sopenharmony_ci err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); 117262306a36Sopenharmony_ci if (err) 117362306a36Sopenharmony_ci goto err_port_vp_mode_trans; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci return 0; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_cierr_port_vp_mode_trans: 117962306a36Sopenharmony_ci mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 118062306a36Sopenharmony_ci if (fid->rif) 118162306a36Sopenharmony_ci mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid, 118262306a36Sopenharmony_ci false); 118362306a36Sopenharmony_cierr_erif_eport_to_vid_map_one: 118462306a36Sopenharmony_ci __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false); 118562306a36Sopenharmony_cierr_port_vid_map: 118662306a36Sopenharmony_ci mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid); 118762306a36Sopenharmony_ci return err; 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_cistatic void 119162306a36Sopenharmony_cimlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid, 119262306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 119362306a36Sopenharmony_ci{ 119462306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 119562306a36Sopenharmony_ci u16 local_port = mlxsw_sp_port->local_port; 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) 119862306a36Sopenharmony_ci mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); 119962306a36Sopenharmony_ci mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (fid->rif) 120262306a36Sopenharmony_ci mlxsw_sp_fid_erif_eport_to_vid_map_one(fid, local_port, vid, 120362306a36Sopenharmony_ci false); 120462306a36Sopenharmony_ci __mlxsw_sp_fid_port_vid_map(fid, mlxsw_sp_port->local_port, vid, false); 120562306a36Sopenharmony_ci mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid); 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cistatic int mlxsw_sp_fid_rfid_vni_set(struct mlxsw_sp_fid *fid) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci return -EOPNOTSUPP; 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_cistatic void mlxsw_sp_fid_rfid_vni_clear(struct mlxsw_sp_fid *fid) 121462306a36Sopenharmony_ci{ 121562306a36Sopenharmony_ci WARN_ON_ONCE(1); 121662306a36Sopenharmony_ci} 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_cistatic int mlxsw_sp_fid_rfid_nve_flood_index_set(struct mlxsw_sp_fid *fid) 121962306a36Sopenharmony_ci{ 122062306a36Sopenharmony_ci return -EOPNOTSUPP; 122162306a36Sopenharmony_ci} 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_cistatic void mlxsw_sp_fid_rfid_nve_flood_index_clear(struct mlxsw_sp_fid *fid) 122462306a36Sopenharmony_ci{ 122562306a36Sopenharmony_ci WARN_ON_ONCE(1); 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic int 122962306a36Sopenharmony_cimlxsw_sp_fid_rfid_vid_to_fid_rif_update(const struct mlxsw_sp_fid *fid, 123062306a36Sopenharmony_ci const struct mlxsw_sp_rif *rif) 123162306a36Sopenharmony_ci{ 123262306a36Sopenharmony_ci return 0; 123362306a36Sopenharmony_ci} 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = { 123662306a36Sopenharmony_ci .setup = mlxsw_sp_fid_rfid_setup, 123762306a36Sopenharmony_ci .configure = mlxsw_sp_fid_rfid_configure, 123862306a36Sopenharmony_ci .deconfigure = mlxsw_sp_fid_rfid_deconfigure, 123962306a36Sopenharmony_ci .index_alloc = mlxsw_sp_fid_rfid_index_alloc, 124062306a36Sopenharmony_ci .compare = mlxsw_sp_fid_rfid_compare, 124162306a36Sopenharmony_ci .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map, 124262306a36Sopenharmony_ci .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap, 124362306a36Sopenharmony_ci .vni_set = mlxsw_sp_fid_rfid_vni_set, 124462306a36Sopenharmony_ci .vni_clear = mlxsw_sp_fid_rfid_vni_clear, 124562306a36Sopenharmony_ci .nve_flood_index_set = mlxsw_sp_fid_rfid_nve_flood_index_set, 124662306a36Sopenharmony_ci .nve_flood_index_clear = mlxsw_sp_fid_rfid_nve_flood_index_clear, 124762306a36Sopenharmony_ci .vid_to_fid_rif_update = mlxsw_sp_fid_rfid_vid_to_fid_rif_update, 124862306a36Sopenharmony_ci}; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_cistatic void mlxsw_sp_fid_dummy_setup(struct mlxsw_sp_fid *fid, const void *arg) 125162306a36Sopenharmony_ci{ 125262306a36Sopenharmony_ci fid->fid_offset = 0; 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_cistatic int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid) 125662306a36Sopenharmony_ci{ 125762306a36Sopenharmony_ci return mlxsw_sp_fid_op(fid, true); 125862306a36Sopenharmony_ci} 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_cistatic void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid) 126162306a36Sopenharmony_ci{ 126262306a36Sopenharmony_ci mlxsw_sp_fid_op(fid, false); 126362306a36Sopenharmony_ci} 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_cistatic int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid, 126662306a36Sopenharmony_ci const void *arg, u16 *p_fid_index) 126762306a36Sopenharmony_ci{ 126862306a36Sopenharmony_ci *p_fid_index = fid->fid_family->start_index; 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci return 0; 127162306a36Sopenharmony_ci} 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_cistatic bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid, 127462306a36Sopenharmony_ci const void *arg) 127562306a36Sopenharmony_ci{ 127662306a36Sopenharmony_ci return true; 127762306a36Sopenharmony_ci} 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_cistatic int mlxsw_sp_fid_dummy_vni_set(struct mlxsw_sp_fid *fid) 128062306a36Sopenharmony_ci{ 128162306a36Sopenharmony_ci return -EOPNOTSUPP; 128262306a36Sopenharmony_ci} 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_cistatic void mlxsw_sp_fid_dummy_vni_clear(struct mlxsw_sp_fid *fid) 128562306a36Sopenharmony_ci{ 128662306a36Sopenharmony_ci WARN_ON_ONCE(1); 128762306a36Sopenharmony_ci} 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_cistatic int mlxsw_sp_fid_dummy_nve_flood_index_set(struct mlxsw_sp_fid *fid) 129062306a36Sopenharmony_ci{ 129162306a36Sopenharmony_ci return -EOPNOTSUPP; 129262306a36Sopenharmony_ci} 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_cistatic void mlxsw_sp_fid_dummy_nve_flood_index_clear(struct mlxsw_sp_fid *fid) 129562306a36Sopenharmony_ci{ 129662306a36Sopenharmony_ci WARN_ON_ONCE(1); 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = { 130062306a36Sopenharmony_ci .setup = mlxsw_sp_fid_dummy_setup, 130162306a36Sopenharmony_ci .configure = mlxsw_sp_fid_dummy_configure, 130262306a36Sopenharmony_ci .deconfigure = mlxsw_sp_fid_dummy_deconfigure, 130362306a36Sopenharmony_ci .index_alloc = mlxsw_sp_fid_dummy_index_alloc, 130462306a36Sopenharmony_ci .compare = mlxsw_sp_fid_dummy_compare, 130562306a36Sopenharmony_ci .vni_set = mlxsw_sp_fid_dummy_vni_set, 130662306a36Sopenharmony_ci .vni_clear = mlxsw_sp_fid_dummy_vni_clear, 130762306a36Sopenharmony_ci .nve_flood_index_set = mlxsw_sp_fid_dummy_nve_flood_index_set, 130862306a36Sopenharmony_ci .nve_flood_index_clear = mlxsw_sp_fid_dummy_nve_flood_index_clear, 130962306a36Sopenharmony_ci}; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021q_configure(struct mlxsw_sp_fid *fid) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid); 131462306a36Sopenharmony_ci int err; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci err = mlxsw_sp_fid_op(fid, true); 131762306a36Sopenharmony_ci if (err) 131862306a36Sopenharmony_ci return err; 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci err = mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, true, fid->rif); 132162306a36Sopenharmony_ci if (err) 132262306a36Sopenharmony_ci goto err_vid_to_fid_map; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci return 0; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_cierr_vid_to_fid_map: 132762306a36Sopenharmony_ci mlxsw_sp_fid_op(fid, false); 132862306a36Sopenharmony_ci return err; 132962306a36Sopenharmony_ci} 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_cistatic void mlxsw_sp_fid_8021q_deconfigure(struct mlxsw_sp_fid *fid) 133262306a36Sopenharmony_ci{ 133362306a36Sopenharmony_ci struct mlxsw_sp_fid_8021q *fid_8021q = mlxsw_sp_fid_8021q_fid(fid); 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci if (fid->vni_valid) 133662306a36Sopenharmony_ci mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci mlxsw_sp_fid_vid_to_fid_map(fid, fid_8021q->vid, false, NULL); 133962306a36Sopenharmony_ci mlxsw_sp_fid_op(fid, false); 134062306a36Sopenharmony_ci} 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_cistatic int mlxsw_sp_fid_8021q_port_vid_map(struct mlxsw_sp_fid *fid, 134362306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, 134462306a36Sopenharmony_ci u16 vid) 134562306a36Sopenharmony_ci{ 134662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 134762306a36Sopenharmony_ci u16 local_port = mlxsw_sp_port->local_port; 134862306a36Sopenharmony_ci int err; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci /* In case there are no {Port, VID} => FID mappings on the port, 135162306a36Sopenharmony_ci * we can use the global VID => FID mapping we created when the 135262306a36Sopenharmony_ci * FID was configured, otherwise, configure new mapping. 135362306a36Sopenharmony_ci */ 135462306a36Sopenharmony_ci if (mlxsw_sp->fid_core->port_fid_mappings[local_port]) { 135562306a36Sopenharmony_ci err = __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, true); 135662306a36Sopenharmony_ci if (err) 135762306a36Sopenharmony_ci return err; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci err = mlxsw_sp_fid_evid_map(fid, local_port, vid, true); 136162306a36Sopenharmony_ci if (err) 136262306a36Sopenharmony_ci goto err_fid_evid_map; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci err = mlxsw_sp_fid_port_vid_list_add(fid, mlxsw_sp_port->local_port, 136562306a36Sopenharmony_ci vid); 136662306a36Sopenharmony_ci if (err) 136762306a36Sopenharmony_ci goto err_port_vid_list_add; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci return 0; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_cierr_port_vid_list_add: 137262306a36Sopenharmony_ci mlxsw_sp_fid_evid_map(fid, local_port, vid, false); 137362306a36Sopenharmony_cierr_fid_evid_map: 137462306a36Sopenharmony_ci if (mlxsw_sp->fid_core->port_fid_mappings[local_port]) 137562306a36Sopenharmony_ci __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false); 137662306a36Sopenharmony_ci return err; 137762306a36Sopenharmony_ci} 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_cistatic void 138062306a36Sopenharmony_cimlxsw_sp_fid_8021q_port_vid_unmap(struct mlxsw_sp_fid *fid, 138162306a36Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 138262306a36Sopenharmony_ci{ 138362306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 138462306a36Sopenharmony_ci u16 local_port = mlxsw_sp_port->local_port; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci mlxsw_sp_fid_port_vid_list_del(fid, mlxsw_sp_port->local_port, vid); 138762306a36Sopenharmony_ci mlxsw_sp_fid_evid_map(fid, local_port, vid, false); 138862306a36Sopenharmony_ci if (mlxsw_sp->fid_core->port_fid_mappings[local_port]) 138962306a36Sopenharmony_ci __mlxsw_sp_fid_port_vid_map(fid, local_port, vid, false); 139062306a36Sopenharmony_ci} 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_ops = { 139362306a36Sopenharmony_ci .setup = mlxsw_sp_fid_8021q_setup, 139462306a36Sopenharmony_ci .configure = mlxsw_sp_fid_8021q_configure, 139562306a36Sopenharmony_ci .deconfigure = mlxsw_sp_fid_8021q_deconfigure, 139662306a36Sopenharmony_ci .index_alloc = mlxsw_sp_fid_8021d_index_alloc, 139762306a36Sopenharmony_ci .compare = mlxsw_sp_fid_8021q_compare, 139862306a36Sopenharmony_ci .port_vid_map = mlxsw_sp_fid_8021q_port_vid_map, 139962306a36Sopenharmony_ci .port_vid_unmap = mlxsw_sp_fid_8021q_port_vid_unmap, 140062306a36Sopenharmony_ci .vni_set = mlxsw_sp_fid_8021d_vni_set, 140162306a36Sopenharmony_ci .vni_clear = mlxsw_sp_fid_8021d_vni_clear, 140262306a36Sopenharmony_ci .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set, 140362306a36Sopenharmony_ci .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, 140462306a36Sopenharmony_ci .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload, 140562306a36Sopenharmony_ci .vid_to_fid_rif_update = mlxsw_sp_fid_8021q_vid_to_fid_rif_update, 140662306a36Sopenharmony_ci}; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci/* There are 4K-2 802.1Q FIDs */ 140962306a36Sopenharmony_ci#define MLXSW_SP_FID_8021Q_START 1 /* FID 0 is reserved. */ 141062306a36Sopenharmony_ci#define MLXSW_SP_FID_8021Q_END (MLXSW_SP_FID_8021Q_START + \ 141162306a36Sopenharmony_ci MLXSW_SP_FID_8021Q_MAX - 1) 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci/* There are 1K 802.1D FIDs */ 141462306a36Sopenharmony_ci#define MLXSW_SP_FID_8021D_START (MLXSW_SP_FID_8021Q_END + 1) 141562306a36Sopenharmony_ci#define MLXSW_SP_FID_8021D_END (MLXSW_SP_FID_8021D_START + \ 141662306a36Sopenharmony_ci MLXSW_SP_FID_8021D_MAX - 1) 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci/* There is one dummy FID */ 141962306a36Sopenharmony_ci#define MLXSW_SP_FID_DUMMY (MLXSW_SP_FID_8021D_END + 1) 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci/* There are 11K rFIDs */ 142262306a36Sopenharmony_ci#define MLXSW_SP_RFID_START (MLXSW_SP_FID_DUMMY + 1) 142362306a36Sopenharmony_ci#define MLXSW_SP_RFID_END (MLXSW_SP_RFID_START + \ 142462306a36Sopenharmony_ci MLXSW_SP_FID_RFID_MAX - 1) 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021q_family = { 142762306a36Sopenharmony_ci .type = MLXSW_SP_FID_TYPE_8021Q, 142862306a36Sopenharmony_ci .fid_size = sizeof(struct mlxsw_sp_fid_8021q), 142962306a36Sopenharmony_ci .start_index = MLXSW_SP_FID_8021Q_START, 143062306a36Sopenharmony_ci .end_index = MLXSW_SP_FID_8021Q_END, 143162306a36Sopenharmony_ci .flood_tables = mlxsw_sp_fid_8021d_flood_tables, 143262306a36Sopenharmony_ci .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), 143362306a36Sopenharmony_ci .rif_type = MLXSW_SP_RIF_TYPE_VLAN, 143462306a36Sopenharmony_ci .ops = &mlxsw_sp_fid_8021q_ops, 143562306a36Sopenharmony_ci .flood_rsp = false, 143662306a36Sopenharmony_ci .bridge_type = MLXSW_REG_BRIDGE_TYPE_0, 143762306a36Sopenharmony_ci .pgt_base = MLXSW_SP_FID_8021Q_PGT_BASE, 143862306a36Sopenharmony_ci .smpe_index_valid = false, 143962306a36Sopenharmony_ci}; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp1_fid_8021d_family = { 144262306a36Sopenharmony_ci .type = MLXSW_SP_FID_TYPE_8021D, 144362306a36Sopenharmony_ci .fid_size = sizeof(struct mlxsw_sp_fid_8021d), 144462306a36Sopenharmony_ci .start_index = MLXSW_SP_FID_8021D_START, 144562306a36Sopenharmony_ci .end_index = MLXSW_SP_FID_8021D_END, 144662306a36Sopenharmony_ci .flood_tables = mlxsw_sp_fid_8021d_flood_tables, 144762306a36Sopenharmony_ci .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), 144862306a36Sopenharmony_ci .rif_type = MLXSW_SP_RIF_TYPE_FID, 144962306a36Sopenharmony_ci .ops = &mlxsw_sp_fid_8021d_ops, 145062306a36Sopenharmony_ci .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, 145162306a36Sopenharmony_ci .pgt_base = MLXSW_SP_FID_8021D_PGT_BASE, 145262306a36Sopenharmony_ci .smpe_index_valid = false, 145362306a36Sopenharmony_ci}; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp1_fid_dummy_family = { 145662306a36Sopenharmony_ci .type = MLXSW_SP_FID_TYPE_DUMMY, 145762306a36Sopenharmony_ci .fid_size = sizeof(struct mlxsw_sp_fid), 145862306a36Sopenharmony_ci .start_index = MLXSW_SP_FID_DUMMY, 145962306a36Sopenharmony_ci .end_index = MLXSW_SP_FID_DUMMY, 146062306a36Sopenharmony_ci .ops = &mlxsw_sp_fid_dummy_ops, 146162306a36Sopenharmony_ci .smpe_index_valid = false, 146262306a36Sopenharmony_ci}; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = { 146562306a36Sopenharmony_ci .type = MLXSW_SP_FID_TYPE_RFID, 146662306a36Sopenharmony_ci .fid_size = sizeof(struct mlxsw_sp_fid), 146762306a36Sopenharmony_ci .start_index = MLXSW_SP_RFID_START, 146862306a36Sopenharmony_ci .end_index = MLXSW_SP_RFID_END, 146962306a36Sopenharmony_ci .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT, 147062306a36Sopenharmony_ci .ops = &mlxsw_sp_fid_rfid_ops, 147162306a36Sopenharmony_ci .flood_rsp = true, 147262306a36Sopenharmony_ci .smpe_index_valid = false, 147362306a36Sopenharmony_ci}; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ciconst struct mlxsw_sp_fid_family *mlxsw_sp1_fid_family_arr[] = { 147662306a36Sopenharmony_ci [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp1_fid_8021q_family, 147762306a36Sopenharmony_ci [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp1_fid_8021d_family, 147862306a36Sopenharmony_ci [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp1_fid_dummy_family, 147962306a36Sopenharmony_ci [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family, 148062306a36Sopenharmony_ci}; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021q_family = { 148362306a36Sopenharmony_ci .type = MLXSW_SP_FID_TYPE_8021Q, 148462306a36Sopenharmony_ci .fid_size = sizeof(struct mlxsw_sp_fid_8021q), 148562306a36Sopenharmony_ci .start_index = MLXSW_SP_FID_8021Q_START, 148662306a36Sopenharmony_ci .end_index = MLXSW_SP_FID_8021Q_END, 148762306a36Sopenharmony_ci .flood_tables = mlxsw_sp_fid_8021d_flood_tables, 148862306a36Sopenharmony_ci .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), 148962306a36Sopenharmony_ci .rif_type = MLXSW_SP_RIF_TYPE_VLAN, 149062306a36Sopenharmony_ci .ops = &mlxsw_sp_fid_8021q_ops, 149162306a36Sopenharmony_ci .flood_rsp = false, 149262306a36Sopenharmony_ci .bridge_type = MLXSW_REG_BRIDGE_TYPE_0, 149362306a36Sopenharmony_ci .pgt_base = MLXSW_SP_FID_8021Q_PGT_BASE, 149462306a36Sopenharmony_ci .smpe_index_valid = true, 149562306a36Sopenharmony_ci}; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp2_fid_8021d_family = { 149862306a36Sopenharmony_ci .type = MLXSW_SP_FID_TYPE_8021D, 149962306a36Sopenharmony_ci .fid_size = sizeof(struct mlxsw_sp_fid_8021d), 150062306a36Sopenharmony_ci .start_index = MLXSW_SP_FID_8021D_START, 150162306a36Sopenharmony_ci .end_index = MLXSW_SP_FID_8021D_END, 150262306a36Sopenharmony_ci .flood_tables = mlxsw_sp_fid_8021d_flood_tables, 150362306a36Sopenharmony_ci .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), 150462306a36Sopenharmony_ci .rif_type = MLXSW_SP_RIF_TYPE_FID, 150562306a36Sopenharmony_ci .ops = &mlxsw_sp_fid_8021d_ops, 150662306a36Sopenharmony_ci .bridge_type = MLXSW_REG_BRIDGE_TYPE_1, 150762306a36Sopenharmony_ci .pgt_base = MLXSW_SP_FID_8021D_PGT_BASE, 150862306a36Sopenharmony_ci .smpe_index_valid = true, 150962306a36Sopenharmony_ci}; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp2_fid_dummy_family = { 151262306a36Sopenharmony_ci .type = MLXSW_SP_FID_TYPE_DUMMY, 151362306a36Sopenharmony_ci .fid_size = sizeof(struct mlxsw_sp_fid), 151462306a36Sopenharmony_ci .start_index = MLXSW_SP_FID_DUMMY, 151562306a36Sopenharmony_ci .end_index = MLXSW_SP_FID_DUMMY, 151662306a36Sopenharmony_ci .ops = &mlxsw_sp_fid_dummy_ops, 151762306a36Sopenharmony_ci .smpe_index_valid = false, 151862306a36Sopenharmony_ci}; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ciconst struct mlxsw_sp_fid_family *mlxsw_sp2_fid_family_arr[] = { 152162306a36Sopenharmony_ci [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp2_fid_8021q_family, 152262306a36Sopenharmony_ci [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp2_fid_8021d_family, 152362306a36Sopenharmony_ci [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp2_fid_dummy_family, 152462306a36Sopenharmony_ci [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family, 152562306a36Sopenharmony_ci}; 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_cistatic struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp, 152862306a36Sopenharmony_ci enum mlxsw_sp_fid_type type, 152962306a36Sopenharmony_ci const void *arg) 153062306a36Sopenharmony_ci{ 153162306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family; 153262306a36Sopenharmony_ci struct mlxsw_sp_fid *fid; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; 153562306a36Sopenharmony_ci list_for_each_entry(fid, &fid_family->fids_list, list) { 153662306a36Sopenharmony_ci if (!fid->fid_family->ops->compare(fid, arg)) 153762306a36Sopenharmony_ci continue; 153862306a36Sopenharmony_ci refcount_inc(&fid->ref_count); 153962306a36Sopenharmony_ci return fid; 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci return NULL; 154362306a36Sopenharmony_ci} 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_cistatic struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, 154662306a36Sopenharmony_ci enum mlxsw_sp_fid_type type, 154762306a36Sopenharmony_ci const void *arg) 154862306a36Sopenharmony_ci{ 154962306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family; 155062306a36Sopenharmony_ci struct mlxsw_sp_fid *fid; 155162306a36Sopenharmony_ci u16 fid_index; 155262306a36Sopenharmony_ci int err; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg); 155562306a36Sopenharmony_ci if (fid) 155662306a36Sopenharmony_ci return fid; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; 155962306a36Sopenharmony_ci fid = kzalloc(fid_family->fid_size, GFP_KERNEL); 156062306a36Sopenharmony_ci if (!fid) 156162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci INIT_LIST_HEAD(&fid->port_vid_list); 156462306a36Sopenharmony_ci fid->fid_family = fid_family; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index); 156762306a36Sopenharmony_ci if (err) 156862306a36Sopenharmony_ci goto err_index_alloc; 156962306a36Sopenharmony_ci fid->fid_index = fid_index; 157062306a36Sopenharmony_ci __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci fid->fid_family->ops->setup(fid, arg); 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci err = fid->fid_family->ops->configure(fid); 157562306a36Sopenharmony_ci if (err) 157662306a36Sopenharmony_ci goto err_configure; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node, 157962306a36Sopenharmony_ci mlxsw_sp_fid_ht_params); 158062306a36Sopenharmony_ci if (err) 158162306a36Sopenharmony_ci goto err_rhashtable_insert; 158262306a36Sopenharmony_ci 158362306a36Sopenharmony_ci list_add(&fid->list, &fid_family->fids_list); 158462306a36Sopenharmony_ci refcount_set(&fid->ref_count, 1); 158562306a36Sopenharmony_ci return fid; 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_cierr_rhashtable_insert: 158862306a36Sopenharmony_ci fid->fid_family->ops->deconfigure(fid); 158962306a36Sopenharmony_cierr_configure: 159062306a36Sopenharmony_ci __clear_bit(fid_index - fid_family->start_index, 159162306a36Sopenharmony_ci fid_family->fids_bitmap); 159262306a36Sopenharmony_cierr_index_alloc: 159362306a36Sopenharmony_ci kfree(fid); 159462306a36Sopenharmony_ci return ERR_PTR(err); 159562306a36Sopenharmony_ci} 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_civoid mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid) 159862306a36Sopenharmony_ci{ 159962306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 160062306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci if (!refcount_dec_and_test(&fid->ref_count)) 160362306a36Sopenharmony_ci return; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci list_del(&fid->list); 160662306a36Sopenharmony_ci rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht, 160762306a36Sopenharmony_ci &fid->ht_node, mlxsw_sp_fid_ht_params); 160862306a36Sopenharmony_ci fid->fid_family->ops->deconfigure(fid); 160962306a36Sopenharmony_ci __clear_bit(fid->fid_index - fid_family->start_index, 161062306a36Sopenharmony_ci fid_family->fids_bitmap); 161162306a36Sopenharmony_ci WARN_ON_ONCE(!list_empty(&fid->port_vid_list)); 161262306a36Sopenharmony_ci kfree(fid); 161362306a36Sopenharmony_ci} 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid) 161662306a36Sopenharmony_ci{ 161762306a36Sopenharmony_ci return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid); 161862306a36Sopenharmony_ci} 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, 162162306a36Sopenharmony_ci int br_ifindex) 162262306a36Sopenharmony_ci{ 162362306a36Sopenharmony_ci return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex); 162462306a36Sopenharmony_ci} 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp, 162762306a36Sopenharmony_ci u16 vid) 162862306a36Sopenharmony_ci{ 162962306a36Sopenharmony_ci return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid); 163062306a36Sopenharmony_ci} 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp, 163362306a36Sopenharmony_ci int br_ifindex) 163462306a36Sopenharmony_ci{ 163562306a36Sopenharmony_ci return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, 163662306a36Sopenharmony_ci &br_ifindex); 163762306a36Sopenharmony_ci} 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp, 164062306a36Sopenharmony_ci u16 rif_index) 164162306a36Sopenharmony_ci{ 164262306a36Sopenharmony_ci return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index); 164362306a36Sopenharmony_ci} 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp) 164662306a36Sopenharmony_ci{ 164762306a36Sopenharmony_ci return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL); 164862306a36Sopenharmony_ci} 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_cistatic int 165162306a36Sopenharmony_cimlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, 165262306a36Sopenharmony_ci const struct mlxsw_sp_flood_table *flood_table) 165362306a36Sopenharmony_ci{ 165462306a36Sopenharmony_ci enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; 165562306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 165662306a36Sopenharmony_ci const int *sfgc_packet_types; 165762306a36Sopenharmony_ci u16 num_fids, mid_base; 165862306a36Sopenharmony_ci int err, i; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0); 166162306a36Sopenharmony_ci num_fids = mlxsw_sp_fid_family_num_fids(fid_family); 166262306a36Sopenharmony_ci err = mlxsw_sp_pgt_mid_alloc_range(mlxsw_sp, mid_base, num_fids); 166362306a36Sopenharmony_ci if (err) 166462306a36Sopenharmony_ci return err; 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; 166762306a36Sopenharmony_ci for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { 166862306a36Sopenharmony_ci char sfgc_pl[MLXSW_REG_SFGC_LEN]; 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci if (!sfgc_packet_types[i]) 167162306a36Sopenharmony_ci continue; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci mlxsw_reg_sfgc_pack(sfgc_pl, i, fid_family->bridge_type, 167462306a36Sopenharmony_ci flood_table->table_type, 0, mid_base); 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); 167762306a36Sopenharmony_ci if (err) 167862306a36Sopenharmony_ci goto err_reg_write; 167962306a36Sopenharmony_ci } 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci return 0; 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_cierr_reg_write: 168462306a36Sopenharmony_ci mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids); 168562306a36Sopenharmony_ci return err; 168662306a36Sopenharmony_ci} 168762306a36Sopenharmony_ci 168862306a36Sopenharmony_cistatic void 168962306a36Sopenharmony_cimlxsw_sp_fid_flood_table_fini(struct mlxsw_sp_fid_family *fid_family, 169062306a36Sopenharmony_ci const struct mlxsw_sp_flood_table *flood_table) 169162306a36Sopenharmony_ci{ 169262306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 169362306a36Sopenharmony_ci u16 num_fids, mid_base; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci mid_base = mlxsw_sp_fid_flood_table_mid(fid_family, flood_table, 0); 169662306a36Sopenharmony_ci num_fids = mlxsw_sp_fid_family_num_fids(fid_family); 169762306a36Sopenharmony_ci mlxsw_sp_pgt_mid_free_range(mlxsw_sp, mid_base, num_fids); 169862306a36Sopenharmony_ci} 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_cistatic int 170162306a36Sopenharmony_cimlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) 170262306a36Sopenharmony_ci{ 170362306a36Sopenharmony_ci int i; 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci for (i = 0; i < fid_family->nr_flood_tables; i++) { 170662306a36Sopenharmony_ci const struct mlxsw_sp_flood_table *flood_table; 170762306a36Sopenharmony_ci int err; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci flood_table = &fid_family->flood_tables[i]; 171062306a36Sopenharmony_ci err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table); 171162306a36Sopenharmony_ci if (err) 171262306a36Sopenharmony_ci return err; 171362306a36Sopenharmony_ci } 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci return 0; 171662306a36Sopenharmony_ci} 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_cistatic void 171962306a36Sopenharmony_cimlxsw_sp_fid_flood_tables_fini(struct mlxsw_sp_fid_family *fid_family) 172062306a36Sopenharmony_ci{ 172162306a36Sopenharmony_ci int i; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci for (i = 0; i < fid_family->nr_flood_tables; i++) { 172462306a36Sopenharmony_ci const struct mlxsw_sp_flood_table *flood_table; 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci flood_table = &fid_family->flood_tables[i]; 172762306a36Sopenharmony_ci mlxsw_sp_fid_flood_table_fini(fid_family, flood_table); 172862306a36Sopenharmony_ci } 172962306a36Sopenharmony_ci} 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_cistatic int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp, 173262306a36Sopenharmony_ci const struct mlxsw_sp_fid_family *tmpl) 173362306a36Sopenharmony_ci{ 173462306a36Sopenharmony_ci u16 nr_fids = tmpl->end_index - tmpl->start_index + 1; 173562306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family; 173662306a36Sopenharmony_ci int err; 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL); 173962306a36Sopenharmony_ci if (!fid_family) 174062306a36Sopenharmony_ci return -ENOMEM; 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci fid_family->mlxsw_sp = mlxsw_sp; 174362306a36Sopenharmony_ci INIT_LIST_HEAD(&fid_family->fids_list); 174462306a36Sopenharmony_ci fid_family->fids_bitmap = bitmap_zalloc(nr_fids, GFP_KERNEL); 174562306a36Sopenharmony_ci if (!fid_family->fids_bitmap) { 174662306a36Sopenharmony_ci err = -ENOMEM; 174762306a36Sopenharmony_ci goto err_alloc_fids_bitmap; 174862306a36Sopenharmony_ci } 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci if (fid_family->flood_tables) { 175162306a36Sopenharmony_ci err = mlxsw_sp_fid_flood_tables_init(fid_family); 175262306a36Sopenharmony_ci if (err) 175362306a36Sopenharmony_ci goto err_fid_flood_tables_init; 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family; 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci return 0; 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_cierr_fid_flood_tables_init: 176162306a36Sopenharmony_ci bitmap_free(fid_family->fids_bitmap); 176262306a36Sopenharmony_cierr_alloc_fids_bitmap: 176362306a36Sopenharmony_ci kfree(fid_family); 176462306a36Sopenharmony_ci return err; 176562306a36Sopenharmony_ci} 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_cistatic void 176862306a36Sopenharmony_cimlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp, 176962306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family) 177062306a36Sopenharmony_ci{ 177162306a36Sopenharmony_ci mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci if (fid_family->flood_tables) 177462306a36Sopenharmony_ci mlxsw_sp_fid_flood_tables_fini(fid_family); 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci bitmap_free(fid_family->fids_bitmap); 177762306a36Sopenharmony_ci WARN_ON_ONCE(!list_empty(&fid_family->fids_list)); 177862306a36Sopenharmony_ci kfree(fid_family); 177962306a36Sopenharmony_ci} 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ciint mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port) 178262306a36Sopenharmony_ci{ 178362306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci /* Track number of FIDs configured on the port with mapping type 178662306a36Sopenharmony_ci * PORT_VID_TO_FID, so that we know when to transition the port 178762306a36Sopenharmony_ci * back to non-virtual (VLAN) mode. 178862306a36Sopenharmony_ci */ 178962306a36Sopenharmony_ci mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); 179262306a36Sopenharmony_ci} 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_civoid mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port) 179562306a36Sopenharmony_ci{ 179662306a36Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; 179962306a36Sopenharmony_ci} 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ciint mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) 180262306a36Sopenharmony_ci{ 180362306a36Sopenharmony_ci unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); 180462306a36Sopenharmony_ci struct mlxsw_sp_fid_core *fid_core; 180562306a36Sopenharmony_ci int err, i; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL); 180862306a36Sopenharmony_ci if (!fid_core) 180962306a36Sopenharmony_ci return -ENOMEM; 181062306a36Sopenharmony_ci mlxsw_sp->fid_core = fid_core; 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params); 181362306a36Sopenharmony_ci if (err) 181462306a36Sopenharmony_ci goto err_rhashtable_fid_init; 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params); 181762306a36Sopenharmony_ci if (err) 181862306a36Sopenharmony_ci goto err_rhashtable_vni_init; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int), 182162306a36Sopenharmony_ci GFP_KERNEL); 182262306a36Sopenharmony_ci if (!fid_core->port_fid_mappings) { 182362306a36Sopenharmony_ci err = -ENOMEM; 182462306a36Sopenharmony_ci goto err_alloc_port_fid_mappings; 182562306a36Sopenharmony_ci } 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) { 182862306a36Sopenharmony_ci err = mlxsw_sp_fid_family_register(mlxsw_sp, 182962306a36Sopenharmony_ci mlxsw_sp->fid_family_arr[i]); 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci if (err) 183262306a36Sopenharmony_ci goto err_fid_ops_register; 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci return 0; 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_cierr_fid_ops_register: 183862306a36Sopenharmony_ci for (i--; i >= 0; i--) { 183962306a36Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci fid_family = fid_core->fid_family_arr[i]; 184262306a36Sopenharmony_ci mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family); 184362306a36Sopenharmony_ci } 184462306a36Sopenharmony_ci kfree(fid_core->port_fid_mappings); 184562306a36Sopenharmony_cierr_alloc_port_fid_mappings: 184662306a36Sopenharmony_ci rhashtable_destroy(&fid_core->vni_ht); 184762306a36Sopenharmony_cierr_rhashtable_vni_init: 184862306a36Sopenharmony_ci rhashtable_destroy(&fid_core->fid_ht); 184962306a36Sopenharmony_cierr_rhashtable_fid_init: 185062306a36Sopenharmony_ci kfree(fid_core); 185162306a36Sopenharmony_ci return err; 185262306a36Sopenharmony_ci} 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_civoid mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) 185562306a36Sopenharmony_ci{ 185662306a36Sopenharmony_ci struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; 185762306a36Sopenharmony_ci int i; 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_ci for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) 186062306a36Sopenharmony_ci mlxsw_sp_fid_family_unregister(mlxsw_sp, 186162306a36Sopenharmony_ci fid_core->fid_family_arr[i]); 186262306a36Sopenharmony_ci kfree(fid_core->port_fid_mappings); 186362306a36Sopenharmony_ci rhashtable_destroy(&fid_core->vni_ht); 186462306a36Sopenharmony_ci rhashtable_destroy(&fid_core->fid_ht); 186562306a36Sopenharmony_ci kfree(fid_core); 186662306a36Sopenharmony_ci} 1867