18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/kernel.h> 58c2ecf20Sopenharmony_ci#include <linux/bitops.h> 68c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 78c2ecf20Sopenharmony_ci#include <linux/if_bridge.h> 88c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 98c2ecf20Sopenharmony_ci#include <linux/rhashtable.h> 108c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 118c2ecf20Sopenharmony_ci#include <linux/refcount.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "spectrum.h" 148c2ecf20Sopenharmony_ci#include "reg.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistruct mlxsw_sp_fid_family; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistruct mlxsw_sp_fid_core { 198c2ecf20Sopenharmony_ci struct rhashtable fid_ht; 208c2ecf20Sopenharmony_ci struct rhashtable vni_ht; 218c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family_arr[MLXSW_SP_FID_TYPE_MAX]; 228c2ecf20Sopenharmony_ci unsigned int *port_fid_mappings; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct mlxsw_sp_fid { 268c2ecf20Sopenharmony_ci struct list_head list; 278c2ecf20Sopenharmony_ci struct mlxsw_sp_rif *rif; 288c2ecf20Sopenharmony_ci refcount_t ref_count; 298c2ecf20Sopenharmony_ci u16 fid_index; 308c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family; 318c2ecf20Sopenharmony_ci struct rhash_head ht_node; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci struct rhash_head vni_ht_node; 348c2ecf20Sopenharmony_ci enum mlxsw_sp_nve_type nve_type; 358c2ecf20Sopenharmony_ci __be32 vni; 368c2ecf20Sopenharmony_ci u32 nve_flood_index; 378c2ecf20Sopenharmony_ci int nve_ifindex; 388c2ecf20Sopenharmony_ci u8 vni_valid:1, 398c2ecf20Sopenharmony_ci nve_flood_index_valid:1; 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistruct mlxsw_sp_fid_8021q { 438c2ecf20Sopenharmony_ci struct mlxsw_sp_fid common; 448c2ecf20Sopenharmony_ci u16 vid; 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct mlxsw_sp_fid_8021d { 488c2ecf20Sopenharmony_ci struct mlxsw_sp_fid common; 498c2ecf20Sopenharmony_ci int br_ifindex; 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic const struct rhashtable_params mlxsw_sp_fid_ht_params = { 538c2ecf20Sopenharmony_ci .key_len = sizeof_field(struct mlxsw_sp_fid, fid_index), 548c2ecf20Sopenharmony_ci .key_offset = offsetof(struct mlxsw_sp_fid, fid_index), 558c2ecf20Sopenharmony_ci .head_offset = offsetof(struct mlxsw_sp_fid, ht_node), 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic const struct rhashtable_params mlxsw_sp_fid_vni_ht_params = { 598c2ecf20Sopenharmony_ci .key_len = sizeof_field(struct mlxsw_sp_fid, vni), 608c2ecf20Sopenharmony_ci .key_offset = offsetof(struct mlxsw_sp_fid, vni), 618c2ecf20Sopenharmony_ci .head_offset = offsetof(struct mlxsw_sp_fid, vni_ht_node), 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistruct mlxsw_sp_flood_table { 658c2ecf20Sopenharmony_ci enum mlxsw_sp_flood_type packet_type; 668c2ecf20Sopenharmony_ci enum mlxsw_reg_sfgc_bridge_type bridge_type; 678c2ecf20Sopenharmony_ci enum mlxsw_flood_table_type table_type; 688c2ecf20Sopenharmony_ci int table_index; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct mlxsw_sp_fid_ops { 728c2ecf20Sopenharmony_ci void (*setup)(struct mlxsw_sp_fid *fid, const void *arg); 738c2ecf20Sopenharmony_ci int (*configure)(struct mlxsw_sp_fid *fid); 748c2ecf20Sopenharmony_ci void (*deconfigure)(struct mlxsw_sp_fid *fid); 758c2ecf20Sopenharmony_ci int (*index_alloc)(struct mlxsw_sp_fid *fid, const void *arg, 768c2ecf20Sopenharmony_ci u16 *p_fid_index); 778c2ecf20Sopenharmony_ci bool (*compare)(const struct mlxsw_sp_fid *fid, 788c2ecf20Sopenharmony_ci const void *arg); 798c2ecf20Sopenharmony_ci u16 (*flood_index)(const struct mlxsw_sp_fid *fid); 808c2ecf20Sopenharmony_ci int (*port_vid_map)(struct mlxsw_sp_fid *fid, 818c2ecf20Sopenharmony_ci struct mlxsw_sp_port *port, u16 vid); 828c2ecf20Sopenharmony_ci void (*port_vid_unmap)(struct mlxsw_sp_fid *fid, 838c2ecf20Sopenharmony_ci struct mlxsw_sp_port *port, u16 vid); 848c2ecf20Sopenharmony_ci int (*vni_set)(struct mlxsw_sp_fid *fid, __be32 vni); 858c2ecf20Sopenharmony_ci void (*vni_clear)(struct mlxsw_sp_fid *fid); 868c2ecf20Sopenharmony_ci int (*nve_flood_index_set)(struct mlxsw_sp_fid *fid, 878c2ecf20Sopenharmony_ci u32 nve_flood_index); 888c2ecf20Sopenharmony_ci void (*nve_flood_index_clear)(struct mlxsw_sp_fid *fid); 898c2ecf20Sopenharmony_ci void (*fdb_clear_offload)(const struct mlxsw_sp_fid *fid, 908c2ecf20Sopenharmony_ci const struct net_device *nve_dev); 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistruct mlxsw_sp_fid_family { 948c2ecf20Sopenharmony_ci enum mlxsw_sp_fid_type type; 958c2ecf20Sopenharmony_ci size_t fid_size; 968c2ecf20Sopenharmony_ci u16 start_index; 978c2ecf20Sopenharmony_ci u16 end_index; 988c2ecf20Sopenharmony_ci struct list_head fids_list; 998c2ecf20Sopenharmony_ci unsigned long *fids_bitmap; 1008c2ecf20Sopenharmony_ci const struct mlxsw_sp_flood_table *flood_tables; 1018c2ecf20Sopenharmony_ci int nr_flood_tables; 1028c2ecf20Sopenharmony_ci enum mlxsw_sp_rif_type rif_type; 1038c2ecf20Sopenharmony_ci const struct mlxsw_sp_fid_ops *ops; 1048c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp; 1058c2ecf20Sopenharmony_ci u8 lag_vid_valid:1; 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic const int mlxsw_sp_sfgc_uc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { 1098c2ecf20Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_UNKNOWN_UNICAST] = 1, 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { 1138c2ecf20Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_BROADCAST] = 1, 1148c2ecf20Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP] = 1, 1158c2ecf20Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL] = 1, 1168c2ecf20Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST] = 1, 1178c2ecf20Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6] = 1, 1188c2ecf20Sopenharmony_ci}; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = { 1218c2ecf20Sopenharmony_ci [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4] = 1, 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic const int *mlxsw_sp_packet_type_sfgc_types[] = { 1258c2ecf20Sopenharmony_ci [MLXSW_SP_FLOOD_TYPE_UC] = mlxsw_sp_sfgc_uc_packet_types, 1268c2ecf20Sopenharmony_ci [MLXSW_SP_FLOOD_TYPE_BC] = mlxsw_sp_sfgc_bc_packet_types, 1278c2ecf20Sopenharmony_ci [MLXSW_SP_FLOOD_TYPE_MC] = mlxsw_sp_sfgc_mc_packet_types, 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cibool mlxsw_sp_fid_is_dummy(struct mlxsw_sp *mlxsw_sp, u16 fid_index) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci enum mlxsw_sp_fid_type fid_type = MLXSW_SP_FID_TYPE_DUMMY; 1338c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci fid_family = mlxsw_sp->fid_core->fid_family_arr[fid_type]; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return fid_family->start_index == fid_index; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cibool mlxsw_sp_fid_lag_vid_valid(const struct mlxsw_sp_fid *fid) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci return fid->fid_family->lag_vid_valid; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_index(struct mlxsw_sp *mlxsw_sp, 1468c2ecf20Sopenharmony_ci u16 fid_index) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci struct mlxsw_sp_fid *fid; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->fid_ht, &fid_index, 1518c2ecf20Sopenharmony_ci mlxsw_sp_fid_ht_params); 1528c2ecf20Sopenharmony_ci if (fid) 1538c2ecf20Sopenharmony_ci refcount_inc(&fid->ref_count); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return fid; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ciint mlxsw_sp_fid_nve_ifindex(const struct mlxsw_sp_fid *fid, int *nve_ifindex) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci if (!fid->vni_valid) 1618c2ecf20Sopenharmony_ci return -EINVAL; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci *nve_ifindex = fid->nve_ifindex; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return 0; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ciint mlxsw_sp_fid_nve_type(const struct mlxsw_sp_fid *fid, 1698c2ecf20Sopenharmony_ci enum mlxsw_sp_nve_type *p_type) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci if (!fid->vni_valid) 1728c2ecf20Sopenharmony_ci return -EINVAL; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci *p_type = fid->nve_type; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return 0; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_lookup_by_vni(struct mlxsw_sp *mlxsw_sp, 1808c2ecf20Sopenharmony_ci __be32 vni) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci struct mlxsw_sp_fid *fid; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci fid = rhashtable_lookup_fast(&mlxsw_sp->fid_core->vni_ht, &vni, 1858c2ecf20Sopenharmony_ci mlxsw_sp_fid_vni_ht_params); 1868c2ecf20Sopenharmony_ci if (fid) 1878c2ecf20Sopenharmony_ci refcount_inc(&fid->ref_count); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return fid; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ciint mlxsw_sp_fid_vni(const struct mlxsw_sp_fid *fid, __be32 *vni) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci if (!fid->vni_valid) 1958c2ecf20Sopenharmony_ci return -EINVAL; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci *vni = fid->vni; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ciint mlxsw_sp_fid_nve_flood_index_set(struct mlxsw_sp_fid *fid, 2038c2ecf20Sopenharmony_ci u32 nve_flood_index) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 2068c2ecf20Sopenharmony_ci const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 2078c2ecf20Sopenharmony_ci int err; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (WARN_ON(!ops->nve_flood_index_set || fid->nve_flood_index_valid)) 2108c2ecf20Sopenharmony_ci return -EINVAL; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci err = ops->nve_flood_index_set(fid, nve_flood_index); 2138c2ecf20Sopenharmony_ci if (err) 2148c2ecf20Sopenharmony_ci return err; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci fid->nve_flood_index = nve_flood_index; 2178c2ecf20Sopenharmony_ci fid->nve_flood_index_valid = true; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_civoid mlxsw_sp_fid_nve_flood_index_clear(struct mlxsw_sp_fid *fid) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 2258c2ecf20Sopenharmony_ci const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci if (WARN_ON(!ops->nve_flood_index_clear || !fid->nve_flood_index_valid)) 2288c2ecf20Sopenharmony_ci return; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci fid->nve_flood_index_valid = false; 2318c2ecf20Sopenharmony_ci ops->nve_flood_index_clear(fid); 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cibool mlxsw_sp_fid_nve_flood_index_is_set(const struct mlxsw_sp_fid *fid) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci return fid->nve_flood_index_valid; 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ciint mlxsw_sp_fid_vni_set(struct mlxsw_sp_fid *fid, enum mlxsw_sp_nve_type type, 2408c2ecf20Sopenharmony_ci __be32 vni, int nve_ifindex) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 2438c2ecf20Sopenharmony_ci const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 2448c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 2458c2ecf20Sopenharmony_ci int err; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (WARN_ON(!ops->vni_set || fid->vni_valid)) 2488c2ecf20Sopenharmony_ci return -EINVAL; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci fid->nve_type = type; 2518c2ecf20Sopenharmony_ci fid->nve_ifindex = nve_ifindex; 2528c2ecf20Sopenharmony_ci fid->vni = vni; 2538c2ecf20Sopenharmony_ci err = rhashtable_lookup_insert_fast(&mlxsw_sp->fid_core->vni_ht, 2548c2ecf20Sopenharmony_ci &fid->vni_ht_node, 2558c2ecf20Sopenharmony_ci mlxsw_sp_fid_vni_ht_params); 2568c2ecf20Sopenharmony_ci if (err) 2578c2ecf20Sopenharmony_ci return err; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci err = ops->vni_set(fid, vni); 2608c2ecf20Sopenharmony_ci if (err) 2618c2ecf20Sopenharmony_ci goto err_vni_set; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci fid->vni_valid = true; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cierr_vni_set: 2688c2ecf20Sopenharmony_ci rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node, 2698c2ecf20Sopenharmony_ci mlxsw_sp_fid_vni_ht_params); 2708c2ecf20Sopenharmony_ci return err; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_civoid mlxsw_sp_fid_vni_clear(struct mlxsw_sp_fid *fid) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 2768c2ecf20Sopenharmony_ci const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 2778c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (WARN_ON(!ops->vni_clear || !fid->vni_valid)) 2808c2ecf20Sopenharmony_ci return; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci fid->vni_valid = false; 2838c2ecf20Sopenharmony_ci ops->vni_clear(fid); 2848c2ecf20Sopenharmony_ci rhashtable_remove_fast(&mlxsw_sp->fid_core->vni_ht, &fid->vni_ht_node, 2858c2ecf20Sopenharmony_ci mlxsw_sp_fid_vni_ht_params); 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cibool mlxsw_sp_fid_vni_is_set(const struct mlxsw_sp_fid *fid) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci return fid->vni_valid; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_civoid mlxsw_sp_fid_fdb_clear_offload(const struct mlxsw_sp_fid *fid, 2948c2ecf20Sopenharmony_ci const struct net_device *nve_dev) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 2978c2ecf20Sopenharmony_ci const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (ops->fdb_clear_offload) 3008c2ecf20Sopenharmony_ci ops->fdb_clear_offload(fid, nve_dev); 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_flood_table * 3048c2ecf20Sopenharmony_cimlxsw_sp_fid_flood_table_lookup(const struct mlxsw_sp_fid *fid, 3058c2ecf20Sopenharmony_ci enum mlxsw_sp_flood_type packet_type) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 3088c2ecf20Sopenharmony_ci int i; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci for (i = 0; i < fid_family->nr_flood_tables; i++) { 3118c2ecf20Sopenharmony_ci if (fid_family->flood_tables[i].packet_type != packet_type) 3128c2ecf20Sopenharmony_ci continue; 3138c2ecf20Sopenharmony_ci return &fid_family->flood_tables[i]; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci return NULL; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ciint mlxsw_sp_fid_flood_set(struct mlxsw_sp_fid *fid, 3208c2ecf20Sopenharmony_ci enum mlxsw_sp_flood_type packet_type, u8 local_port, 3218c2ecf20Sopenharmony_ci bool member) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 3248c2ecf20Sopenharmony_ci const struct mlxsw_sp_fid_ops *ops = fid_family->ops; 3258c2ecf20Sopenharmony_ci const struct mlxsw_sp_flood_table *flood_table; 3268c2ecf20Sopenharmony_ci char *sftr_pl; 3278c2ecf20Sopenharmony_ci int err; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (WARN_ON(!fid_family->flood_tables || !ops->flood_index)) 3308c2ecf20Sopenharmony_ci return -EINVAL; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci flood_table = mlxsw_sp_fid_flood_table_lookup(fid, packet_type); 3338c2ecf20Sopenharmony_ci if (!flood_table) 3348c2ecf20Sopenharmony_ci return -ESRCH; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci sftr_pl = kmalloc(MLXSW_REG_SFTR_LEN, GFP_KERNEL); 3378c2ecf20Sopenharmony_ci if (!sftr_pl) 3388c2ecf20Sopenharmony_ci return -ENOMEM; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci mlxsw_reg_sftr_pack(sftr_pl, flood_table->table_index, 3418c2ecf20Sopenharmony_ci ops->flood_index(fid), flood_table->table_type, 1, 3428c2ecf20Sopenharmony_ci local_port, member); 3438c2ecf20Sopenharmony_ci err = mlxsw_reg_write(fid_family->mlxsw_sp->core, MLXSW_REG(sftr), 3448c2ecf20Sopenharmony_ci sftr_pl); 3458c2ecf20Sopenharmony_ci kfree(sftr_pl); 3468c2ecf20Sopenharmony_ci return err; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ciint mlxsw_sp_fid_port_vid_map(struct mlxsw_sp_fid *fid, 3508c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci if (WARN_ON(!fid->fid_family->ops->port_vid_map)) 3538c2ecf20Sopenharmony_ci return -EINVAL; 3548c2ecf20Sopenharmony_ci return fid->fid_family->ops->port_vid_map(fid, mlxsw_sp_port, vid); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_civoid mlxsw_sp_fid_port_vid_unmap(struct mlxsw_sp_fid *fid, 3588c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci fid->fid_family->ops->port_vid_unmap(fid, mlxsw_sp_port, vid); 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ciu16 mlxsw_sp_fid_index(const struct mlxsw_sp_fid *fid) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci return fid->fid_index; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cienum mlxsw_sp_fid_type mlxsw_sp_fid_type(const struct mlxsw_sp_fid *fid) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci return fid->fid_family->type; 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_civoid mlxsw_sp_fid_rif_set(struct mlxsw_sp_fid *fid, struct mlxsw_sp_rif *rif) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci fid->rif = rif; 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistruct mlxsw_sp_rif *mlxsw_sp_fid_rif(const struct mlxsw_sp_fid *fid) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci return fid->rif; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cienum mlxsw_sp_rif_type 3848c2ecf20Sopenharmony_cimlxsw_sp_fid_type_rif_type(const struct mlxsw_sp *mlxsw_sp, 3858c2ecf20Sopenharmony_ci enum mlxsw_sp_fid_type type) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci return fid_core->fid_family_arr[type]->rif_type; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic struct mlxsw_sp_fid_8021q * 3938c2ecf20Sopenharmony_cimlxsw_sp_fid_8021q_fid(const struct mlxsw_sp_fid *fid) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci return container_of(fid, struct mlxsw_sp_fid_8021q, common); 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ciu16 mlxsw_sp_fid_8021q_vid(const struct mlxsw_sp_fid *fid) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci return mlxsw_sp_fid_8021q_fid(fid)->vid; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_cistatic void mlxsw_sp_fid_8021q_setup(struct mlxsw_sp_fid *fid, const void *arg) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci u16 vid = *(u16 *) arg; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci mlxsw_sp_fid_8021q_fid(fid)->vid = vid; 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic enum mlxsw_reg_sfmr_op mlxsw_sp_sfmr_op(bool valid) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci return valid ? MLXSW_REG_SFMR_OP_CREATE_FID : 4138c2ecf20Sopenharmony_ci MLXSW_REG_SFMR_OP_DESTROY_FID; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic int mlxsw_sp_fid_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, 4178c2ecf20Sopenharmony_ci u16 fid_offset, bool valid) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci char sfmr_pl[MLXSW_REG_SFMR_LEN]; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci mlxsw_reg_sfmr_pack(sfmr_pl, mlxsw_sp_sfmr_op(valid), fid_index, 4228c2ecf20Sopenharmony_ci fid_offset); 4238c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic int mlxsw_sp_fid_vni_op(struct mlxsw_sp *mlxsw_sp, u16 fid_index, 4278c2ecf20Sopenharmony_ci __be32 vni, bool vni_valid, u32 nve_flood_index, 4288c2ecf20Sopenharmony_ci bool nve_flood_index_valid) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci char sfmr_pl[MLXSW_REG_SFMR_LEN]; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci mlxsw_reg_sfmr_pack(sfmr_pl, MLXSW_REG_SFMR_OP_CREATE_FID, fid_index, 4338c2ecf20Sopenharmony_ci 0); 4348c2ecf20Sopenharmony_ci mlxsw_reg_sfmr_vv_set(sfmr_pl, vni_valid); 4358c2ecf20Sopenharmony_ci mlxsw_reg_sfmr_vni_set(sfmr_pl, be32_to_cpu(vni)); 4368c2ecf20Sopenharmony_ci mlxsw_reg_sfmr_vtfp_set(sfmr_pl, nve_flood_index_valid); 4378c2ecf20Sopenharmony_ci mlxsw_reg_sfmr_nve_tunnel_flood_ptr_set(sfmr_pl, nve_flood_index); 4388c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfmr), sfmr_pl); 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic int __mlxsw_sp_fid_port_vid_map(struct mlxsw_sp *mlxsw_sp, u16 fid_index, 4428c2ecf20Sopenharmony_ci u8 local_port, u16 vid, bool valid) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci enum mlxsw_reg_svfa_mt mt = MLXSW_REG_SVFA_MT_PORT_VID_TO_FID; 4458c2ecf20Sopenharmony_ci char svfa_pl[MLXSW_REG_SVFA_LEN]; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci mlxsw_reg_svfa_pack(svfa_pl, local_port, mt, valid, fid_index, vid); 4488c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(svfa), svfa_pl); 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic struct mlxsw_sp_fid_8021d * 4528c2ecf20Sopenharmony_cimlxsw_sp_fid_8021d_fid(const struct mlxsw_sp_fid *fid) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci return container_of(fid, struct mlxsw_sp_fid_8021d, common); 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic void mlxsw_sp_fid_8021d_setup(struct mlxsw_sp_fid *fid, const void *arg) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci int br_ifindex = *(int *) arg; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci mlxsw_sp_fid_8021d_fid(fid)->br_ifindex = br_ifindex; 4628c2ecf20Sopenharmony_ci} 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic int mlxsw_sp_fid_8021d_configure(struct mlxsw_sp_fid *fid) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci return mlxsw_sp_fid_op(fid_family->mlxsw_sp, fid->fid_index, 0, true); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic void mlxsw_sp_fid_8021d_deconfigure(struct mlxsw_sp_fid *fid) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci if (fid->vni_valid) 4748c2ecf20Sopenharmony_ci mlxsw_sp_nve_fid_disable(fid->fid_family->mlxsw_sp, fid); 4758c2ecf20Sopenharmony_ci mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic int mlxsw_sp_fid_8021d_index_alloc(struct mlxsw_sp_fid *fid, 4798c2ecf20Sopenharmony_ci const void *arg, u16 *p_fid_index) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 4828c2ecf20Sopenharmony_ci u16 nr_fids, fid_index; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci nr_fids = fid_family->end_index - fid_family->start_index + 1; 4858c2ecf20Sopenharmony_ci fid_index = find_first_zero_bit(fid_family->fids_bitmap, nr_fids); 4868c2ecf20Sopenharmony_ci if (fid_index == nr_fids) 4878c2ecf20Sopenharmony_ci return -ENOBUFS; 4888c2ecf20Sopenharmony_ci *p_fid_index = fid_family->start_index + fid_index; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci return 0; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_cistatic bool 4948c2ecf20Sopenharmony_cimlxsw_sp_fid_8021d_compare(const struct mlxsw_sp_fid *fid, const void *arg) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci int br_ifindex = *(int *) arg; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci return mlxsw_sp_fid_8021d_fid(fid)->br_ifindex == br_ifindex; 4998c2ecf20Sopenharmony_ci} 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cistatic u16 mlxsw_sp_fid_8021d_flood_index(const struct mlxsw_sp_fid *fid) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci return fid->fid_index - VLAN_N_VID; 5048c2ecf20Sopenharmony_ci} 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic int mlxsw_sp_port_vp_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 5098c2ecf20Sopenharmony_ci struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 5108c2ecf20Sopenharmony_ci int err; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci list_for_each_entry(mlxsw_sp_port_vlan, &mlxsw_sp_port->vlans_list, 5138c2ecf20Sopenharmony_ci list) { 5148c2ecf20Sopenharmony_ci struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; 5158c2ecf20Sopenharmony_ci u16 vid = mlxsw_sp_port_vlan->vid; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (!fid) 5188c2ecf20Sopenharmony_ci continue; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 5218c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port, 5228c2ecf20Sopenharmony_ci vid, true); 5238c2ecf20Sopenharmony_ci if (err) 5248c2ecf20Sopenharmony_ci goto err_fid_port_vid_map; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci err = mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, true); 5288c2ecf20Sopenharmony_ci if (err) 5298c2ecf20Sopenharmony_ci goto err_port_vp_mode_set; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci return 0; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cierr_port_vp_mode_set: 5348c2ecf20Sopenharmony_cierr_fid_port_vid_map: 5358c2ecf20Sopenharmony_ci list_for_each_entry_continue_reverse(mlxsw_sp_port_vlan, 5368c2ecf20Sopenharmony_ci &mlxsw_sp_port->vlans_list, list) { 5378c2ecf20Sopenharmony_ci struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; 5388c2ecf20Sopenharmony_ci u16 vid = mlxsw_sp_port_vlan->vid; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci if (!fid) 5418c2ecf20Sopenharmony_ci continue; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 5448c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port, vid, 5458c2ecf20Sopenharmony_ci false); 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci return err; 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic void mlxsw_sp_port_vlan_mode_trans(struct mlxsw_sp_port *mlxsw_sp_port) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 5538c2ecf20Sopenharmony_ci struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci list_for_each_entry_reverse(mlxsw_sp_port_vlan, 5588c2ecf20Sopenharmony_ci &mlxsw_sp_port->vlans_list, list) { 5598c2ecf20Sopenharmony_ci struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid; 5608c2ecf20Sopenharmony_ci u16 vid = mlxsw_sp_port_vlan->vid; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (!fid) 5638c2ecf20Sopenharmony_ci continue; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 5668c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port, vid, 5678c2ecf20Sopenharmony_ci false); 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci} 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic int mlxsw_sp_fid_8021d_port_vid_map(struct mlxsw_sp_fid *fid, 5728c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, 5738c2ecf20Sopenharmony_ci u16 vid) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 5768c2ecf20Sopenharmony_ci u8 local_port = mlxsw_sp_port->local_port; 5778c2ecf20Sopenharmony_ci int err; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci err = __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 5808c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port, vid, true); 5818c2ecf20Sopenharmony_ci if (err) 5828c2ecf20Sopenharmony_ci return err; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { 5858c2ecf20Sopenharmony_ci err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); 5868c2ecf20Sopenharmony_ci if (err) 5878c2ecf20Sopenharmony_ci goto err_port_vp_mode_trans; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cierr_port_vp_mode_trans: 5938c2ecf20Sopenharmony_ci mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 5948c2ecf20Sopenharmony_ci __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 5958c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port, vid, false); 5968c2ecf20Sopenharmony_ci return err; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cistatic void 6008c2ecf20Sopenharmony_cimlxsw_sp_fid_8021d_port_vid_unmap(struct mlxsw_sp_fid *fid, 6018c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 6048c2ecf20Sopenharmony_ci u8 local_port = mlxsw_sp_port->local_port; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) 6078c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); 6088c2ecf20Sopenharmony_ci mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 6098c2ecf20Sopenharmony_ci __mlxsw_sp_fid_port_vid_map(mlxsw_sp, fid->fid_index, 6108c2ecf20Sopenharmony_ci mlxsw_sp_port->local_port, vid, false); 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cistatic int mlxsw_sp_fid_8021d_vni_set(struct mlxsw_sp_fid *fid, __be32 vni) 6148c2ecf20Sopenharmony_ci{ 6158c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, vni, 6188c2ecf20Sopenharmony_ci true, fid->nve_flood_index, 6198c2ecf20Sopenharmony_ci fid->nve_flood_index_valid); 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_cistatic void mlxsw_sp_fid_8021d_vni_clear(struct mlxsw_sp_fid *fid) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, 0, false, 6278c2ecf20Sopenharmony_ci fid->nve_flood_index, fid->nve_flood_index_valid); 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_cistatic int mlxsw_sp_fid_8021d_nve_flood_index_set(struct mlxsw_sp_fid *fid, 6318c2ecf20Sopenharmony_ci u32 nve_flood_index) 6328c2ecf20Sopenharmony_ci{ 6338c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, 6368c2ecf20Sopenharmony_ci fid->vni, fid->vni_valid, nve_flood_index, 6378c2ecf20Sopenharmony_ci true); 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic void mlxsw_sp_fid_8021d_nve_flood_index_clear(struct mlxsw_sp_fid *fid) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci mlxsw_sp_fid_vni_op(fid_family->mlxsw_sp, fid->fid_index, fid->vni, 6458c2ecf20Sopenharmony_ci fid->vni_valid, 0, false); 6468c2ecf20Sopenharmony_ci} 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_cistatic void 6498c2ecf20Sopenharmony_cimlxsw_sp_fid_8021d_fdb_clear_offload(const struct mlxsw_sp_fid *fid, 6508c2ecf20Sopenharmony_ci const struct net_device *nve_dev) 6518c2ecf20Sopenharmony_ci{ 6528c2ecf20Sopenharmony_ci br_fdb_clear_offload(nve_dev, 0); 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021d_ops = { 6568c2ecf20Sopenharmony_ci .setup = mlxsw_sp_fid_8021d_setup, 6578c2ecf20Sopenharmony_ci .configure = mlxsw_sp_fid_8021d_configure, 6588c2ecf20Sopenharmony_ci .deconfigure = mlxsw_sp_fid_8021d_deconfigure, 6598c2ecf20Sopenharmony_ci .index_alloc = mlxsw_sp_fid_8021d_index_alloc, 6608c2ecf20Sopenharmony_ci .compare = mlxsw_sp_fid_8021d_compare, 6618c2ecf20Sopenharmony_ci .flood_index = mlxsw_sp_fid_8021d_flood_index, 6628c2ecf20Sopenharmony_ci .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, 6638c2ecf20Sopenharmony_ci .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, 6648c2ecf20Sopenharmony_ci .vni_set = mlxsw_sp_fid_8021d_vni_set, 6658c2ecf20Sopenharmony_ci .vni_clear = mlxsw_sp_fid_8021d_vni_clear, 6668c2ecf20Sopenharmony_ci .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set, 6678c2ecf20Sopenharmony_ci .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, 6688c2ecf20Sopenharmony_ci .fdb_clear_offload = mlxsw_sp_fid_8021d_fdb_clear_offload, 6698c2ecf20Sopenharmony_ci}; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_flood_table mlxsw_sp_fid_8021d_flood_tables[] = { 6728c2ecf20Sopenharmony_ci { 6738c2ecf20Sopenharmony_ci .packet_type = MLXSW_SP_FLOOD_TYPE_UC, 6748c2ecf20Sopenharmony_ci .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, 6758c2ecf20Sopenharmony_ci .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, 6768c2ecf20Sopenharmony_ci .table_index = 0, 6778c2ecf20Sopenharmony_ci }, 6788c2ecf20Sopenharmony_ci { 6798c2ecf20Sopenharmony_ci .packet_type = MLXSW_SP_FLOOD_TYPE_MC, 6808c2ecf20Sopenharmony_ci .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, 6818c2ecf20Sopenharmony_ci .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, 6828c2ecf20Sopenharmony_ci .table_index = 1, 6838c2ecf20Sopenharmony_ci }, 6848c2ecf20Sopenharmony_ci { 6858c2ecf20Sopenharmony_ci .packet_type = MLXSW_SP_FLOOD_TYPE_BC, 6868c2ecf20Sopenharmony_ci .bridge_type = MLXSW_REG_SFGC_BRIDGE_TYPE_VFID, 6878c2ecf20Sopenharmony_ci .table_type = MLXSW_REG_SFGC_TABLE_TYPE_FID, 6888c2ecf20Sopenharmony_ci .table_index = 2, 6898c2ecf20Sopenharmony_ci }, 6908c2ecf20Sopenharmony_ci}; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci/* Range and flood configuration must match mlxsw_config_profile */ 6938c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021d_family = { 6948c2ecf20Sopenharmony_ci .type = MLXSW_SP_FID_TYPE_8021D, 6958c2ecf20Sopenharmony_ci .fid_size = sizeof(struct mlxsw_sp_fid_8021d), 6968c2ecf20Sopenharmony_ci .start_index = VLAN_N_VID, 6978c2ecf20Sopenharmony_ci .end_index = VLAN_N_VID + MLXSW_SP_FID_8021D_MAX - 1, 6988c2ecf20Sopenharmony_ci .flood_tables = mlxsw_sp_fid_8021d_flood_tables, 6998c2ecf20Sopenharmony_ci .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), 7008c2ecf20Sopenharmony_ci .rif_type = MLXSW_SP_RIF_TYPE_FID, 7018c2ecf20Sopenharmony_ci .ops = &mlxsw_sp_fid_8021d_ops, 7028c2ecf20Sopenharmony_ci .lag_vid_valid = 1, 7038c2ecf20Sopenharmony_ci}; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic bool 7068c2ecf20Sopenharmony_cimlxsw_sp_fid_8021q_compare(const struct mlxsw_sp_fid *fid, const void *arg) 7078c2ecf20Sopenharmony_ci{ 7088c2ecf20Sopenharmony_ci u16 vid = *(u16 *) arg; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci return mlxsw_sp_fid_8021q_fid(fid)->vid == vid; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic void 7148c2ecf20Sopenharmony_cimlxsw_sp_fid_8021q_fdb_clear_offload(const struct mlxsw_sp_fid *fid, 7158c2ecf20Sopenharmony_ci const struct net_device *nve_dev) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci br_fdb_clear_offload(nve_dev, mlxsw_sp_fid_8021q_vid(fid)); 7188c2ecf20Sopenharmony_ci} 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_fid_ops mlxsw_sp_fid_8021q_emu_ops = { 7218c2ecf20Sopenharmony_ci .setup = mlxsw_sp_fid_8021q_setup, 7228c2ecf20Sopenharmony_ci .configure = mlxsw_sp_fid_8021d_configure, 7238c2ecf20Sopenharmony_ci .deconfigure = mlxsw_sp_fid_8021d_deconfigure, 7248c2ecf20Sopenharmony_ci .index_alloc = mlxsw_sp_fid_8021d_index_alloc, 7258c2ecf20Sopenharmony_ci .compare = mlxsw_sp_fid_8021q_compare, 7268c2ecf20Sopenharmony_ci .flood_index = mlxsw_sp_fid_8021d_flood_index, 7278c2ecf20Sopenharmony_ci .port_vid_map = mlxsw_sp_fid_8021d_port_vid_map, 7288c2ecf20Sopenharmony_ci .port_vid_unmap = mlxsw_sp_fid_8021d_port_vid_unmap, 7298c2ecf20Sopenharmony_ci .vni_set = mlxsw_sp_fid_8021d_vni_set, 7308c2ecf20Sopenharmony_ci .vni_clear = mlxsw_sp_fid_8021d_vni_clear, 7318c2ecf20Sopenharmony_ci .nve_flood_index_set = mlxsw_sp_fid_8021d_nve_flood_index_set, 7328c2ecf20Sopenharmony_ci .nve_flood_index_clear = mlxsw_sp_fid_8021d_nve_flood_index_clear, 7338c2ecf20Sopenharmony_ci .fdb_clear_offload = mlxsw_sp_fid_8021q_fdb_clear_offload, 7348c2ecf20Sopenharmony_ci}; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci/* There are 4K-2 emulated 802.1Q FIDs, starting right after the 802.1D FIDs */ 7378c2ecf20Sopenharmony_ci#define MLXSW_SP_FID_8021Q_EMU_START (VLAN_N_VID + MLXSW_SP_FID_8021D_MAX) 7388c2ecf20Sopenharmony_ci#define MLXSW_SP_FID_8021Q_EMU_END (MLXSW_SP_FID_8021Q_EMU_START + \ 7398c2ecf20Sopenharmony_ci VLAN_VID_MASK - 2) 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci/* Range and flood configuration must match mlxsw_config_profile */ 7428c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp_fid_8021q_emu_family = { 7438c2ecf20Sopenharmony_ci .type = MLXSW_SP_FID_TYPE_8021Q, 7448c2ecf20Sopenharmony_ci .fid_size = sizeof(struct mlxsw_sp_fid_8021q), 7458c2ecf20Sopenharmony_ci .start_index = MLXSW_SP_FID_8021Q_EMU_START, 7468c2ecf20Sopenharmony_ci .end_index = MLXSW_SP_FID_8021Q_EMU_END, 7478c2ecf20Sopenharmony_ci .flood_tables = mlxsw_sp_fid_8021d_flood_tables, 7488c2ecf20Sopenharmony_ci .nr_flood_tables = ARRAY_SIZE(mlxsw_sp_fid_8021d_flood_tables), 7498c2ecf20Sopenharmony_ci .rif_type = MLXSW_SP_RIF_TYPE_VLAN, 7508c2ecf20Sopenharmony_ci .ops = &mlxsw_sp_fid_8021q_emu_ops, 7518c2ecf20Sopenharmony_ci .lag_vid_valid = 1, 7528c2ecf20Sopenharmony_ci}; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic int mlxsw_sp_fid_rfid_configure(struct mlxsw_sp_fid *fid) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci /* rFIDs are allocated by the device during init */ 7578c2ecf20Sopenharmony_ci return 0; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic void mlxsw_sp_fid_rfid_deconfigure(struct mlxsw_sp_fid *fid) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic int mlxsw_sp_fid_rfid_index_alloc(struct mlxsw_sp_fid *fid, 7658c2ecf20Sopenharmony_ci const void *arg, u16 *p_fid_index) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci u16 rif_index = *(u16 *) arg; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci *p_fid_index = fid->fid_family->start_index + rif_index; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci return 0; 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_cistatic bool mlxsw_sp_fid_rfid_compare(const struct mlxsw_sp_fid *fid, 7758c2ecf20Sopenharmony_ci const void *arg) 7768c2ecf20Sopenharmony_ci{ 7778c2ecf20Sopenharmony_ci u16 rif_index = *(u16 *) arg; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return fid->fid_index == rif_index + fid->fid_family->start_index; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_cistatic int mlxsw_sp_fid_rfid_port_vid_map(struct mlxsw_sp_fid *fid, 7838c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, 7848c2ecf20Sopenharmony_ci u16 vid) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 7878c2ecf20Sopenharmony_ci u8 local_port = mlxsw_sp_port->local_port; 7888c2ecf20Sopenharmony_ci int err; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci /* We only need to transition the port to virtual mode since 7918c2ecf20Sopenharmony_ci * {Port, VID} => FID is done by the firmware upon RIF creation. 7928c2ecf20Sopenharmony_ci */ 7938c2ecf20Sopenharmony_ci if (mlxsw_sp->fid_core->port_fid_mappings[local_port]++ == 0) { 7948c2ecf20Sopenharmony_ci err = mlxsw_sp_port_vp_mode_trans(mlxsw_sp_port); 7958c2ecf20Sopenharmony_ci if (err) 7968c2ecf20Sopenharmony_ci goto err_port_vp_mode_trans; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci return 0; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cierr_port_vp_mode_trans: 8028c2ecf20Sopenharmony_ci mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 8038c2ecf20Sopenharmony_ci return err; 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic void 8078c2ecf20Sopenharmony_cimlxsw_sp_fid_rfid_port_vid_unmap(struct mlxsw_sp_fid *fid, 8088c2ecf20Sopenharmony_ci struct mlxsw_sp_port *mlxsw_sp_port, u16 vid) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 8118c2ecf20Sopenharmony_ci u8 local_port = mlxsw_sp_port->local_port; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci if (mlxsw_sp->fid_core->port_fid_mappings[local_port] == 1) 8148c2ecf20Sopenharmony_ci mlxsw_sp_port_vlan_mode_trans(mlxsw_sp_port); 8158c2ecf20Sopenharmony_ci mlxsw_sp->fid_core->port_fid_mappings[local_port]--; 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_fid_ops mlxsw_sp_fid_rfid_ops = { 8198c2ecf20Sopenharmony_ci .configure = mlxsw_sp_fid_rfid_configure, 8208c2ecf20Sopenharmony_ci .deconfigure = mlxsw_sp_fid_rfid_deconfigure, 8218c2ecf20Sopenharmony_ci .index_alloc = mlxsw_sp_fid_rfid_index_alloc, 8228c2ecf20Sopenharmony_ci .compare = mlxsw_sp_fid_rfid_compare, 8238c2ecf20Sopenharmony_ci .port_vid_map = mlxsw_sp_fid_rfid_port_vid_map, 8248c2ecf20Sopenharmony_ci .port_vid_unmap = mlxsw_sp_fid_rfid_port_vid_unmap, 8258c2ecf20Sopenharmony_ci}; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci#define MLXSW_SP_RFID_BASE (15 * 1024) 8288c2ecf20Sopenharmony_ci#define MLXSW_SP_RFID_MAX 1024 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp_fid_rfid_family = { 8318c2ecf20Sopenharmony_ci .type = MLXSW_SP_FID_TYPE_RFID, 8328c2ecf20Sopenharmony_ci .fid_size = sizeof(struct mlxsw_sp_fid), 8338c2ecf20Sopenharmony_ci .start_index = MLXSW_SP_RFID_BASE, 8348c2ecf20Sopenharmony_ci .end_index = MLXSW_SP_RFID_BASE + MLXSW_SP_RFID_MAX - 1, 8358c2ecf20Sopenharmony_ci .rif_type = MLXSW_SP_RIF_TYPE_SUBPORT, 8368c2ecf20Sopenharmony_ci .ops = &mlxsw_sp_fid_rfid_ops, 8378c2ecf20Sopenharmony_ci}; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic int mlxsw_sp_fid_dummy_configure(struct mlxsw_sp_fid *fid) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid->fid_family->mlxsw_sp; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci return mlxsw_sp_fid_op(mlxsw_sp, fid->fid_index, 0, true); 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic void mlxsw_sp_fid_dummy_deconfigure(struct mlxsw_sp_fid *fid) 8478c2ecf20Sopenharmony_ci{ 8488c2ecf20Sopenharmony_ci mlxsw_sp_fid_op(fid->fid_family->mlxsw_sp, fid->fid_index, 0, false); 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_cistatic int mlxsw_sp_fid_dummy_index_alloc(struct mlxsw_sp_fid *fid, 8528c2ecf20Sopenharmony_ci const void *arg, u16 *p_fid_index) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci *p_fid_index = fid->fid_family->start_index; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci return 0; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cistatic bool mlxsw_sp_fid_dummy_compare(const struct mlxsw_sp_fid *fid, 8608c2ecf20Sopenharmony_ci const void *arg) 8618c2ecf20Sopenharmony_ci{ 8628c2ecf20Sopenharmony_ci return true; 8638c2ecf20Sopenharmony_ci} 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_fid_ops mlxsw_sp_fid_dummy_ops = { 8668c2ecf20Sopenharmony_ci .configure = mlxsw_sp_fid_dummy_configure, 8678c2ecf20Sopenharmony_ci .deconfigure = mlxsw_sp_fid_dummy_deconfigure, 8688c2ecf20Sopenharmony_ci .index_alloc = mlxsw_sp_fid_dummy_index_alloc, 8698c2ecf20Sopenharmony_ci .compare = mlxsw_sp_fid_dummy_compare, 8708c2ecf20Sopenharmony_ci}; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_fid_family mlxsw_sp_fid_dummy_family = { 8738c2ecf20Sopenharmony_ci .type = MLXSW_SP_FID_TYPE_DUMMY, 8748c2ecf20Sopenharmony_ci .fid_size = sizeof(struct mlxsw_sp_fid), 8758c2ecf20Sopenharmony_ci .start_index = VLAN_N_VID - 1, 8768c2ecf20Sopenharmony_ci .end_index = VLAN_N_VID - 1, 8778c2ecf20Sopenharmony_ci .ops = &mlxsw_sp_fid_dummy_ops, 8788c2ecf20Sopenharmony_ci}; 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_fid_family *mlxsw_sp_fid_family_arr[] = { 8818c2ecf20Sopenharmony_ci [MLXSW_SP_FID_TYPE_8021Q] = &mlxsw_sp_fid_8021q_emu_family, 8828c2ecf20Sopenharmony_ci [MLXSW_SP_FID_TYPE_8021D] = &mlxsw_sp_fid_8021d_family, 8838c2ecf20Sopenharmony_ci [MLXSW_SP_FID_TYPE_RFID] = &mlxsw_sp_fid_rfid_family, 8848c2ecf20Sopenharmony_ci [MLXSW_SP_FID_TYPE_DUMMY] = &mlxsw_sp_fid_dummy_family, 8858c2ecf20Sopenharmony_ci}; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic struct mlxsw_sp_fid *mlxsw_sp_fid_lookup(struct mlxsw_sp *mlxsw_sp, 8888c2ecf20Sopenharmony_ci enum mlxsw_sp_fid_type type, 8898c2ecf20Sopenharmony_ci const void *arg) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family; 8928c2ecf20Sopenharmony_ci struct mlxsw_sp_fid *fid; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; 8958c2ecf20Sopenharmony_ci list_for_each_entry(fid, &fid_family->fids_list, list) { 8968c2ecf20Sopenharmony_ci if (!fid->fid_family->ops->compare(fid, arg)) 8978c2ecf20Sopenharmony_ci continue; 8988c2ecf20Sopenharmony_ci refcount_inc(&fid->ref_count); 8998c2ecf20Sopenharmony_ci return fid; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci return NULL; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic struct mlxsw_sp_fid *mlxsw_sp_fid_get(struct mlxsw_sp *mlxsw_sp, 9068c2ecf20Sopenharmony_ci enum mlxsw_sp_fid_type type, 9078c2ecf20Sopenharmony_ci const void *arg) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family; 9108c2ecf20Sopenharmony_ci struct mlxsw_sp_fid *fid; 9118c2ecf20Sopenharmony_ci u16 fid_index; 9128c2ecf20Sopenharmony_ci int err; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci fid = mlxsw_sp_fid_lookup(mlxsw_sp, type, arg); 9158c2ecf20Sopenharmony_ci if (fid) 9168c2ecf20Sopenharmony_ci return fid; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci fid_family = mlxsw_sp->fid_core->fid_family_arr[type]; 9198c2ecf20Sopenharmony_ci fid = kzalloc(fid_family->fid_size, GFP_KERNEL); 9208c2ecf20Sopenharmony_ci if (!fid) 9218c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 9228c2ecf20Sopenharmony_ci fid->fid_family = fid_family; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci err = fid->fid_family->ops->index_alloc(fid, arg, &fid_index); 9258c2ecf20Sopenharmony_ci if (err) 9268c2ecf20Sopenharmony_ci goto err_index_alloc; 9278c2ecf20Sopenharmony_ci fid->fid_index = fid_index; 9288c2ecf20Sopenharmony_ci __set_bit(fid_index - fid_family->start_index, fid_family->fids_bitmap); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci if (fid->fid_family->ops->setup) 9318c2ecf20Sopenharmony_ci fid->fid_family->ops->setup(fid, arg); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci err = fid->fid_family->ops->configure(fid); 9348c2ecf20Sopenharmony_ci if (err) 9358c2ecf20Sopenharmony_ci goto err_configure; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci err = rhashtable_insert_fast(&mlxsw_sp->fid_core->fid_ht, &fid->ht_node, 9388c2ecf20Sopenharmony_ci mlxsw_sp_fid_ht_params); 9398c2ecf20Sopenharmony_ci if (err) 9408c2ecf20Sopenharmony_ci goto err_rhashtable_insert; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci list_add(&fid->list, &fid_family->fids_list); 9438c2ecf20Sopenharmony_ci refcount_set(&fid->ref_count, 1); 9448c2ecf20Sopenharmony_ci return fid; 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_cierr_rhashtable_insert: 9478c2ecf20Sopenharmony_ci fid->fid_family->ops->deconfigure(fid); 9488c2ecf20Sopenharmony_cierr_configure: 9498c2ecf20Sopenharmony_ci __clear_bit(fid_index - fid_family->start_index, 9508c2ecf20Sopenharmony_ci fid_family->fids_bitmap); 9518c2ecf20Sopenharmony_cierr_index_alloc: 9528c2ecf20Sopenharmony_ci kfree(fid); 9538c2ecf20Sopenharmony_ci return ERR_PTR(err); 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_civoid mlxsw_sp_fid_put(struct mlxsw_sp_fid *fid) 9578c2ecf20Sopenharmony_ci{ 9588c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family = fid->fid_family; 9598c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (!refcount_dec_and_test(&fid->ref_count)) 9628c2ecf20Sopenharmony_ci return; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci list_del(&fid->list); 9658c2ecf20Sopenharmony_ci rhashtable_remove_fast(&mlxsw_sp->fid_core->fid_ht, 9668c2ecf20Sopenharmony_ci &fid->ht_node, mlxsw_sp_fid_ht_params); 9678c2ecf20Sopenharmony_ci fid->fid_family->ops->deconfigure(fid); 9688c2ecf20Sopenharmony_ci __clear_bit(fid->fid_index - fid_family->start_index, 9698c2ecf20Sopenharmony_ci fid_family->fids_bitmap); 9708c2ecf20Sopenharmony_ci kfree(fid); 9718c2ecf20Sopenharmony_ci} 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_8021q_get(struct mlxsw_sp *mlxsw_sp, u16 vid) 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid); 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_8021d_get(struct mlxsw_sp *mlxsw_sp, 9798c2ecf20Sopenharmony_ci int br_ifindex) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, &br_ifindex); 9828c2ecf20Sopenharmony_ci} 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_8021q_lookup(struct mlxsw_sp *mlxsw_sp, 9858c2ecf20Sopenharmony_ci u16 vid) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021Q, &vid); 9888c2ecf20Sopenharmony_ci} 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_8021d_lookup(struct mlxsw_sp *mlxsw_sp, 9918c2ecf20Sopenharmony_ci int br_ifindex) 9928c2ecf20Sopenharmony_ci{ 9938c2ecf20Sopenharmony_ci return mlxsw_sp_fid_lookup(mlxsw_sp, MLXSW_SP_FID_TYPE_8021D, 9948c2ecf20Sopenharmony_ci &br_ifindex); 9958c2ecf20Sopenharmony_ci} 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_rfid_get(struct mlxsw_sp *mlxsw_sp, 9988c2ecf20Sopenharmony_ci u16 rif_index) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_RFID, &rif_index); 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistruct mlxsw_sp_fid *mlxsw_sp_fid_dummy_get(struct mlxsw_sp *mlxsw_sp) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci return mlxsw_sp_fid_get(mlxsw_sp, MLXSW_SP_FID_TYPE_DUMMY, NULL); 10068c2ecf20Sopenharmony_ci} 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cistatic int 10098c2ecf20Sopenharmony_cimlxsw_sp_fid_flood_table_init(struct mlxsw_sp_fid_family *fid_family, 10108c2ecf20Sopenharmony_ci const struct mlxsw_sp_flood_table *flood_table) 10118c2ecf20Sopenharmony_ci{ 10128c2ecf20Sopenharmony_ci enum mlxsw_sp_flood_type packet_type = flood_table->packet_type; 10138c2ecf20Sopenharmony_ci const int *sfgc_packet_types; 10148c2ecf20Sopenharmony_ci int i; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci sfgc_packet_types = mlxsw_sp_packet_type_sfgc_types[packet_type]; 10178c2ecf20Sopenharmony_ci for (i = 0; i < MLXSW_REG_SFGC_TYPE_MAX; i++) { 10188c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = fid_family->mlxsw_sp; 10198c2ecf20Sopenharmony_ci char sfgc_pl[MLXSW_REG_SFGC_LEN]; 10208c2ecf20Sopenharmony_ci int err; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci if (!sfgc_packet_types[i]) 10238c2ecf20Sopenharmony_ci continue; 10248c2ecf20Sopenharmony_ci mlxsw_reg_sfgc_pack(sfgc_pl, i, flood_table->bridge_type, 10258c2ecf20Sopenharmony_ci flood_table->table_type, 10268c2ecf20Sopenharmony_ci flood_table->table_index); 10278c2ecf20Sopenharmony_ci err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfgc), sfgc_pl); 10288c2ecf20Sopenharmony_ci if (err) 10298c2ecf20Sopenharmony_ci return err; 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci return 0; 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_cistatic int 10368c2ecf20Sopenharmony_cimlxsw_sp_fid_flood_tables_init(struct mlxsw_sp_fid_family *fid_family) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci int i; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci for (i = 0; i < fid_family->nr_flood_tables; i++) { 10418c2ecf20Sopenharmony_ci const struct mlxsw_sp_flood_table *flood_table; 10428c2ecf20Sopenharmony_ci int err; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci flood_table = &fid_family->flood_tables[i]; 10458c2ecf20Sopenharmony_ci err = mlxsw_sp_fid_flood_table_init(fid_family, flood_table); 10468c2ecf20Sopenharmony_ci if (err) 10478c2ecf20Sopenharmony_ci return err; 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci return 0; 10518c2ecf20Sopenharmony_ci} 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cistatic int mlxsw_sp_fid_family_register(struct mlxsw_sp *mlxsw_sp, 10548c2ecf20Sopenharmony_ci const struct mlxsw_sp_fid_family *tmpl) 10558c2ecf20Sopenharmony_ci{ 10568c2ecf20Sopenharmony_ci u16 nr_fids = tmpl->end_index - tmpl->start_index + 1; 10578c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family; 10588c2ecf20Sopenharmony_ci int err; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci fid_family = kmemdup(tmpl, sizeof(*fid_family), GFP_KERNEL); 10618c2ecf20Sopenharmony_ci if (!fid_family) 10628c2ecf20Sopenharmony_ci return -ENOMEM; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci fid_family->mlxsw_sp = mlxsw_sp; 10658c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&fid_family->fids_list); 10668c2ecf20Sopenharmony_ci fid_family->fids_bitmap = bitmap_zalloc(nr_fids, GFP_KERNEL); 10678c2ecf20Sopenharmony_ci if (!fid_family->fids_bitmap) { 10688c2ecf20Sopenharmony_ci err = -ENOMEM; 10698c2ecf20Sopenharmony_ci goto err_alloc_fids_bitmap; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci if (fid_family->flood_tables) { 10738c2ecf20Sopenharmony_ci err = mlxsw_sp_fid_flood_tables_init(fid_family); 10748c2ecf20Sopenharmony_ci if (err) 10758c2ecf20Sopenharmony_ci goto err_fid_flood_tables_init; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci mlxsw_sp->fid_core->fid_family_arr[tmpl->type] = fid_family; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci return 0; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_cierr_fid_flood_tables_init: 10838c2ecf20Sopenharmony_ci bitmap_free(fid_family->fids_bitmap); 10848c2ecf20Sopenharmony_cierr_alloc_fids_bitmap: 10858c2ecf20Sopenharmony_ci kfree(fid_family); 10868c2ecf20Sopenharmony_ci return err; 10878c2ecf20Sopenharmony_ci} 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_cistatic void 10908c2ecf20Sopenharmony_cimlxsw_sp_fid_family_unregister(struct mlxsw_sp *mlxsw_sp, 10918c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family) 10928c2ecf20Sopenharmony_ci{ 10938c2ecf20Sopenharmony_ci mlxsw_sp->fid_core->fid_family_arr[fid_family->type] = NULL; 10948c2ecf20Sopenharmony_ci bitmap_free(fid_family->fids_bitmap); 10958c2ecf20Sopenharmony_ci WARN_ON_ONCE(!list_empty(&fid_family->fids_list)); 10968c2ecf20Sopenharmony_ci kfree(fid_family); 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ciint mlxsw_sp_port_fids_init(struct mlxsw_sp_port *mlxsw_sp_port) 11008c2ecf20Sopenharmony_ci{ 11018c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci /* Track number of FIDs configured on the port with mapping type 11048c2ecf20Sopenharmony_ci * PORT_VID_TO_FID, so that we know when to transition the port 11058c2ecf20Sopenharmony_ci * back to non-virtual (VLAN) mode. 11068c2ecf20Sopenharmony_ci */ 11078c2ecf20Sopenharmony_ci mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci return mlxsw_sp_port_vp_mode_set(mlxsw_sp_port, false); 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_civoid mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci mlxsw_sp->fid_core->port_fid_mappings[mlxsw_sp_port->local_port] = 0; 11178c2ecf20Sopenharmony_ci} 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ciint mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp) 11208c2ecf20Sopenharmony_ci{ 11218c2ecf20Sopenharmony_ci unsigned int max_ports = mlxsw_core_max_ports(mlxsw_sp->core); 11228c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_core *fid_core; 11238c2ecf20Sopenharmony_ci int err, i; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci fid_core = kzalloc(sizeof(*mlxsw_sp->fid_core), GFP_KERNEL); 11268c2ecf20Sopenharmony_ci if (!fid_core) 11278c2ecf20Sopenharmony_ci return -ENOMEM; 11288c2ecf20Sopenharmony_ci mlxsw_sp->fid_core = fid_core; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci err = rhashtable_init(&fid_core->fid_ht, &mlxsw_sp_fid_ht_params); 11318c2ecf20Sopenharmony_ci if (err) 11328c2ecf20Sopenharmony_ci goto err_rhashtable_fid_init; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci err = rhashtable_init(&fid_core->vni_ht, &mlxsw_sp_fid_vni_ht_params); 11358c2ecf20Sopenharmony_ci if (err) 11368c2ecf20Sopenharmony_ci goto err_rhashtable_vni_init; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci fid_core->port_fid_mappings = kcalloc(max_ports, sizeof(unsigned int), 11398c2ecf20Sopenharmony_ci GFP_KERNEL); 11408c2ecf20Sopenharmony_ci if (!fid_core->port_fid_mappings) { 11418c2ecf20Sopenharmony_ci err = -ENOMEM; 11428c2ecf20Sopenharmony_ci goto err_alloc_port_fid_mappings; 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) { 11468c2ecf20Sopenharmony_ci err = mlxsw_sp_fid_family_register(mlxsw_sp, 11478c2ecf20Sopenharmony_ci mlxsw_sp_fid_family_arr[i]); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci if (err) 11508c2ecf20Sopenharmony_ci goto err_fid_ops_register; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci return 0; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_cierr_fid_ops_register: 11568c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) { 11578c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_family *fid_family; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci fid_family = fid_core->fid_family_arr[i]; 11608c2ecf20Sopenharmony_ci mlxsw_sp_fid_family_unregister(mlxsw_sp, fid_family); 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci kfree(fid_core->port_fid_mappings); 11638c2ecf20Sopenharmony_cierr_alloc_port_fid_mappings: 11648c2ecf20Sopenharmony_ci rhashtable_destroy(&fid_core->vni_ht); 11658c2ecf20Sopenharmony_cierr_rhashtable_vni_init: 11668c2ecf20Sopenharmony_ci rhashtable_destroy(&fid_core->fid_ht); 11678c2ecf20Sopenharmony_cierr_rhashtable_fid_init: 11688c2ecf20Sopenharmony_ci kfree(fid_core); 11698c2ecf20Sopenharmony_ci return err; 11708c2ecf20Sopenharmony_ci} 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_civoid mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp) 11738c2ecf20Sopenharmony_ci{ 11748c2ecf20Sopenharmony_ci struct mlxsw_sp_fid_core *fid_core = mlxsw_sp->fid_core; 11758c2ecf20Sopenharmony_ci int i; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci for (i = 0; i < MLXSW_SP_FID_TYPE_MAX; i++) 11788c2ecf20Sopenharmony_ci mlxsw_sp_fid_family_unregister(mlxsw_sp, 11798c2ecf20Sopenharmony_ci fid_core->fid_family_arr[i]); 11808c2ecf20Sopenharmony_ci kfree(fid_core->port_fid_mappings); 11818c2ecf20Sopenharmony_ci rhashtable_destroy(&fid_core->vni_ht); 11828c2ecf20Sopenharmony_ci rhashtable_destroy(&fid_core->fid_ht); 11838c2ecf20Sopenharmony_ci kfree(fid_core); 11848c2ecf20Sopenharmony_ci} 1185