18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright (c) 2020 Mellanox Technologies. All rights reserved */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/idr.h> 58c2ecf20Sopenharmony_ci#include <linux/log2.h> 68c2ecf20Sopenharmony_ci#include <linux/mutex.h> 78c2ecf20Sopenharmony_ci#include <linux/netlink.h> 88c2ecf20Sopenharmony_ci#include <net/devlink.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "spectrum.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_cistruct mlxsw_sp_policer_family { 138c2ecf20Sopenharmony_ci enum mlxsw_sp_policer_type type; 148c2ecf20Sopenharmony_ci enum mlxsw_reg_qpcr_g qpcr_type; 158c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp; 168c2ecf20Sopenharmony_ci u16 start_index; /* Inclusive */ 178c2ecf20Sopenharmony_ci u16 end_index; /* Exclusive */ 188c2ecf20Sopenharmony_ci struct idr policer_idr; 198c2ecf20Sopenharmony_ci struct mutex lock; /* Protects policer_idr */ 208c2ecf20Sopenharmony_ci atomic_t policers_count; 218c2ecf20Sopenharmony_ci const struct mlxsw_sp_policer_family_ops *ops; 228c2ecf20Sopenharmony_ci}; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct mlxsw_sp_policer { 258c2ecf20Sopenharmony_ci struct mlxsw_sp_policer_params params; 268c2ecf20Sopenharmony_ci u16 index; 278c2ecf20Sopenharmony_ci}; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistruct mlxsw_sp_policer_family_ops { 308c2ecf20Sopenharmony_ci int (*init)(struct mlxsw_sp_policer_family *family); 318c2ecf20Sopenharmony_ci void (*fini)(struct mlxsw_sp_policer_family *family); 328c2ecf20Sopenharmony_ci int (*policer_index_alloc)(struct mlxsw_sp_policer_family *family, 338c2ecf20Sopenharmony_ci struct mlxsw_sp_policer *policer); 348c2ecf20Sopenharmony_ci struct mlxsw_sp_policer * (*policer_index_free)(struct mlxsw_sp_policer_family *family, 358c2ecf20Sopenharmony_ci u16 policer_index); 368c2ecf20Sopenharmony_ci int (*policer_init)(struct mlxsw_sp_policer_family *family, 378c2ecf20Sopenharmony_ci const struct mlxsw_sp_policer *policer); 388c2ecf20Sopenharmony_ci int (*policer_params_check)(const struct mlxsw_sp_policer_family *family, 398c2ecf20Sopenharmony_ci const struct mlxsw_sp_policer_params *params, 408c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack); 418c2ecf20Sopenharmony_ci}; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct mlxsw_sp_policer_core { 448c2ecf20Sopenharmony_ci struct mlxsw_sp_policer_family *family_arr[MLXSW_SP_POLICER_TYPE_MAX + 1]; 458c2ecf20Sopenharmony_ci const struct mlxsw_sp_policer_core_ops *ops; 468c2ecf20Sopenharmony_ci u8 lowest_bs_bits; 478c2ecf20Sopenharmony_ci u8 highest_bs_bits; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistruct mlxsw_sp_policer_core_ops { 518c2ecf20Sopenharmony_ci int (*init)(struct mlxsw_sp_policer_core *policer_core); 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic u64 mlxsw_sp_policer_rate_bytes_ps_kbps(u64 rate_bytes_ps) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci return div_u64(rate_bytes_ps, 1000) * BITS_PER_BYTE; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic u8 mlxsw_sp_policer_burst_bytes_hw_units(u64 burst_bytes) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci /* Provided burst size is in bytes. The ASIC burst size value is 628c2ecf20Sopenharmony_ci * (2 ^ bs) * 512 bits. Convert the provided size to 512-bit units. 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci u64 bs512 = div_u64(burst_bytes, 64); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (!bs512) 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci return fls64(bs512) - 1; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic u64 mlxsw_sp_policer_single_rate_occ_get(void *priv) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct mlxsw_sp_policer_family *family = priv; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return atomic_read(&family->policers_count); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int 808c2ecf20Sopenharmony_cimlxsw_sp_policer_single_rate_family_init(struct mlxsw_sp_policer_family *family) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct mlxsw_core *core = family->mlxsw_sp->core; 838c2ecf20Sopenharmony_ci struct devlink *devlink; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* CPU policers are allocated from the first N policers in the global 868c2ecf20Sopenharmony_ci * range, so skip them. 878c2ecf20Sopenharmony_ci */ 888c2ecf20Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(core, MAX_GLOBAL_POLICERS) || 898c2ecf20Sopenharmony_ci !MLXSW_CORE_RES_VALID(core, MAX_CPU_POLICERS)) 908c2ecf20Sopenharmony_ci return -EIO; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci family->start_index = MLXSW_CORE_RES_GET(core, MAX_CPU_POLICERS); 938c2ecf20Sopenharmony_ci family->end_index = MLXSW_CORE_RES_GET(core, MAX_GLOBAL_POLICERS); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci atomic_set(&family->policers_count, 0); 968c2ecf20Sopenharmony_ci devlink = priv_to_devlink(core); 978c2ecf20Sopenharmony_ci devlink_resource_occ_get_register(devlink, 988c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS, 998c2ecf20Sopenharmony_ci mlxsw_sp_policer_single_rate_occ_get, 1008c2ecf20Sopenharmony_ci family); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic void 1068c2ecf20Sopenharmony_cimlxsw_sp_policer_single_rate_family_fini(struct mlxsw_sp_policer_family *family) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci struct devlink *devlink = priv_to_devlink(family->mlxsw_sp->core); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci devlink_resource_occ_get_unregister(devlink, 1118c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS); 1128c2ecf20Sopenharmony_ci WARN_ON(atomic_read(&family->policers_count) != 0); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int 1168c2ecf20Sopenharmony_cimlxsw_sp_policer_single_rate_index_alloc(struct mlxsw_sp_policer_family *family, 1178c2ecf20Sopenharmony_ci struct mlxsw_sp_policer *policer) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci int id; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci mutex_lock(&family->lock); 1228c2ecf20Sopenharmony_ci id = idr_alloc(&family->policer_idr, policer, family->start_index, 1238c2ecf20Sopenharmony_ci family->end_index, GFP_KERNEL); 1248c2ecf20Sopenharmony_ci mutex_unlock(&family->lock); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (id < 0) 1278c2ecf20Sopenharmony_ci return id; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci atomic_inc(&family->policers_count); 1308c2ecf20Sopenharmony_ci policer->index = id; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic struct mlxsw_sp_policer * 1368c2ecf20Sopenharmony_cimlxsw_sp_policer_single_rate_index_free(struct mlxsw_sp_policer_family *family, 1378c2ecf20Sopenharmony_ci u16 policer_index) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci struct mlxsw_sp_policer *policer; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci atomic_dec(&family->policers_count); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci mutex_lock(&family->lock); 1448c2ecf20Sopenharmony_ci policer = idr_remove(&family->policer_idr, policer_index); 1458c2ecf20Sopenharmony_ci mutex_unlock(&family->lock); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci WARN_ON(!policer); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci return policer; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic int 1538c2ecf20Sopenharmony_cimlxsw_sp_policer_single_rate_init(struct mlxsw_sp_policer_family *family, 1548c2ecf20Sopenharmony_ci const struct mlxsw_sp_policer *policer) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci u64 rate_kbps = mlxsw_sp_policer_rate_bytes_ps_kbps(policer->params.rate); 1578c2ecf20Sopenharmony_ci u8 bs = mlxsw_sp_policer_burst_bytes_hw_units(policer->params.burst); 1588c2ecf20Sopenharmony_ci struct mlxsw_sp *mlxsw_sp = family->mlxsw_sp; 1598c2ecf20Sopenharmony_ci char qpcr_pl[MLXSW_REG_QPCR_LEN]; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci mlxsw_reg_qpcr_pack(qpcr_pl, policer->index, MLXSW_REG_QPCR_IR_UNITS_K, 1628c2ecf20Sopenharmony_ci true, rate_kbps, bs); 1638c2ecf20Sopenharmony_ci mlxsw_reg_qpcr_clear_counter_set(qpcr_pl, true); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int 1698c2ecf20Sopenharmony_cimlxsw_sp_policer_single_rate_params_check(const struct mlxsw_sp_policer_family *family, 1708c2ecf20Sopenharmony_ci const struct mlxsw_sp_policer_params *params, 1718c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct mlxsw_sp_policer_core *policer_core = family->mlxsw_sp->policer_core; 1748c2ecf20Sopenharmony_ci u64 rate_bps = params->rate * BITS_PER_BYTE; 1758c2ecf20Sopenharmony_ci u8 bs; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (!params->bytes) { 1788c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Only bandwidth policing is currently supported by single rate policers"); 1798c2ecf20Sopenharmony_ci return -EINVAL; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (!is_power_of_2(params->burst)) { 1838c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Policer burst size is not power of two"); 1848c2ecf20Sopenharmony_ci return -EINVAL; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci bs = mlxsw_sp_policer_burst_bytes_hw_units(params->burst); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (bs < policer_core->lowest_bs_bits) { 1908c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Policer burst size lower than limit"); 1918c2ecf20Sopenharmony_ci return -EINVAL; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (bs > policer_core->highest_bs_bits) { 1958c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Policer burst size higher than limit"); 1968c2ecf20Sopenharmony_ci return -EINVAL; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (rate_bps < MLXSW_REG_QPCR_LOWEST_CIR_BITS) { 2008c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Policer rate lower than limit"); 2018c2ecf20Sopenharmony_ci return -EINVAL; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (rate_bps > MLXSW_REG_QPCR_HIGHEST_CIR_BITS) { 2058c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Policer rate higher than limit"); 2068c2ecf20Sopenharmony_ci return -EINVAL; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci return 0; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_policer_family_ops mlxsw_sp_policer_single_rate_ops = { 2138c2ecf20Sopenharmony_ci .init = mlxsw_sp_policer_single_rate_family_init, 2148c2ecf20Sopenharmony_ci .fini = mlxsw_sp_policer_single_rate_family_fini, 2158c2ecf20Sopenharmony_ci .policer_index_alloc = mlxsw_sp_policer_single_rate_index_alloc, 2168c2ecf20Sopenharmony_ci .policer_index_free = mlxsw_sp_policer_single_rate_index_free, 2178c2ecf20Sopenharmony_ci .policer_init = mlxsw_sp_policer_single_rate_init, 2188c2ecf20Sopenharmony_ci .policer_params_check = mlxsw_sp_policer_single_rate_params_check, 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_policer_family mlxsw_sp_policer_single_rate_family = { 2228c2ecf20Sopenharmony_ci .type = MLXSW_SP_POLICER_TYPE_SINGLE_RATE, 2238c2ecf20Sopenharmony_ci .qpcr_type = MLXSW_REG_QPCR_G_GLOBAL, 2248c2ecf20Sopenharmony_ci .ops = &mlxsw_sp_policer_single_rate_ops, 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic const struct mlxsw_sp_policer_family *mlxsw_sp_policer_family_arr[] = { 2288c2ecf20Sopenharmony_ci [MLXSW_SP_POLICER_TYPE_SINGLE_RATE] = &mlxsw_sp_policer_single_rate_family, 2298c2ecf20Sopenharmony_ci}; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ciint mlxsw_sp_policer_add(struct mlxsw_sp *mlxsw_sp, 2328c2ecf20Sopenharmony_ci enum mlxsw_sp_policer_type type, 2338c2ecf20Sopenharmony_ci const struct mlxsw_sp_policer_params *params, 2348c2ecf20Sopenharmony_ci struct netlink_ext_ack *extack, u16 *p_policer_index) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct mlxsw_sp_policer_family *family; 2378c2ecf20Sopenharmony_ci struct mlxsw_sp_policer *policer; 2388c2ecf20Sopenharmony_ci int err; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci family = mlxsw_sp->policer_core->family_arr[type]; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci err = family->ops->policer_params_check(family, params, extack); 2438c2ecf20Sopenharmony_ci if (err) 2448c2ecf20Sopenharmony_ci return err; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci policer = kmalloc(sizeof(*policer), GFP_KERNEL); 2478c2ecf20Sopenharmony_ci if (!policer) 2488c2ecf20Sopenharmony_ci return -ENOMEM; 2498c2ecf20Sopenharmony_ci policer->params = *params; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci err = family->ops->policer_index_alloc(family, policer); 2528c2ecf20Sopenharmony_ci if (err) { 2538c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to allocate policer index"); 2548c2ecf20Sopenharmony_ci goto err_policer_index_alloc; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci err = family->ops->policer_init(family, policer); 2588c2ecf20Sopenharmony_ci if (err) { 2598c2ecf20Sopenharmony_ci NL_SET_ERR_MSG_MOD(extack, "Failed to initialize policer"); 2608c2ecf20Sopenharmony_ci goto err_policer_init; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci *p_policer_index = policer->index; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cierr_policer_init: 2688c2ecf20Sopenharmony_ci family->ops->policer_index_free(family, policer->index); 2698c2ecf20Sopenharmony_cierr_policer_index_alloc: 2708c2ecf20Sopenharmony_ci kfree(policer); 2718c2ecf20Sopenharmony_ci return err; 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_civoid mlxsw_sp_policer_del(struct mlxsw_sp *mlxsw_sp, 2758c2ecf20Sopenharmony_ci enum mlxsw_sp_policer_type type, u16 policer_index) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci struct mlxsw_sp_policer_family *family; 2788c2ecf20Sopenharmony_ci struct mlxsw_sp_policer *policer; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci family = mlxsw_sp->policer_core->family_arr[type]; 2818c2ecf20Sopenharmony_ci policer = family->ops->policer_index_free(family, policer_index); 2828c2ecf20Sopenharmony_ci kfree(policer); 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ciint mlxsw_sp_policer_drops_counter_get(struct mlxsw_sp *mlxsw_sp, 2868c2ecf20Sopenharmony_ci enum mlxsw_sp_policer_type type, 2878c2ecf20Sopenharmony_ci u16 policer_index, u64 *p_drops) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct mlxsw_sp_policer_family *family; 2908c2ecf20Sopenharmony_ci char qpcr_pl[MLXSW_REG_QPCR_LEN]; 2918c2ecf20Sopenharmony_ci int err; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci family = mlxsw_sp->policer_core->family_arr[type]; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci MLXSW_REG_ZERO(qpcr, qpcr_pl); 2968c2ecf20Sopenharmony_ci mlxsw_reg_qpcr_pid_set(qpcr_pl, policer_index); 2978c2ecf20Sopenharmony_ci mlxsw_reg_qpcr_g_set(qpcr_pl, family->qpcr_type); 2988c2ecf20Sopenharmony_ci err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(qpcr), qpcr_pl); 2998c2ecf20Sopenharmony_ci if (err) 3008c2ecf20Sopenharmony_ci return err; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci *p_drops = mlxsw_reg_qpcr_violate_count_get(qpcr_pl); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return 0; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int 3088c2ecf20Sopenharmony_cimlxsw_sp_policer_family_register(struct mlxsw_sp *mlxsw_sp, 3098c2ecf20Sopenharmony_ci const struct mlxsw_sp_policer_family *tmpl) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct mlxsw_sp_policer_family *family; 3128c2ecf20Sopenharmony_ci int err; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci family = kmemdup(tmpl, sizeof(*family), GFP_KERNEL); 3158c2ecf20Sopenharmony_ci if (!family) 3168c2ecf20Sopenharmony_ci return -ENOMEM; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci family->mlxsw_sp = mlxsw_sp; 3198c2ecf20Sopenharmony_ci idr_init(&family->policer_idr); 3208c2ecf20Sopenharmony_ci mutex_init(&family->lock); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci err = family->ops->init(family); 3238c2ecf20Sopenharmony_ci if (err) 3248c2ecf20Sopenharmony_ci goto err_family_init; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (WARN_ON(family->start_index >= family->end_index)) { 3278c2ecf20Sopenharmony_ci err = -EINVAL; 3288c2ecf20Sopenharmony_ci goto err_index_check; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci mlxsw_sp->policer_core->family_arr[tmpl->type] = family; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci return 0; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cierr_index_check: 3368c2ecf20Sopenharmony_ci family->ops->fini(family); 3378c2ecf20Sopenharmony_cierr_family_init: 3388c2ecf20Sopenharmony_ci mutex_destroy(&family->lock); 3398c2ecf20Sopenharmony_ci idr_destroy(&family->policer_idr); 3408c2ecf20Sopenharmony_ci kfree(family); 3418c2ecf20Sopenharmony_ci return err; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic void 3458c2ecf20Sopenharmony_cimlxsw_sp_policer_family_unregister(struct mlxsw_sp *mlxsw_sp, 3468c2ecf20Sopenharmony_ci struct mlxsw_sp_policer_family *family) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci family->ops->fini(family); 3498c2ecf20Sopenharmony_ci mutex_destroy(&family->lock); 3508c2ecf20Sopenharmony_ci WARN_ON(!idr_is_empty(&family->policer_idr)); 3518c2ecf20Sopenharmony_ci idr_destroy(&family->policer_idr); 3528c2ecf20Sopenharmony_ci kfree(family); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ciint mlxsw_sp_policers_init(struct mlxsw_sp *mlxsw_sp) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct mlxsw_sp_policer_core *policer_core; 3588c2ecf20Sopenharmony_ci int i, err; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci policer_core = kzalloc(sizeof(*policer_core), GFP_KERNEL); 3618c2ecf20Sopenharmony_ci if (!policer_core) 3628c2ecf20Sopenharmony_ci return -ENOMEM; 3638c2ecf20Sopenharmony_ci mlxsw_sp->policer_core = policer_core; 3648c2ecf20Sopenharmony_ci policer_core->ops = mlxsw_sp->policer_core_ops; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci err = policer_core->ops->init(policer_core); 3678c2ecf20Sopenharmony_ci if (err) 3688c2ecf20Sopenharmony_ci goto err_init; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci for (i = 0; i < MLXSW_SP_POLICER_TYPE_MAX + 1; i++) { 3718c2ecf20Sopenharmony_ci err = mlxsw_sp_policer_family_register(mlxsw_sp, mlxsw_sp_policer_family_arr[i]); 3728c2ecf20Sopenharmony_ci if (err) 3738c2ecf20Sopenharmony_ci goto err_family_register; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return 0; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cierr_family_register: 3798c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) { 3808c2ecf20Sopenharmony_ci struct mlxsw_sp_policer_family *family; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci family = mlxsw_sp->policer_core->family_arr[i]; 3838c2ecf20Sopenharmony_ci mlxsw_sp_policer_family_unregister(mlxsw_sp, family); 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_cierr_init: 3868c2ecf20Sopenharmony_ci kfree(mlxsw_sp->policer_core); 3878c2ecf20Sopenharmony_ci return err; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_civoid mlxsw_sp_policers_fini(struct mlxsw_sp *mlxsw_sp) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci int i; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci for (i = MLXSW_SP_POLICER_TYPE_MAX; i >= 0; i--) { 3958c2ecf20Sopenharmony_ci struct mlxsw_sp_policer_family *family; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci family = mlxsw_sp->policer_core->family_arr[i]; 3988c2ecf20Sopenharmony_ci mlxsw_sp_policer_family_unregister(mlxsw_sp, family); 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci kfree(mlxsw_sp->policer_core); 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ciint mlxsw_sp_policer_resources_register(struct mlxsw_core *mlxsw_core) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci u64 global_policers, cpu_policers, single_rate_policers; 4078c2ecf20Sopenharmony_ci struct devlink *devlink = priv_to_devlink(mlxsw_core); 4088c2ecf20Sopenharmony_ci struct devlink_resource_size_params size_params; 4098c2ecf20Sopenharmony_ci int err; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if (!MLXSW_CORE_RES_VALID(mlxsw_core, MAX_GLOBAL_POLICERS) || 4128c2ecf20Sopenharmony_ci !MLXSW_CORE_RES_VALID(mlxsw_core, MAX_CPU_POLICERS)) 4138c2ecf20Sopenharmony_ci return -EIO; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci global_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_GLOBAL_POLICERS); 4168c2ecf20Sopenharmony_ci cpu_policers = MLXSW_CORE_RES_GET(mlxsw_core, MAX_CPU_POLICERS); 4178c2ecf20Sopenharmony_ci single_rate_policers = global_policers - cpu_policers; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci devlink_resource_size_params_init(&size_params, global_policers, 4208c2ecf20Sopenharmony_ci global_policers, 1, 4218c2ecf20Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 4228c2ecf20Sopenharmony_ci err = devlink_resource_register(devlink, "global_policers", 4238c2ecf20Sopenharmony_ci global_policers, 4248c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_GLOBAL_POLICERS, 4258c2ecf20Sopenharmony_ci DEVLINK_RESOURCE_ID_PARENT_TOP, 4268c2ecf20Sopenharmony_ci &size_params); 4278c2ecf20Sopenharmony_ci if (err) 4288c2ecf20Sopenharmony_ci return err; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci devlink_resource_size_params_init(&size_params, single_rate_policers, 4318c2ecf20Sopenharmony_ci single_rate_policers, 1, 4328c2ecf20Sopenharmony_ci DEVLINK_RESOURCE_UNIT_ENTRY); 4338c2ecf20Sopenharmony_ci err = devlink_resource_register(devlink, "single_rate_policers", 4348c2ecf20Sopenharmony_ci single_rate_policers, 4358c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_SINGLE_RATE_POLICERS, 4368c2ecf20Sopenharmony_ci MLXSW_SP_RESOURCE_GLOBAL_POLICERS, 4378c2ecf20Sopenharmony_ci &size_params); 4388c2ecf20Sopenharmony_ci if (err) 4398c2ecf20Sopenharmony_ci return err; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci return 0; 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int 4458c2ecf20Sopenharmony_cimlxsw_sp1_policer_core_init(struct mlxsw_sp_policer_core *policer_core) 4468c2ecf20Sopenharmony_ci{ 4478c2ecf20Sopenharmony_ci policer_core->lowest_bs_bits = MLXSW_REG_QPCR_LOWEST_CBS_BITS_SP1; 4488c2ecf20Sopenharmony_ci policer_core->highest_bs_bits = MLXSW_REG_QPCR_HIGHEST_CBS_BITS_SP1; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ciconst struct mlxsw_sp_policer_core_ops mlxsw_sp1_policer_core_ops = { 4548c2ecf20Sopenharmony_ci .init = mlxsw_sp1_policer_core_init, 4558c2ecf20Sopenharmony_ci}; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic int 4588c2ecf20Sopenharmony_cimlxsw_sp2_policer_core_init(struct mlxsw_sp_policer_core *policer_core) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci policer_core->lowest_bs_bits = MLXSW_REG_QPCR_LOWEST_CBS_BITS_SP2; 4618c2ecf20Sopenharmony_ci policer_core->highest_bs_bits = MLXSW_REG_QPCR_HIGHEST_CBS_BITS_SP2; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci return 0; 4648c2ecf20Sopenharmony_ci} 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ciconst struct mlxsw_sp_policer_core_ops mlxsw_sp2_policer_core_ops = { 4678c2ecf20Sopenharmony_ci .init = mlxsw_sp2_policer_core_init, 4688c2ecf20Sopenharmony_ci}; 469