root/drivers/net/ethernet/mellanox/mlxsw/spectrum_cnt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlxsw_sp_counter_pool_validate
  2. mlxsw_sp_counter_sub_pools_prepare
  3. mlxsw_sp_counter_pool_init
  4. mlxsw_sp_counter_pool_fini
  5. mlxsw_sp_counter_alloc
  6. mlxsw_sp_counter_free

   1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2 /* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
   3 
   4 #include <linux/kernel.h>
   5 #include <linux/bitops.h>
   6 
   7 #include "spectrum_cnt.h"
   8 
   9 #define MLXSW_SP_COUNTER_POOL_BANK_SIZE 4096
  10 
  11 struct mlxsw_sp_counter_sub_pool {
  12         unsigned int base_index;
  13         unsigned int size;
  14         unsigned int entry_size;
  15         unsigned int bank_count;
  16 };
  17 
  18 struct mlxsw_sp_counter_pool {
  19         unsigned int pool_size;
  20         unsigned long *usage; /* Usage bitmap */
  21         struct mlxsw_sp_counter_sub_pool *sub_pools;
  22 };
  23 
  24 static struct mlxsw_sp_counter_sub_pool mlxsw_sp_counter_sub_pools[] = {
  25         [MLXSW_SP_COUNTER_SUB_POOL_FLOW] = {
  26                 .bank_count = 6,
  27         },
  28         [MLXSW_SP_COUNTER_SUB_POOL_RIF] = {
  29                 .bank_count = 2,
  30         }
  31 };
  32 
  33 static int mlxsw_sp_counter_pool_validate(struct mlxsw_sp *mlxsw_sp)
  34 {
  35         unsigned int total_bank_config = 0;
  36         unsigned int pool_size;
  37         int i;
  38 
  39         pool_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, COUNTER_POOL_SIZE);
  40         /* Check config is valid, no bank over subscription */
  41         for (i = 0; i < ARRAY_SIZE(mlxsw_sp_counter_sub_pools); i++)
  42                 total_bank_config += mlxsw_sp_counter_sub_pools[i].bank_count;
  43         if (total_bank_config > pool_size / MLXSW_SP_COUNTER_POOL_BANK_SIZE + 1)
  44                 return -EINVAL;
  45         return 0;
  46 }
  47 
  48 static int mlxsw_sp_counter_sub_pools_prepare(struct mlxsw_sp *mlxsw_sp)
  49 {
  50         struct mlxsw_sp_counter_sub_pool *sub_pool;
  51 
  52         /* Prepare generic flow pool*/
  53         sub_pool = &mlxsw_sp_counter_sub_pools[MLXSW_SP_COUNTER_SUB_POOL_FLOW];
  54         if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, COUNTER_SIZE_PACKETS_BYTES))
  55                 return -EIO;
  56         sub_pool->entry_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
  57                                                   COUNTER_SIZE_PACKETS_BYTES);
  58         /* Prepare erif pool*/
  59         sub_pool = &mlxsw_sp_counter_sub_pools[MLXSW_SP_COUNTER_SUB_POOL_RIF];
  60         if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, COUNTER_SIZE_ROUTER_BASIC))
  61                 return -EIO;
  62         sub_pool->entry_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
  63                                                   COUNTER_SIZE_ROUTER_BASIC);
  64         return 0;
  65 }
  66 
  67 int mlxsw_sp_counter_pool_init(struct mlxsw_sp *mlxsw_sp)
  68 {
  69         struct mlxsw_sp_counter_sub_pool *sub_pool;
  70         struct mlxsw_sp_counter_pool *pool;
  71         unsigned int base_index;
  72         unsigned int map_size;
  73         int i;
  74         int err;
  75 
  76         if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, COUNTER_POOL_SIZE))
  77                 return -EIO;
  78 
  79         err = mlxsw_sp_counter_pool_validate(mlxsw_sp);
  80         if (err)
  81                 return err;
  82 
  83         err = mlxsw_sp_counter_sub_pools_prepare(mlxsw_sp);
  84         if (err)
  85                 return err;
  86 
  87         pool = kzalloc(sizeof(*pool), GFP_KERNEL);
  88         if (!pool)
  89                 return -ENOMEM;
  90 
  91         pool->pool_size = MLXSW_CORE_RES_GET(mlxsw_sp->core, COUNTER_POOL_SIZE);
  92         map_size = BITS_TO_LONGS(pool->pool_size) * sizeof(unsigned long);
  93 
  94         pool->usage = kzalloc(map_size, GFP_KERNEL);
  95         if (!pool->usage) {
  96                 err = -ENOMEM;
  97                 goto err_usage_alloc;
  98         }
  99 
 100         pool->sub_pools = mlxsw_sp_counter_sub_pools;
 101         /* Allocation is based on bank count which should be
 102          * specified for each sub pool statically.
 103          */
 104         base_index = 0;
 105         for (i = 0; i < ARRAY_SIZE(mlxsw_sp_counter_sub_pools); i++) {
 106                 sub_pool = &pool->sub_pools[i];
 107                 sub_pool->size = sub_pool->bank_count *
 108                                  MLXSW_SP_COUNTER_POOL_BANK_SIZE;
 109                 sub_pool->base_index = base_index;
 110                 base_index += sub_pool->size;
 111                 /* The last bank can't be fully used */
 112                 if (sub_pool->base_index + sub_pool->size > pool->pool_size)
 113                         sub_pool->size = pool->pool_size - sub_pool->base_index;
 114         }
 115 
 116         mlxsw_sp->counter_pool = pool;
 117         return 0;
 118 
 119 err_usage_alloc:
 120         kfree(pool);
 121         return err;
 122 }
 123 
 124 void mlxsw_sp_counter_pool_fini(struct mlxsw_sp *mlxsw_sp)
 125 {
 126         struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;
 127 
 128         WARN_ON(find_first_bit(pool->usage, pool->pool_size) !=
 129                                pool->pool_size);
 130         kfree(pool->usage);
 131         kfree(pool);
 132 }
 133 
 134 int mlxsw_sp_counter_alloc(struct mlxsw_sp *mlxsw_sp,
 135                            enum mlxsw_sp_counter_sub_pool_id sub_pool_id,
 136                            unsigned int *p_counter_index)
 137 {
 138         struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;
 139         struct mlxsw_sp_counter_sub_pool *sub_pool;
 140         unsigned int entry_index;
 141         unsigned int stop_index;
 142         int i;
 143 
 144         sub_pool = &mlxsw_sp_counter_sub_pools[sub_pool_id];
 145         stop_index = sub_pool->base_index + sub_pool->size;
 146         entry_index = sub_pool->base_index;
 147 
 148         entry_index = find_next_zero_bit(pool->usage, stop_index, entry_index);
 149         if (entry_index == stop_index)
 150                 return -ENOBUFS;
 151         /* The sub-pools can contain non-integer number of entries
 152          * so we must check for overflow
 153          */
 154         if (entry_index + sub_pool->entry_size > stop_index)
 155                 return -ENOBUFS;
 156         for (i = 0; i < sub_pool->entry_size; i++)
 157                 __set_bit(entry_index + i, pool->usage);
 158 
 159         *p_counter_index = entry_index;
 160         return 0;
 161 }
 162 
 163 void mlxsw_sp_counter_free(struct mlxsw_sp *mlxsw_sp,
 164                            enum mlxsw_sp_counter_sub_pool_id sub_pool_id,
 165                            unsigned int counter_index)
 166 {
 167         struct mlxsw_sp_counter_pool *pool = mlxsw_sp->counter_pool;
 168         struct mlxsw_sp_counter_sub_pool *sub_pool;
 169         int i;
 170 
 171         if (WARN_ON(counter_index >= pool->pool_size))
 172                 return;
 173         sub_pool = &mlxsw_sp_counter_sub_pools[sub_pool_id];
 174         for (i = 0; i < sub_pool->entry_size; i++)
 175                 __clear_bit(counter_index + i, pool->usage);
 176 }

/* [<][>][^][v][top][bottom][index][help] */