Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
0003 
0004 #include <linux/kernel.h>
0005 #include <linux/bitops.h>
0006 #include <linux/spinlock.h>
0007 
0008 #include "spectrum_cnt.h"
0009 
0010 struct mlxsw_sp_counter_sub_pool {
0011     u64 size;
0012     unsigned int base_index;
0013     enum mlxsw_res_id entry_size_res_id;
0014     const char *resource_name; /* devlink resource name */
0015     u64 resource_id; /* devlink resource id */
0016     unsigned int entry_size;
0017     unsigned int bank_count;
0018     atomic_t active_entries_count;
0019 };
0020 
0021 struct mlxsw_sp_counter_pool {
0022     u64 pool_size;
0023     unsigned long *usage; /* Usage bitmap */
0024     spinlock_t counter_pool_lock; /* Protects counter pool allocations */
0025     atomic_t active_entries_count;
0026     unsigned int sub_pools_count;
0027     struct mlxsw_sp_counter_sub_pool sub_pools[];
0028 };
0029 
0030 static const struct mlxsw_sp_counter_sub_pool mlxsw_sp_counter_sub_pools[] = {
0031     [MLXSW_SP_COUNTER_SUB_POOL_FLOW] = {
0032         .entry_size_res_id = MLXSW_RES_ID_COUNTER_SIZE_PACKETS_BYTES,
0033         .resource_name = MLXSW_SP_RESOURCE_NAME_COUNTERS_FLOW,
0034         .resource_id = MLXSW_SP_RESOURCE_COUNTERS_FLOW,
0035         .bank_count = 6,
0036     },
0037     [MLXSW_SP_COUNTER_SUB_POOL_RIF] = {
0038         .entry_size_res_id = MLXSW_RES_ID_COUNTER_SIZE_ROUTER_BASIC,
0039         .resource_name = MLXSW_SP_RESOURCE_NAME_COUNTERS_RIF,
0040         .resource_id = MLXSW_SP_RESOURCE_COUNTERS_RIF,
0041         .bank_count = 2,
0042     }
0043 };
0044 
0045 static u64 mlxsw_sp_counter_sub_pool_occ_get(void *priv)
0046 {
0047     const struct mlxsw_sp_counter_sub_pool *sub_pool = priv;
0048 
0049     return atomic_read(&sub_pool->active_entries_count);
0050 }
0051 
0052 static int mlxsw_sp_counter_sub_pools_init(struct mlxsw_sp *mlxsw_sp)
0053 {
0054     struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;
0055     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
0056     struct mlxsw_sp_counter_sub_pool *sub_pool;
0057     unsigned int base_index = 0;
0058     enum mlxsw_res_id res_id;
0059     int err;
0060     int i;
0061 
0062     for (i = 0; i < pool->sub_pools_count; i++) {
0063         sub_pool = &pool->sub_pools[i];
0064         res_id = sub_pool->entry_size_res_id;
0065 
0066         if (!mlxsw_core_res_valid(mlxsw_sp->core, res_id))
0067             return -EIO;
0068         sub_pool->entry_size = mlxsw_core_res_get(mlxsw_sp->core,
0069                               res_id);
0070         err = devl_resource_size_get(devlink,
0071                          sub_pool->resource_id,
0072                          &sub_pool->size);
0073         if (err)
0074             goto err_resource_size_get;
0075 
0076         devl_resource_occ_get_register(devlink,
0077                            sub_pool->resource_id,
0078                            mlxsw_sp_counter_sub_pool_occ_get,
0079                            sub_pool);
0080 
0081         sub_pool->base_index = base_index;
0082         base_index += sub_pool->size;
0083         atomic_set(&sub_pool->active_entries_count, 0);
0084     }
0085     return 0;
0086 
0087 err_resource_size_get:
0088     for (i--; i >= 0; i--) {
0089         sub_pool = &pool->sub_pools[i];
0090 
0091         devl_resource_occ_get_unregister(devlink,
0092                          sub_pool->resource_id);
0093     }
0094     return err;
0095 }
0096 
0097 static void mlxsw_sp_counter_sub_pools_fini(struct mlxsw_sp *mlxsw_sp)
0098 {
0099     struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;
0100     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
0101     struct mlxsw_sp_counter_sub_pool *sub_pool;
0102     int i;
0103 
0104     for (i = 0; i < pool->sub_pools_count; i++) {
0105         sub_pool = &pool->sub_pools[i];
0106 
0107         WARN_ON(atomic_read(&sub_pool->active_entries_count));
0108         devl_resource_occ_get_unregister(devlink,
0109                          sub_pool->resource_id);
0110     }
0111 }
0112 
0113 static u64 mlxsw_sp_counter_pool_occ_get(void *priv)
0114 {
0115     const struct mlxsw_sp_counter_pool *pool = priv;
0116 
0117     return atomic_read(&pool->active_entries_count);
0118 }
0119 
0120 int mlxsw_sp_counter_pool_init(struct mlxsw_sp *mlxsw_sp)
0121 {
0122     unsigned int sub_pools_count = ARRAY_SIZE(mlxsw_sp_counter_sub_pools);
0123     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
0124     struct mlxsw_sp_counter_pool *pool;
0125     int err;
0126 
0127     pool = kzalloc(struct_size(pool, sub_pools, sub_pools_count),
0128                GFP_KERNEL);
0129     if (!pool)
0130         return -ENOMEM;
0131     mlxsw_sp->counter_pool = pool;
0132     pool->sub_pools_count = sub_pools_count;
0133     memcpy(pool->sub_pools, mlxsw_sp_counter_sub_pools,
0134            flex_array_size(pool, sub_pools, pool->sub_pools_count));
0135     spin_lock_init(&pool->counter_pool_lock);
0136     atomic_set(&pool->active_entries_count, 0);
0137 
0138     err = devl_resource_size_get(devlink, MLXSW_SP_RESOURCE_COUNTERS,
0139                      &pool->pool_size);
0140     if (err)
0141         goto err_pool_resource_size_get;
0142     devl_resource_occ_get_register(devlink, MLXSW_SP_RESOURCE_COUNTERS,
0143                        mlxsw_sp_counter_pool_occ_get, pool);
0144 
0145     pool->usage = bitmap_zalloc(pool->pool_size, GFP_KERNEL);
0146     if (!pool->usage) {
0147         err = -ENOMEM;
0148         goto err_usage_alloc;
0149     }
0150 
0151     err = mlxsw_sp_counter_sub_pools_init(mlxsw_sp);
0152     if (err)
0153         goto err_sub_pools_init;
0154 
0155     return 0;
0156 
0157 err_sub_pools_init:
0158     bitmap_free(pool->usage);
0159 err_usage_alloc:
0160     devl_resource_occ_get_unregister(devlink,
0161                      MLXSW_SP_RESOURCE_COUNTERS);
0162 err_pool_resource_size_get:
0163     kfree(pool);
0164     return err;
0165 }
0166 
0167 void mlxsw_sp_counter_pool_fini(struct mlxsw_sp *mlxsw_sp)
0168 {
0169     struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;
0170     struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
0171 
0172     mlxsw_sp_counter_sub_pools_fini(mlxsw_sp);
0173     WARN_ON(find_first_bit(pool->usage, pool->pool_size) !=
0174                    pool->pool_size);
0175     WARN_ON(atomic_read(&pool->active_entries_count));
0176     bitmap_free(pool->usage);
0177     devl_resource_occ_get_unregister(devlink,
0178                      MLXSW_SP_RESOURCE_COUNTERS);
0179     kfree(pool);
0180 }
0181 
0182 int mlxsw_sp_counter_alloc(struct mlxsw_sp *mlxsw_sp,
0183                enum mlxsw_sp_counter_sub_pool_id sub_pool_id,
0184                unsigned int *p_counter_index)
0185 {
0186     struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;
0187     struct mlxsw_sp_counter_sub_pool *sub_pool;
0188     unsigned int entry_index;
0189     unsigned int stop_index;
0190     int i, err;
0191 
0192     sub_pool = &pool->sub_pools[sub_pool_id];
0193     stop_index = sub_pool->base_index + sub_pool->size;
0194     entry_index = sub_pool->base_index;
0195 
0196     spin_lock(&pool->counter_pool_lock);
0197     entry_index = find_next_zero_bit(pool->usage, stop_index, entry_index);
0198     if (entry_index == stop_index) {
0199         err = -ENOBUFS;
0200         goto err_alloc;
0201     }
0202     /* The sub-pools can contain non-integer number of entries
0203      * so we must check for overflow
0204      */
0205     if (entry_index + sub_pool->entry_size > stop_index) {
0206         err = -ENOBUFS;
0207         goto err_alloc;
0208     }
0209     for (i = 0; i < sub_pool->entry_size; i++)
0210         __set_bit(entry_index + i, pool->usage);
0211     spin_unlock(&pool->counter_pool_lock);
0212 
0213     *p_counter_index = entry_index;
0214     atomic_add(sub_pool->entry_size, &sub_pool->active_entries_count);
0215     atomic_add(sub_pool->entry_size, &pool->active_entries_count);
0216     return 0;
0217 
0218 err_alloc:
0219     spin_unlock(&pool->counter_pool_lock);
0220     return err;
0221 }
0222 
0223 void mlxsw_sp_counter_free(struct mlxsw_sp *mlxsw_sp,
0224                enum mlxsw_sp_counter_sub_pool_id sub_pool_id,
0225                unsigned int counter_index)
0226 {
0227     struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;
0228     struct mlxsw_sp_counter_sub_pool *sub_pool;
0229     int i;
0230 
0231     if (WARN_ON(counter_index >= pool->pool_size))
0232         return;
0233     sub_pool = &pool->sub_pools[sub_pool_id];
0234     spin_lock(&pool->counter_pool_lock);
0235     for (i = 0; i < sub_pool->entry_size; i++)
0236         __clear_bit(counter_index + i, pool->usage);
0237     spin_unlock(&pool->counter_pool_lock);
0238     atomic_sub(sub_pool->entry_size, &sub_pool->active_entries_count);
0239     atomic_sub(sub_pool->entry_size, &pool->active_entries_count);
0240 }
0241 
0242 int mlxsw_sp_counter_resources_register(struct mlxsw_core *mlxsw_core)
0243 {
0244     static struct devlink_resource_size_params size_params;
0245     struct devlink *devlink = priv_to_devlink(mlxsw_core);
0246     const struct mlxsw_sp_counter_sub_pool *sub_pool;
0247     unsigned int total_bank_config;
0248     u64 sub_pool_size;
0249     u64 base_index;
0250     u64 pool_size;
0251     u64 bank_size;
0252     int err;
0253     int i;
0254 
0255     if (!MLXSW_CORE_RES_VALID(mlxsw_core, COUNTER_POOL_SIZE) ||
0256         !MLXSW_CORE_RES_VALID(mlxsw_core, COUNTER_BANK_SIZE))
0257         return -EIO;
0258 
0259     pool_size = MLXSW_CORE_RES_GET(mlxsw_core, COUNTER_POOL_SIZE);
0260     bank_size = MLXSW_CORE_RES_GET(mlxsw_core, COUNTER_BANK_SIZE);
0261 
0262     devlink_resource_size_params_init(&size_params, pool_size,
0263                       pool_size, bank_size,
0264                       DEVLINK_RESOURCE_UNIT_ENTRY);
0265     err = devl_resource_register(devlink,
0266                      MLXSW_SP_RESOURCE_NAME_COUNTERS,
0267                      pool_size,
0268                      MLXSW_SP_RESOURCE_COUNTERS,
0269                      DEVLINK_RESOURCE_ID_PARENT_TOP,
0270                      &size_params);
0271     if (err)
0272         return err;
0273 
0274     /* Allocation is based on bank count which should be
0275      * specified for each sub pool statically.
0276      */
0277     total_bank_config = 0;
0278     base_index = 0;
0279     for (i = 0; i < ARRAY_SIZE(mlxsw_sp_counter_sub_pools); i++) {
0280         sub_pool = &mlxsw_sp_counter_sub_pools[i];
0281         sub_pool_size = sub_pool->bank_count * bank_size;
0282         /* The last bank can't be fully used */
0283         if (base_index + sub_pool_size > pool_size)
0284             sub_pool_size = pool_size - base_index;
0285         base_index += sub_pool_size;
0286 
0287         devlink_resource_size_params_init(&size_params, sub_pool_size,
0288                           sub_pool_size, bank_size,
0289                           DEVLINK_RESOURCE_UNIT_ENTRY);
0290         err = devl_resource_register(devlink,
0291                          sub_pool->resource_name,
0292                          sub_pool_size,
0293                          sub_pool->resource_id,
0294                          MLXSW_SP_RESOURCE_COUNTERS,
0295                          &size_params);
0296         if (err)
0297             return err;
0298         total_bank_config += sub_pool->bank_count;
0299     }
0300 
0301     /* Check config is valid, no bank over subscription */
0302     if (WARN_ON(total_bank_config > div64_u64(pool_size, bank_size) + 1))
0303         return -EINVAL;
0304 
0305     return 0;
0306 }