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

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

DEFINITIONS

This source file includes following definitions.
  1. mlxsw_sp1_kvdl_alloc_size_part
  2. mlxsw_sp1_kvdl_index_part
  3. mlxsw_sp1_kvdl_to_kvdl_index
  4. mlxsw_sp1_kvdl_to_entry_index
  5. mlxsw_sp1_kvdl_part_alloc
  6. mlxsw_sp1_kvdl_part_free
  7. mlxsw_sp1_kvdl_alloc
  8. mlxsw_sp1_kvdl_free
  9. mlxsw_sp1_kvdl_alloc_size_query
  10. mlxsw_sp1_kvdl_part_update
  11. mlxsw_sp1_kvdl_part_init
  12. mlxsw_sp1_kvdl_part_fini
  13. mlxsw_sp1_kvdl_parts_init
  14. mlxsw_sp1_kvdl_parts_fini
  15. mlxsw_sp1_kvdl_part_occ
  16. mlxsw_sp1_kvdl_occ_get
  17. mlxsw_sp1_kvdl_single_occ_get
  18. mlxsw_sp1_kvdl_chunks_occ_get
  19. mlxsw_sp1_kvdl_large_chunks_occ_get
  20. mlxsw_sp1_kvdl_init
  21. mlxsw_sp1_kvdl_fini
  22. mlxsw_sp1_kvdl_resources_register

   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 
   9 #define MLXSW_SP1_KVDL_SINGLE_BASE 0
  10 #define MLXSW_SP1_KVDL_SINGLE_SIZE 16384
  11 #define MLXSW_SP1_KVDL_SINGLE_END \
  12         (MLXSW_SP1_KVDL_SINGLE_SIZE + MLXSW_SP1_KVDL_SINGLE_BASE - 1)
  13 
  14 #define MLXSW_SP1_KVDL_CHUNKS_BASE \
  15         (MLXSW_SP1_KVDL_SINGLE_BASE + MLXSW_SP1_KVDL_SINGLE_SIZE)
  16 #define MLXSW_SP1_KVDL_CHUNKS_SIZE 49152
  17 #define MLXSW_SP1_KVDL_CHUNKS_END \
  18         (MLXSW_SP1_KVDL_CHUNKS_SIZE + MLXSW_SP1_KVDL_CHUNKS_BASE - 1)
  19 
  20 #define MLXSW_SP1_KVDL_LARGE_CHUNKS_BASE \
  21         (MLXSW_SP1_KVDL_CHUNKS_BASE + MLXSW_SP1_KVDL_CHUNKS_SIZE)
  22 #define MLXSW_SP1_KVDL_LARGE_CHUNKS_SIZE \
  23         (MLXSW_SP_KVD_LINEAR_SIZE - MLXSW_SP1_KVDL_LARGE_CHUNKS_BASE)
  24 #define MLXSW_SP1_KVDL_LARGE_CHUNKS_END \
  25         (MLXSW_SP1_KVDL_LARGE_CHUNKS_SIZE + MLXSW_SP1_KVDL_LARGE_CHUNKS_BASE - 1)
  26 
  27 #define MLXSW_SP1_KVDL_SINGLE_ALLOC_SIZE 1
  28 #define MLXSW_SP1_KVDL_CHUNKS_ALLOC_SIZE 32
  29 #define MLXSW_SP1_KVDL_LARGE_CHUNKS_ALLOC_SIZE 512
  30 
  31 struct mlxsw_sp1_kvdl_part_info {
  32         unsigned int part_index;
  33         unsigned int start_index;
  34         unsigned int end_index;
  35         unsigned int alloc_size;
  36         enum mlxsw_sp_resource_id resource_id;
  37 };
  38 
  39 enum mlxsw_sp1_kvdl_part_id {
  40         MLXSW_SP1_KVDL_PART_ID_SINGLE,
  41         MLXSW_SP1_KVDL_PART_ID_CHUNKS,
  42         MLXSW_SP1_KVDL_PART_ID_LARGE_CHUNKS,
  43 };
  44 
  45 #define MLXSW_SP1_KVDL_PART_INFO(id)                            \
  46 [MLXSW_SP1_KVDL_PART_ID_##id] = {                               \
  47         .start_index = MLXSW_SP1_KVDL_##id##_BASE,              \
  48         .end_index = MLXSW_SP1_KVDL_##id##_END,                 \
  49         .alloc_size = MLXSW_SP1_KVDL_##id##_ALLOC_SIZE,         \
  50         .resource_id = MLXSW_SP_RESOURCE_KVD_LINEAR_##id,       \
  51 }
  52 
  53 static const struct mlxsw_sp1_kvdl_part_info mlxsw_sp1_kvdl_parts_info[] = {
  54         MLXSW_SP1_KVDL_PART_INFO(SINGLE),
  55         MLXSW_SP1_KVDL_PART_INFO(CHUNKS),
  56         MLXSW_SP1_KVDL_PART_INFO(LARGE_CHUNKS),
  57 };
  58 
  59 #define MLXSW_SP1_KVDL_PARTS_INFO_LEN ARRAY_SIZE(mlxsw_sp1_kvdl_parts_info)
  60 
  61 struct mlxsw_sp1_kvdl_part {
  62         struct mlxsw_sp1_kvdl_part_info info;
  63         unsigned long usage[0]; /* Entries */
  64 };
  65 
  66 struct mlxsw_sp1_kvdl {
  67         struct mlxsw_sp1_kvdl_part *parts[MLXSW_SP1_KVDL_PARTS_INFO_LEN];
  68 };
  69 
  70 static struct mlxsw_sp1_kvdl_part *
  71 mlxsw_sp1_kvdl_alloc_size_part(struct mlxsw_sp1_kvdl *kvdl,
  72                                unsigned int alloc_size)
  73 {
  74         struct mlxsw_sp1_kvdl_part *part, *min_part = NULL;
  75         int i;
  76 
  77         for (i = 0; i < MLXSW_SP1_KVDL_PARTS_INFO_LEN; i++) {
  78                 part = kvdl->parts[i];
  79                 if (alloc_size <= part->info.alloc_size &&
  80                     (!min_part ||
  81                      part->info.alloc_size <= min_part->info.alloc_size))
  82                         min_part = part;
  83         }
  84 
  85         return min_part ?: ERR_PTR(-ENOBUFS);
  86 }
  87 
  88 static struct mlxsw_sp1_kvdl_part *
  89 mlxsw_sp1_kvdl_index_part(struct mlxsw_sp1_kvdl *kvdl, u32 kvdl_index)
  90 {
  91         struct mlxsw_sp1_kvdl_part *part;
  92         int i;
  93 
  94         for (i = 0; i < MLXSW_SP1_KVDL_PARTS_INFO_LEN; i++) {
  95                 part = kvdl->parts[i];
  96                 if (kvdl_index >= part->info.start_index &&
  97                     kvdl_index <= part->info.end_index)
  98                         return part;
  99         }
 100 
 101         return ERR_PTR(-EINVAL);
 102 }
 103 
 104 static u32
 105 mlxsw_sp1_kvdl_to_kvdl_index(const struct mlxsw_sp1_kvdl_part_info *info,
 106                              unsigned int entry_index)
 107 {
 108         return info->start_index + entry_index * info->alloc_size;
 109 }
 110 
 111 static unsigned int
 112 mlxsw_sp1_kvdl_to_entry_index(const struct mlxsw_sp1_kvdl_part_info *info,
 113                               u32 kvdl_index)
 114 {
 115         return (kvdl_index - info->start_index) / info->alloc_size;
 116 }
 117 
 118 static int mlxsw_sp1_kvdl_part_alloc(struct mlxsw_sp1_kvdl_part *part,
 119                                      u32 *p_kvdl_index)
 120 {
 121         const struct mlxsw_sp1_kvdl_part_info *info = &part->info;
 122         unsigned int entry_index, nr_entries;
 123 
 124         nr_entries = (info->end_index - info->start_index + 1) /
 125                      info->alloc_size;
 126         entry_index = find_first_zero_bit(part->usage, nr_entries);
 127         if (entry_index == nr_entries)
 128                 return -ENOBUFS;
 129         __set_bit(entry_index, part->usage);
 130 
 131         *p_kvdl_index = mlxsw_sp1_kvdl_to_kvdl_index(info, entry_index);
 132 
 133         return 0;
 134 }
 135 
 136 static void mlxsw_sp1_kvdl_part_free(struct mlxsw_sp1_kvdl_part *part,
 137                                      u32 kvdl_index)
 138 {
 139         const struct mlxsw_sp1_kvdl_part_info *info = &part->info;
 140         unsigned int entry_index;
 141 
 142         entry_index = mlxsw_sp1_kvdl_to_entry_index(info, kvdl_index);
 143         __clear_bit(entry_index, part->usage);
 144 }
 145 
 146 static int mlxsw_sp1_kvdl_alloc(struct mlxsw_sp *mlxsw_sp, void *priv,
 147                                 enum mlxsw_sp_kvdl_entry_type type,
 148                                 unsigned int entry_count,
 149                                 u32 *p_entry_index)
 150 {
 151         struct mlxsw_sp1_kvdl *kvdl = priv;
 152         struct mlxsw_sp1_kvdl_part *part;
 153 
 154         /* Find partition with smallest allocation size satisfying the
 155          * requested size.
 156          */
 157         part = mlxsw_sp1_kvdl_alloc_size_part(kvdl, entry_count);
 158         if (IS_ERR(part))
 159                 return PTR_ERR(part);
 160 
 161         return mlxsw_sp1_kvdl_part_alloc(part, p_entry_index);
 162 }
 163 
 164 static void mlxsw_sp1_kvdl_free(struct mlxsw_sp *mlxsw_sp, void *priv,
 165                                 enum mlxsw_sp_kvdl_entry_type type,
 166                                 unsigned int entry_count, int entry_index)
 167 {
 168         struct mlxsw_sp1_kvdl *kvdl = priv;
 169         struct mlxsw_sp1_kvdl_part *part;
 170 
 171         part = mlxsw_sp1_kvdl_index_part(kvdl, entry_index);
 172         if (IS_ERR(part))
 173                 return;
 174         mlxsw_sp1_kvdl_part_free(part, entry_index);
 175 }
 176 
 177 static int mlxsw_sp1_kvdl_alloc_size_query(struct mlxsw_sp *mlxsw_sp,
 178                                            void *priv,
 179                                            enum mlxsw_sp_kvdl_entry_type type,
 180                                            unsigned int entry_count,
 181                                            unsigned int *p_alloc_size)
 182 {
 183         struct mlxsw_sp1_kvdl *kvdl = priv;
 184         struct mlxsw_sp1_kvdl_part *part;
 185 
 186         part = mlxsw_sp1_kvdl_alloc_size_part(kvdl, entry_count);
 187         if (IS_ERR(part))
 188                 return PTR_ERR(part);
 189 
 190         *p_alloc_size = part->info.alloc_size;
 191 
 192         return 0;
 193 }
 194 
 195 static void mlxsw_sp1_kvdl_part_update(struct mlxsw_sp1_kvdl_part *part,
 196                                        struct mlxsw_sp1_kvdl_part *part_prev,
 197                                        unsigned int size)
 198 {
 199         if (!part_prev) {
 200                 part->info.end_index = size - 1;
 201         } else {
 202                 part->info.start_index = part_prev->info.end_index + 1;
 203                 part->info.end_index = part->info.start_index + size - 1;
 204         }
 205 }
 206 
 207 static struct mlxsw_sp1_kvdl_part *
 208 mlxsw_sp1_kvdl_part_init(struct mlxsw_sp *mlxsw_sp,
 209                          const struct mlxsw_sp1_kvdl_part_info *info,
 210                          struct mlxsw_sp1_kvdl_part *part_prev)
 211 {
 212         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
 213         struct mlxsw_sp1_kvdl_part *part;
 214         bool need_update = true;
 215         unsigned int nr_entries;
 216         size_t usage_size;
 217         u64 resource_size;
 218         int err;
 219 
 220         err = devlink_resource_size_get(devlink, info->resource_id,
 221                                         &resource_size);
 222         if (err) {
 223                 need_update = false;
 224                 resource_size = info->end_index - info->start_index + 1;
 225         }
 226 
 227         nr_entries = div_u64(resource_size, info->alloc_size);
 228         usage_size = BITS_TO_LONGS(nr_entries) * sizeof(unsigned long);
 229         part = kzalloc(sizeof(*part) + usage_size, GFP_KERNEL);
 230         if (!part)
 231                 return ERR_PTR(-ENOMEM);
 232 
 233         memcpy(&part->info, info, sizeof(part->info));
 234 
 235         if (need_update)
 236                 mlxsw_sp1_kvdl_part_update(part, part_prev, resource_size);
 237         return part;
 238 }
 239 
 240 static void mlxsw_sp1_kvdl_part_fini(struct mlxsw_sp1_kvdl_part *part)
 241 {
 242         kfree(part);
 243 }
 244 
 245 static int mlxsw_sp1_kvdl_parts_init(struct mlxsw_sp *mlxsw_sp,
 246                                      struct mlxsw_sp1_kvdl *kvdl)
 247 {
 248         const struct mlxsw_sp1_kvdl_part_info *info;
 249         struct mlxsw_sp1_kvdl_part *part_prev = NULL;
 250         int err, i;
 251 
 252         for (i = 0; i < MLXSW_SP1_KVDL_PARTS_INFO_LEN; i++) {
 253                 info = &mlxsw_sp1_kvdl_parts_info[i];
 254                 kvdl->parts[i] = mlxsw_sp1_kvdl_part_init(mlxsw_sp, info,
 255                                                           part_prev);
 256                 if (IS_ERR(kvdl->parts[i])) {
 257                         err = PTR_ERR(kvdl->parts[i]);
 258                         goto err_kvdl_part_init;
 259                 }
 260                 part_prev = kvdl->parts[i];
 261         }
 262         return 0;
 263 
 264 err_kvdl_part_init:
 265         for (i--; i >= 0; i--)
 266                 mlxsw_sp1_kvdl_part_fini(kvdl->parts[i]);
 267         return err;
 268 }
 269 
 270 static void mlxsw_sp1_kvdl_parts_fini(struct mlxsw_sp1_kvdl *kvdl)
 271 {
 272         int i;
 273 
 274         for (i = 0; i < MLXSW_SP1_KVDL_PARTS_INFO_LEN; i++)
 275                 mlxsw_sp1_kvdl_part_fini(kvdl->parts[i]);
 276 }
 277 
 278 static u64 mlxsw_sp1_kvdl_part_occ(struct mlxsw_sp1_kvdl_part *part)
 279 {
 280         const struct mlxsw_sp1_kvdl_part_info *info = &part->info;
 281         unsigned int nr_entries;
 282         int bit = -1;
 283         u64 occ = 0;
 284 
 285         nr_entries = (info->end_index -
 286                       info->start_index + 1) /
 287                       info->alloc_size;
 288         while ((bit = find_next_bit(part->usage, nr_entries, bit + 1))
 289                 < nr_entries)
 290                 occ += info->alloc_size;
 291         return occ;
 292 }
 293 
 294 static u64 mlxsw_sp1_kvdl_occ_get(void *priv)
 295 {
 296         const struct mlxsw_sp1_kvdl *kvdl = priv;
 297         u64 occ = 0;
 298         int i;
 299 
 300         for (i = 0; i < MLXSW_SP1_KVDL_PARTS_INFO_LEN; i++)
 301                 occ += mlxsw_sp1_kvdl_part_occ(kvdl->parts[i]);
 302 
 303         return occ;
 304 }
 305 
 306 static u64 mlxsw_sp1_kvdl_single_occ_get(void *priv)
 307 {
 308         const struct mlxsw_sp1_kvdl *kvdl = priv;
 309         struct mlxsw_sp1_kvdl_part *part;
 310 
 311         part = kvdl->parts[MLXSW_SP1_KVDL_PART_ID_SINGLE];
 312         return mlxsw_sp1_kvdl_part_occ(part);
 313 }
 314 
 315 static u64 mlxsw_sp1_kvdl_chunks_occ_get(void *priv)
 316 {
 317         const struct mlxsw_sp1_kvdl *kvdl = priv;
 318         struct mlxsw_sp1_kvdl_part *part;
 319 
 320         part = kvdl->parts[MLXSW_SP1_KVDL_PART_ID_CHUNKS];
 321         return mlxsw_sp1_kvdl_part_occ(part);
 322 }
 323 
 324 static u64 mlxsw_sp1_kvdl_large_chunks_occ_get(void *priv)
 325 {
 326         const struct mlxsw_sp1_kvdl *kvdl = priv;
 327         struct mlxsw_sp1_kvdl_part *part;
 328 
 329         part = kvdl->parts[MLXSW_SP1_KVDL_PART_ID_LARGE_CHUNKS];
 330         return mlxsw_sp1_kvdl_part_occ(part);
 331 }
 332 
 333 static int mlxsw_sp1_kvdl_init(struct mlxsw_sp *mlxsw_sp, void *priv)
 334 {
 335         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
 336         struct mlxsw_sp1_kvdl *kvdl = priv;
 337         int err;
 338 
 339         err = mlxsw_sp1_kvdl_parts_init(mlxsw_sp, kvdl);
 340         if (err)
 341                 return err;
 342         devlink_resource_occ_get_register(devlink,
 343                                           MLXSW_SP_RESOURCE_KVD_LINEAR,
 344                                           mlxsw_sp1_kvdl_occ_get,
 345                                           kvdl);
 346         devlink_resource_occ_get_register(devlink,
 347                                           MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE,
 348                                           mlxsw_sp1_kvdl_single_occ_get,
 349                                           kvdl);
 350         devlink_resource_occ_get_register(devlink,
 351                                           MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS,
 352                                           mlxsw_sp1_kvdl_chunks_occ_get,
 353                                           kvdl);
 354         devlink_resource_occ_get_register(devlink,
 355                                           MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS,
 356                                           mlxsw_sp1_kvdl_large_chunks_occ_get,
 357                                           kvdl);
 358         return 0;
 359 }
 360 
 361 static void mlxsw_sp1_kvdl_fini(struct mlxsw_sp *mlxsw_sp, void *priv)
 362 {
 363         struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
 364         struct mlxsw_sp1_kvdl *kvdl = priv;
 365 
 366         devlink_resource_occ_get_unregister(devlink,
 367                                             MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS);
 368         devlink_resource_occ_get_unregister(devlink,
 369                                             MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS);
 370         devlink_resource_occ_get_unregister(devlink,
 371                                             MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE);
 372         devlink_resource_occ_get_unregister(devlink,
 373                                             MLXSW_SP_RESOURCE_KVD_LINEAR);
 374         mlxsw_sp1_kvdl_parts_fini(kvdl);
 375 }
 376 
 377 const struct mlxsw_sp_kvdl_ops mlxsw_sp1_kvdl_ops = {
 378         .priv_size = sizeof(struct mlxsw_sp1_kvdl),
 379         .init = mlxsw_sp1_kvdl_init,
 380         .fini = mlxsw_sp1_kvdl_fini,
 381         .alloc = mlxsw_sp1_kvdl_alloc,
 382         .free = mlxsw_sp1_kvdl_free,
 383         .alloc_size_query = mlxsw_sp1_kvdl_alloc_size_query,
 384 };
 385 
 386 int mlxsw_sp1_kvdl_resources_register(struct mlxsw_core *mlxsw_core)
 387 {
 388         struct devlink *devlink = priv_to_devlink(mlxsw_core);
 389         static struct devlink_resource_size_params size_params;
 390         u32 kvdl_max_size;
 391         int err;
 392 
 393         kvdl_max_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) -
 394                         MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE) -
 395                         MLXSW_CORE_RES_GET(mlxsw_core, KVD_DOUBLE_MIN_SIZE);
 396 
 397         devlink_resource_size_params_init(&size_params, 0, kvdl_max_size,
 398                                           MLXSW_SP1_KVDL_SINGLE_ALLOC_SIZE,
 399                                           DEVLINK_RESOURCE_UNIT_ENTRY);
 400         err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_SINGLES,
 401                                         MLXSW_SP1_KVDL_SINGLE_SIZE,
 402                                         MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE,
 403                                         MLXSW_SP_RESOURCE_KVD_LINEAR,
 404                                         &size_params);
 405         if (err)
 406                 return err;
 407 
 408         devlink_resource_size_params_init(&size_params, 0, kvdl_max_size,
 409                                           MLXSW_SP1_KVDL_CHUNKS_ALLOC_SIZE,
 410                                           DEVLINK_RESOURCE_UNIT_ENTRY);
 411         err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_CHUNKS,
 412                                         MLXSW_SP1_KVDL_CHUNKS_SIZE,
 413                                         MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS,
 414                                         MLXSW_SP_RESOURCE_KVD_LINEAR,
 415                                         &size_params);
 416         if (err)
 417                 return err;
 418 
 419         devlink_resource_size_params_init(&size_params, 0, kvdl_max_size,
 420                                           MLXSW_SP1_KVDL_LARGE_CHUNKS_ALLOC_SIZE,
 421                                           DEVLINK_RESOURCE_UNIT_ENTRY);
 422         err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_LARGE_CHUNKS,
 423                                         MLXSW_SP1_KVDL_LARGE_CHUNKS_SIZE,
 424                                         MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS,
 425                                         MLXSW_SP_RESOURCE_KVD_LINEAR,
 426                                         &size_params);
 427         return err;
 428 }

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