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

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

DEFINITIONS

This source file includes following definitions.
  1. mlxsw_sp2_kvdl_part_find_zero_bits
  2. mlxsw_sp2_kvdl_part_alloc
  3. mlxsw_sp2_kvdl_rec_del
  4. mlxsw_sp2_kvdl_part_free
  5. mlxsw_sp2_kvdl_alloc
  6. mlxsw_sp2_kvdl_free
  7. mlxsw_sp2_kvdl_alloc_size_query
  8. mlxsw_sp2_kvdl_part_init
  9. mlxsw_sp2_kvdl_part_fini
  10. mlxsw_sp2_kvdl_parts_init
  11. mlxsw_sp2_kvdl_parts_fini
  12. mlxsw_sp2_kvdl_init
  13. mlxsw_sp2_kvdl_fini

   1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
   3 
   4 #include <linux/kernel.h>
   5 #include <linux/bitops.h>
   6 
   7 #include "spectrum.h"
   8 #include "core.h"
   9 #include "reg.h"
  10 #include "resources.h"
  11 
  12 struct mlxsw_sp2_kvdl_part_info {
  13         u8 res_type;
  14         /* For each defined partititon we need to know how many
  15          * usage bits we need and how many indexes there are
  16          * represented by a single bit. This could be got from FW
  17          * querying appropriate resources. So have the resource
  18          * ids for for this purpose in partition definition.
  19          */
  20         enum mlxsw_res_id usage_bit_count_res_id;
  21         enum mlxsw_res_id index_range_res_id;
  22 };
  23 
  24 #define MLXSW_SP2_KVDL_PART_INFO(_entry_type, _res_type,                        \
  25                                  _usage_bit_count_res_id, _index_range_res_id)  \
  26 [MLXSW_SP_KVDL_ENTRY_TYPE_##_entry_type] = {                                    \
  27         .res_type = _res_type,                                                  \
  28         .usage_bit_count_res_id = MLXSW_RES_ID_##_usage_bit_count_res_id,       \
  29         .index_range_res_id = MLXSW_RES_ID_##_index_range_res_id,               \
  30 }
  31 
  32 static const struct mlxsw_sp2_kvdl_part_info mlxsw_sp2_kvdl_parts_info[] = {
  33         MLXSW_SP2_KVDL_PART_INFO(ADJ, 0x21, KVD_SIZE, MAX_KVD_LINEAR_RANGE),
  34         MLXSW_SP2_KVDL_PART_INFO(ACTSET, 0x23, MAX_KVD_ACTION_SETS,
  35                                  MAX_KVD_ACTION_SETS),
  36         MLXSW_SP2_KVDL_PART_INFO(PBS, 0x24, KVD_SIZE, KVD_SIZE),
  37         MLXSW_SP2_KVDL_PART_INFO(MCRIGR, 0x26, KVD_SIZE, KVD_SIZE),
  38         MLXSW_SP2_KVDL_PART_INFO(TNUMT, 0x29, KVD_SIZE, KVD_SIZE),
  39 };
  40 
  41 #define MLXSW_SP2_KVDL_PARTS_INFO_LEN ARRAY_SIZE(mlxsw_sp2_kvdl_parts_info)
  42 
  43 struct mlxsw_sp2_kvdl_part {
  44         const struct mlxsw_sp2_kvdl_part_info *info;
  45         unsigned int usage_bit_count;
  46         unsigned int indexes_per_usage_bit;
  47         unsigned int last_allocated_bit;
  48         unsigned long usage[0]; /* Usage bits */
  49 };
  50 
  51 struct mlxsw_sp2_kvdl {
  52         struct mlxsw_sp2_kvdl_part *parts[MLXSW_SP2_KVDL_PARTS_INFO_LEN];
  53 };
  54 
  55 static int mlxsw_sp2_kvdl_part_find_zero_bits(struct mlxsw_sp2_kvdl_part *part,
  56                                               unsigned int bit_count,
  57                                               unsigned int *p_bit)
  58 {
  59         unsigned int start_bit;
  60         unsigned int bit;
  61         unsigned int i;
  62         bool wrap = false;
  63 
  64         start_bit = part->last_allocated_bit + 1;
  65         if (start_bit == part->usage_bit_count)
  66                 start_bit = 0;
  67         bit = start_bit;
  68 again:
  69         bit = find_next_zero_bit(part->usage, part->usage_bit_count, bit);
  70         if (!wrap && bit + bit_count >= part->usage_bit_count) {
  71                 wrap = true;
  72                 bit = 0;
  73                 goto again;
  74         }
  75         if (wrap && bit + bit_count >= start_bit)
  76                 return -ENOBUFS;
  77         for (i = 0; i < bit_count; i++) {
  78                 if (test_bit(bit + i, part->usage)) {
  79                         bit += bit_count;
  80                         goto again;
  81                 }
  82         }
  83         *p_bit = bit;
  84         return 0;
  85 }
  86 
  87 static int mlxsw_sp2_kvdl_part_alloc(struct mlxsw_sp2_kvdl_part *part,
  88                                      unsigned int size,
  89                                      u32 *p_kvdl_index)
  90 {
  91         unsigned int bit_count;
  92         unsigned int bit;
  93         unsigned int i;
  94         int err;
  95 
  96         bit_count = DIV_ROUND_UP(size, part->indexes_per_usage_bit);
  97         err = mlxsw_sp2_kvdl_part_find_zero_bits(part, bit_count, &bit);
  98         if (err)
  99                 return err;
 100         for (i = 0; i < bit_count; i++)
 101                 __set_bit(bit + i, part->usage);
 102         *p_kvdl_index = bit * part->indexes_per_usage_bit;
 103         return 0;
 104 }
 105 
 106 static int mlxsw_sp2_kvdl_rec_del(struct mlxsw_sp *mlxsw_sp, u8 res_type,
 107                                   u16 size, u32 kvdl_index)
 108 {
 109         char *iedr_pl;
 110         int err;
 111 
 112         iedr_pl = kmalloc(MLXSW_REG_IEDR_LEN, GFP_KERNEL);
 113         if (!iedr_pl)
 114                 return -ENOMEM;
 115 
 116         mlxsw_reg_iedr_pack(iedr_pl);
 117         mlxsw_reg_iedr_rec_pack(iedr_pl, 0, res_type, size, kvdl_index);
 118         err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(iedr), iedr_pl);
 119         kfree(iedr_pl);
 120         return err;
 121 }
 122 
 123 static void mlxsw_sp2_kvdl_part_free(struct mlxsw_sp *mlxsw_sp,
 124                                      struct mlxsw_sp2_kvdl_part *part,
 125                                      unsigned int size, u32 kvdl_index)
 126 {
 127         unsigned int bit_count;
 128         unsigned int bit;
 129         unsigned int i;
 130         int err;
 131 
 132         /* We need to ask FW to delete previously used KVD linear index */
 133         err = mlxsw_sp2_kvdl_rec_del(mlxsw_sp, part->info->res_type,
 134                                      size, kvdl_index);
 135         if (err)
 136                 return;
 137 
 138         bit_count = DIV_ROUND_UP(size, part->indexes_per_usage_bit);
 139         bit = kvdl_index / part->indexes_per_usage_bit;
 140         for (i = 0; i < bit_count; i++)
 141                 __clear_bit(bit + i, part->usage);
 142 }
 143 
 144 static int mlxsw_sp2_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, void *priv,
 145                                 enum mlxsw_sp_kvdl_entry_type type,
 146                                 unsigned int entry_count,
 147                                 u32 *p_entry_index)
 148 {
 149         unsigned int size = entry_count * mlxsw_sp_kvdl_entry_size(type);
 150         struct mlxsw_sp2_kvdl *kvdl = priv;
 151         struct mlxsw_sp2_kvdl_part *part = kvdl->parts[type];
 152 
 153         return mlxsw_sp2_kvdl_part_alloc(part, size, p_entry_index);
 154 }
 155 
 156 static void mlxsw_sp2_kvdl_free(struct mlxsw_sp *mlxsw_sp, void *priv,
 157                                 enum mlxsw_sp_kvdl_entry_type type,
 158                                 unsigned int entry_count,
 159                                 int entry_index)
 160 {
 161         unsigned int size = entry_count * mlxsw_sp_kvdl_entry_size(type);
 162         struct mlxsw_sp2_kvdl *kvdl = priv;
 163         struct mlxsw_sp2_kvdl_part *part = kvdl->parts[type];
 164 
 165         return mlxsw_sp2_kvdl_part_free(mlxsw_sp, part, size, entry_index);
 166 }
 167 
 168 static int mlxsw_sp2_kvdl_alloc_size_query(struct mlxsw_sp *mlxsw_sp,
 169                                            void *priv,
 170                                            enum mlxsw_sp_kvdl_entry_type type,
 171                                            unsigned int entry_count,
 172                                            unsigned int *p_alloc_count)
 173 {
 174         *p_alloc_count = entry_count;
 175         return 0;
 176 }
 177 
 178 static struct mlxsw_sp2_kvdl_part *
 179 mlxsw_sp2_kvdl_part_init(struct mlxsw_sp *mlxsw_sp,
 180                          const struct mlxsw_sp2_kvdl_part_info *info)
 181 {
 182         unsigned int indexes_per_usage_bit;
 183         struct mlxsw_sp2_kvdl_part *part;
 184         unsigned int index_range;
 185         unsigned int usage_bit_count;
 186         size_t usage_size;
 187 
 188         if (!mlxsw_core_res_valid(mlxsw_sp->core,
 189                                   info->usage_bit_count_res_id) ||
 190             !mlxsw_core_res_valid(mlxsw_sp->core,
 191                                   info->index_range_res_id))
 192                 return ERR_PTR(-EIO);
 193         usage_bit_count = mlxsw_core_res_get(mlxsw_sp->core,
 194                                              info->usage_bit_count_res_id);
 195         index_range = mlxsw_core_res_get(mlxsw_sp->core,
 196                                          info->index_range_res_id);
 197 
 198         /* For some partitions, one usage bit represents a group of indexes.
 199          * That's why we compute the number of indexes per usage bit here,
 200          * according to queried resources.
 201          */
 202         indexes_per_usage_bit = index_range / usage_bit_count;
 203 
 204         usage_size = BITS_TO_LONGS(usage_bit_count) * sizeof(unsigned long);
 205         part = kzalloc(sizeof(*part) + usage_size, GFP_KERNEL);
 206         if (!part)
 207                 return ERR_PTR(-ENOMEM);
 208         part->info = info;
 209         part->usage_bit_count = usage_bit_count;
 210         part->indexes_per_usage_bit = indexes_per_usage_bit;
 211         part->last_allocated_bit = usage_bit_count - 1;
 212         return part;
 213 }
 214 
 215 static void mlxsw_sp2_kvdl_part_fini(struct mlxsw_sp2_kvdl_part *part)
 216 {
 217         kfree(part);
 218 }
 219 
 220 static int mlxsw_sp2_kvdl_parts_init(struct mlxsw_sp *mlxsw_sp,
 221                                      struct mlxsw_sp2_kvdl *kvdl)
 222 {
 223         const struct mlxsw_sp2_kvdl_part_info *info;
 224         int i;
 225         int err;
 226 
 227         for (i = 0; i < MLXSW_SP2_KVDL_PARTS_INFO_LEN; i++) {
 228                 info = &mlxsw_sp2_kvdl_parts_info[i];
 229                 kvdl->parts[i] = mlxsw_sp2_kvdl_part_init(mlxsw_sp, info);
 230                 if (IS_ERR(kvdl->parts[i])) {
 231                         err = PTR_ERR(kvdl->parts[i]);
 232                         goto err_kvdl_part_init;
 233                 }
 234         }
 235         return 0;
 236 
 237 err_kvdl_part_init:
 238         for (i--; i >= 0; i--)
 239                 mlxsw_sp2_kvdl_part_fini(kvdl->parts[i]);
 240         return err;
 241 }
 242 
 243 static void mlxsw_sp2_kvdl_parts_fini(struct mlxsw_sp2_kvdl *kvdl)
 244 {
 245         int i;
 246 
 247         for (i = 0; i < MLXSW_SP2_KVDL_PARTS_INFO_LEN; i++)
 248                 mlxsw_sp2_kvdl_part_fini(kvdl->parts[i]);
 249 }
 250 
 251 static int mlxsw_sp2_kvdl_init(struct mlxsw_sp *mlxsw_sp, void *priv)
 252 {
 253         struct mlxsw_sp2_kvdl *kvdl = priv;
 254 
 255         return mlxsw_sp2_kvdl_parts_init(mlxsw_sp, kvdl);
 256 }
 257 
 258 static void mlxsw_sp2_kvdl_fini(struct mlxsw_sp *mlxsw_sp, void *priv)
 259 {
 260         struct mlxsw_sp2_kvdl *kvdl = priv;
 261 
 262         mlxsw_sp2_kvdl_parts_fini(kvdl);
 263 }
 264 
 265 const struct mlxsw_sp_kvdl_ops mlxsw_sp2_kvdl_ops = {
 266         .priv_size = sizeof(struct mlxsw_sp2_kvdl),
 267         .init = mlxsw_sp2_kvdl_init,
 268         .fini = mlxsw_sp2_kvdl_fini,
 269         .alloc = mlxsw_sp2_kvdl_alloc,
 270         .free = mlxsw_sp2_kvdl_free,
 271         .alloc_size_query = mlxsw_sp2_kvdl_alloc_size_query,
 272 };

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