brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · 50e5914 Raw
307 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */3 4#include <linux/kernel.h>5#include <linux/bitops.h>6#include <linux/spinlock.h>7 8#include "spectrum_cnt.h"9 10struct mlxsw_sp_counter_sub_pool {11	u64 size;12	unsigned int base_index;13	enum mlxsw_res_id entry_size_res_id;14	const char *resource_name; /* devlink resource name */15	u64 resource_id; /* devlink resource id */16	unsigned int entry_size;17	unsigned int bank_count;18	atomic_t active_entries_count;19};20 21struct mlxsw_sp_counter_pool {22	u64 pool_size;23	unsigned long *usage; /* Usage bitmap */24	spinlock_t counter_pool_lock; /* Protects counter pool allocations */25	atomic_t active_entries_count;26	unsigned int sub_pools_count;27	struct mlxsw_sp_counter_sub_pool sub_pools[] __counted_by(sub_pools_count);28};29 30static const struct mlxsw_sp_counter_sub_pool mlxsw_sp_counter_sub_pools[] = {31	[MLXSW_SP_COUNTER_SUB_POOL_FLOW] = {32		.entry_size_res_id = MLXSW_RES_ID_COUNTER_SIZE_PACKETS_BYTES,33		.resource_name = MLXSW_SP_RESOURCE_NAME_COUNTERS_FLOW,34		.resource_id = MLXSW_SP_RESOURCE_COUNTERS_FLOW,35		.bank_count = 6,36	},37	[MLXSW_SP_COUNTER_SUB_POOL_RIF] = {38		.entry_size_res_id = MLXSW_RES_ID_COUNTER_SIZE_ROUTER_BASIC,39		.resource_name = MLXSW_SP_RESOURCE_NAME_COUNTERS_RIF,40		.resource_id = MLXSW_SP_RESOURCE_COUNTERS_RIF,41		.bank_count = 2,42	}43};44 45static u64 mlxsw_sp_counter_sub_pool_occ_get(void *priv)46{47	const struct mlxsw_sp_counter_sub_pool *sub_pool = priv;48 49	return atomic_read(&sub_pool->active_entries_count);50}51 52static int mlxsw_sp_counter_sub_pools_init(struct mlxsw_sp *mlxsw_sp)53{54	struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;55	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);56	struct mlxsw_sp_counter_sub_pool *sub_pool;57	unsigned int base_index = 0;58	enum mlxsw_res_id res_id;59	int err;60	int i;61 62	for (i = 0; i < pool->sub_pools_count; i++) {63		sub_pool = &pool->sub_pools[i];64		res_id = sub_pool->entry_size_res_id;65 66		if (!mlxsw_core_res_valid(mlxsw_sp->core, res_id))67			return -EIO;68		sub_pool->entry_size = mlxsw_core_res_get(mlxsw_sp->core,69							  res_id);70		err = devl_resource_size_get(devlink,71					     sub_pool->resource_id,72					     &sub_pool->size);73		if (err)74			goto err_resource_size_get;75 76		devl_resource_occ_get_register(devlink,77					       sub_pool->resource_id,78					       mlxsw_sp_counter_sub_pool_occ_get,79					       sub_pool);80 81		sub_pool->base_index = base_index;82		base_index += sub_pool->size;83		atomic_set(&sub_pool->active_entries_count, 0);84	}85	return 0;86 87err_resource_size_get:88	for (i--; i >= 0; i--) {89		sub_pool = &pool->sub_pools[i];90 91		devl_resource_occ_get_unregister(devlink,92						 sub_pool->resource_id);93	}94	return err;95}96 97static void mlxsw_sp_counter_sub_pools_fini(struct mlxsw_sp *mlxsw_sp)98{99	struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;100	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);101	struct mlxsw_sp_counter_sub_pool *sub_pool;102	int i;103 104	for (i = 0; i < pool->sub_pools_count; i++) {105		sub_pool = &pool->sub_pools[i];106 107		WARN_ON(atomic_read(&sub_pool->active_entries_count));108		devl_resource_occ_get_unregister(devlink,109						 sub_pool->resource_id);110	}111}112 113static u64 mlxsw_sp_counter_pool_occ_get(void *priv)114{115	const struct mlxsw_sp_counter_pool *pool = priv;116 117	return atomic_read(&pool->active_entries_count);118}119 120int mlxsw_sp_counter_pool_init(struct mlxsw_sp *mlxsw_sp)121{122	unsigned int sub_pools_count = ARRAY_SIZE(mlxsw_sp_counter_sub_pools);123	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);124	struct mlxsw_sp_counter_pool *pool;125	int err;126 127	pool = kzalloc(struct_size(pool, sub_pools, sub_pools_count),128		       GFP_KERNEL);129	if (!pool)130		return -ENOMEM;131	mlxsw_sp->counter_pool = pool;132	pool->sub_pools_count = sub_pools_count;133	memcpy(pool->sub_pools, mlxsw_sp_counter_sub_pools,134	       flex_array_size(pool, sub_pools, pool->sub_pools_count));135	spin_lock_init(&pool->counter_pool_lock);136	atomic_set(&pool->active_entries_count, 0);137 138	err = devl_resource_size_get(devlink, MLXSW_SP_RESOURCE_COUNTERS,139				     &pool->pool_size);140	if (err)141		goto err_pool_resource_size_get;142	devl_resource_occ_get_register(devlink, MLXSW_SP_RESOURCE_COUNTERS,143				       mlxsw_sp_counter_pool_occ_get, pool);144 145	pool->usage = bitmap_zalloc(pool->pool_size, GFP_KERNEL);146	if (!pool->usage) {147		err = -ENOMEM;148		goto err_usage_alloc;149	}150 151	err = mlxsw_sp_counter_sub_pools_init(mlxsw_sp);152	if (err)153		goto err_sub_pools_init;154 155	return 0;156 157err_sub_pools_init:158	bitmap_free(pool->usage);159err_usage_alloc:160	devl_resource_occ_get_unregister(devlink,161					 MLXSW_SP_RESOURCE_COUNTERS);162err_pool_resource_size_get:163	kfree(pool);164	return err;165}166 167void mlxsw_sp_counter_pool_fini(struct mlxsw_sp *mlxsw_sp)168{169	struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;170	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);171 172	mlxsw_sp_counter_sub_pools_fini(mlxsw_sp);173	WARN_ON(find_first_bit(pool->usage, pool->pool_size) !=174			       pool->pool_size);175	WARN_ON(atomic_read(&pool->active_entries_count));176	bitmap_free(pool->usage);177	devl_resource_occ_get_unregister(devlink,178					 MLXSW_SP_RESOURCE_COUNTERS);179	kfree(pool);180}181 182int mlxsw_sp_counter_alloc(struct mlxsw_sp *mlxsw_sp,183			   enum mlxsw_sp_counter_sub_pool_id sub_pool_id,184			   unsigned int *p_counter_index)185{186	struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;187	struct mlxsw_sp_counter_sub_pool *sub_pool;188	unsigned int entry_index;189	unsigned int stop_index;190	int i, err;191 192	sub_pool = &pool->sub_pools[sub_pool_id];193	stop_index = sub_pool->base_index + sub_pool->size;194	entry_index = sub_pool->base_index;195 196	spin_lock(&pool->counter_pool_lock);197	entry_index = find_next_zero_bit(pool->usage, stop_index, entry_index);198	if (entry_index == stop_index) {199		err = -ENOBUFS;200		goto err_alloc;201	}202	/* The sub-pools can contain non-integer number of entries203	 * so we must check for overflow204	 */205	if (entry_index + sub_pool->entry_size > stop_index) {206		err = -ENOBUFS;207		goto err_alloc;208	}209	for (i = 0; i < sub_pool->entry_size; i++)210		__set_bit(entry_index + i, pool->usage);211	spin_unlock(&pool->counter_pool_lock);212 213	*p_counter_index = entry_index;214	atomic_add(sub_pool->entry_size, &sub_pool->active_entries_count);215	atomic_add(sub_pool->entry_size, &pool->active_entries_count);216	return 0;217 218err_alloc:219	spin_unlock(&pool->counter_pool_lock);220	return err;221}222 223void mlxsw_sp_counter_free(struct mlxsw_sp *mlxsw_sp,224			   enum mlxsw_sp_counter_sub_pool_id sub_pool_id,225			   unsigned int counter_index)226{227	struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;228	struct mlxsw_sp_counter_sub_pool *sub_pool;229	int i;230 231	if (WARN_ON(counter_index >= pool->pool_size))232		return;233	sub_pool = &pool->sub_pools[sub_pool_id];234	spin_lock(&pool->counter_pool_lock);235	for (i = 0; i < sub_pool->entry_size; i++)236		__clear_bit(counter_index + i, pool->usage);237	spin_unlock(&pool->counter_pool_lock);238	atomic_sub(sub_pool->entry_size, &sub_pool->active_entries_count);239	atomic_sub(sub_pool->entry_size, &pool->active_entries_count);240}241 242int mlxsw_sp_counter_resources_register(struct mlxsw_core *mlxsw_core)243{244	static struct devlink_resource_size_params size_params;245	struct devlink *devlink = priv_to_devlink(mlxsw_core);246	const struct mlxsw_sp_counter_sub_pool *sub_pool;247	unsigned int total_bank_config;248	u64 sub_pool_size;249	u64 base_index;250	u64 pool_size;251	u64 bank_size;252	int err;253	int i;254 255	if (!MLXSW_CORE_RES_VALID(mlxsw_core, COUNTER_POOL_SIZE) ||256	    !MLXSW_CORE_RES_VALID(mlxsw_core, COUNTER_BANK_SIZE))257		return -EIO;258 259	pool_size = MLXSW_CORE_RES_GET(mlxsw_core, COUNTER_POOL_SIZE);260	bank_size = MLXSW_CORE_RES_GET(mlxsw_core, COUNTER_BANK_SIZE);261 262	devlink_resource_size_params_init(&size_params, pool_size,263					  pool_size, bank_size,264					  DEVLINK_RESOURCE_UNIT_ENTRY);265	err = devl_resource_register(devlink,266				     MLXSW_SP_RESOURCE_NAME_COUNTERS,267				     pool_size,268				     MLXSW_SP_RESOURCE_COUNTERS,269				     DEVLINK_RESOURCE_ID_PARENT_TOP,270				     &size_params);271	if (err)272		return err;273 274	/* Allocation is based on bank count which should be275	 * specified for each sub pool statically.276	 */277	total_bank_config = 0;278	base_index = 0;279	for (i = 0; i < ARRAY_SIZE(mlxsw_sp_counter_sub_pools); i++) {280		sub_pool = &mlxsw_sp_counter_sub_pools[i];281		sub_pool_size = sub_pool->bank_count * bank_size;282		/* The last bank can't be fully used */283		if (base_index + sub_pool_size > pool_size)284			sub_pool_size = pool_size - base_index;285		base_index += sub_pool_size;286 287		devlink_resource_size_params_init(&size_params, sub_pool_size,288						  sub_pool_size, bank_size,289						  DEVLINK_RESOURCE_UNIT_ENTRY);290		err = devl_resource_register(devlink,291					     sub_pool->resource_name,292					     sub_pool_size,293					     sub_pool->resource_id,294					     MLXSW_SP_RESOURCE_COUNTERS,295					     &size_params);296		if (err)297			return err;298		total_bank_config += sub_pool->bank_count;299	}300 301	/* Check config is valid, no bank over subscription */302	if (WARN_ON(total_bank_config > div64_u64(pool_size, bank_size) + 1))303		return -EINVAL;304 305	return 0;306}307