cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

spectrum1_kvdl.c (12149B)


      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
     31struct 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
     39enum 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
     53static 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
     61struct mlxsw_sp1_kvdl_part {
     62	struct mlxsw_sp1_kvdl_part_info info;
     63	unsigned long usage[];	/* Entries */
     64};
     65
     66struct mlxsw_sp1_kvdl {
     67	struct mlxsw_sp1_kvdl_part *parts[MLXSW_SP1_KVDL_PARTS_INFO_LEN];
     68};
     69
     70static struct mlxsw_sp1_kvdl_part *
     71mlxsw_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
     88static struct mlxsw_sp1_kvdl_part *
     89mlxsw_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
    104static u32
    105mlxsw_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
    111static unsigned int
    112mlxsw_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
    118static 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
    136static 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
    146static 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
    164static 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
    177static 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
    195static 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
    207static struct mlxsw_sp1_kvdl_part *
    208mlxsw_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	u64 resource_size;
    217	int err;
    218
    219	err = devlink_resource_size_get(devlink, info->resource_id,
    220					&resource_size);
    221	if (err) {
    222		need_update = false;
    223		resource_size = info->end_index - info->start_index + 1;
    224	}
    225
    226	nr_entries = div_u64(resource_size, info->alloc_size);
    227	part = kzalloc(struct_size(part, usage, BITS_TO_LONGS(nr_entries)),
    228		       GFP_KERNEL);
    229	if (!part)
    230		return ERR_PTR(-ENOMEM);
    231
    232	memcpy(&part->info, info, sizeof(part->info));
    233
    234	if (need_update)
    235		mlxsw_sp1_kvdl_part_update(part, part_prev, resource_size);
    236	return part;
    237}
    238
    239static void mlxsw_sp1_kvdl_part_fini(struct mlxsw_sp1_kvdl_part *part)
    240{
    241	kfree(part);
    242}
    243
    244static int mlxsw_sp1_kvdl_parts_init(struct mlxsw_sp *mlxsw_sp,
    245				     struct mlxsw_sp1_kvdl *kvdl)
    246{
    247	const struct mlxsw_sp1_kvdl_part_info *info;
    248	struct mlxsw_sp1_kvdl_part *part_prev = NULL;
    249	int err, i;
    250
    251	for (i = 0; i < MLXSW_SP1_KVDL_PARTS_INFO_LEN; i++) {
    252		info = &mlxsw_sp1_kvdl_parts_info[i];
    253		kvdl->parts[i] = mlxsw_sp1_kvdl_part_init(mlxsw_sp, info,
    254							  part_prev);
    255		if (IS_ERR(kvdl->parts[i])) {
    256			err = PTR_ERR(kvdl->parts[i]);
    257			goto err_kvdl_part_init;
    258		}
    259		part_prev = kvdl->parts[i];
    260	}
    261	return 0;
    262
    263err_kvdl_part_init:
    264	for (i--; i >= 0; i--)
    265		mlxsw_sp1_kvdl_part_fini(kvdl->parts[i]);
    266	return err;
    267}
    268
    269static void mlxsw_sp1_kvdl_parts_fini(struct mlxsw_sp1_kvdl *kvdl)
    270{
    271	int i;
    272
    273	for (i = 0; i < MLXSW_SP1_KVDL_PARTS_INFO_LEN; i++)
    274		mlxsw_sp1_kvdl_part_fini(kvdl->parts[i]);
    275}
    276
    277static u64 mlxsw_sp1_kvdl_part_occ(struct mlxsw_sp1_kvdl_part *part)
    278{
    279	const struct mlxsw_sp1_kvdl_part_info *info = &part->info;
    280	unsigned int nr_entries;
    281	int bit = -1;
    282	u64 occ = 0;
    283
    284	nr_entries = (info->end_index -
    285		      info->start_index + 1) /
    286		      info->alloc_size;
    287	while ((bit = find_next_bit(part->usage, nr_entries, bit + 1))
    288		< nr_entries)
    289		occ += info->alloc_size;
    290	return occ;
    291}
    292
    293static u64 mlxsw_sp1_kvdl_occ_get(void *priv)
    294{
    295	const struct mlxsw_sp1_kvdl *kvdl = priv;
    296	u64 occ = 0;
    297	int i;
    298
    299	for (i = 0; i < MLXSW_SP1_KVDL_PARTS_INFO_LEN; i++)
    300		occ += mlxsw_sp1_kvdl_part_occ(kvdl->parts[i]);
    301
    302	return occ;
    303}
    304
    305static u64 mlxsw_sp1_kvdl_single_occ_get(void *priv)
    306{
    307	const struct mlxsw_sp1_kvdl *kvdl = priv;
    308	struct mlxsw_sp1_kvdl_part *part;
    309
    310	part = kvdl->parts[MLXSW_SP1_KVDL_PART_ID_SINGLE];
    311	return mlxsw_sp1_kvdl_part_occ(part);
    312}
    313
    314static u64 mlxsw_sp1_kvdl_chunks_occ_get(void *priv)
    315{
    316	const struct mlxsw_sp1_kvdl *kvdl = priv;
    317	struct mlxsw_sp1_kvdl_part *part;
    318
    319	part = kvdl->parts[MLXSW_SP1_KVDL_PART_ID_CHUNKS];
    320	return mlxsw_sp1_kvdl_part_occ(part);
    321}
    322
    323static u64 mlxsw_sp1_kvdl_large_chunks_occ_get(void *priv)
    324{
    325	const struct mlxsw_sp1_kvdl *kvdl = priv;
    326	struct mlxsw_sp1_kvdl_part *part;
    327
    328	part = kvdl->parts[MLXSW_SP1_KVDL_PART_ID_LARGE_CHUNKS];
    329	return mlxsw_sp1_kvdl_part_occ(part);
    330}
    331
    332static int mlxsw_sp1_kvdl_init(struct mlxsw_sp *mlxsw_sp, void *priv)
    333{
    334	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
    335	struct mlxsw_sp1_kvdl *kvdl = priv;
    336	int err;
    337
    338	err = mlxsw_sp1_kvdl_parts_init(mlxsw_sp, kvdl);
    339	if (err)
    340		return err;
    341	devlink_resource_occ_get_register(devlink,
    342					  MLXSW_SP_RESOURCE_KVD_LINEAR,
    343					  mlxsw_sp1_kvdl_occ_get,
    344					  kvdl);
    345	devlink_resource_occ_get_register(devlink,
    346					  MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE,
    347					  mlxsw_sp1_kvdl_single_occ_get,
    348					  kvdl);
    349	devlink_resource_occ_get_register(devlink,
    350					  MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS,
    351					  mlxsw_sp1_kvdl_chunks_occ_get,
    352					  kvdl);
    353	devlink_resource_occ_get_register(devlink,
    354					  MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS,
    355					  mlxsw_sp1_kvdl_large_chunks_occ_get,
    356					  kvdl);
    357	return 0;
    358}
    359
    360static void mlxsw_sp1_kvdl_fini(struct mlxsw_sp *mlxsw_sp, void *priv)
    361{
    362	struct devlink *devlink = priv_to_devlink(mlxsw_sp->core);
    363	struct mlxsw_sp1_kvdl *kvdl = priv;
    364
    365	devlink_resource_occ_get_unregister(devlink,
    366					    MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS);
    367	devlink_resource_occ_get_unregister(devlink,
    368					    MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS);
    369	devlink_resource_occ_get_unregister(devlink,
    370					    MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE);
    371	devlink_resource_occ_get_unregister(devlink,
    372					    MLXSW_SP_RESOURCE_KVD_LINEAR);
    373	mlxsw_sp1_kvdl_parts_fini(kvdl);
    374}
    375
    376const struct mlxsw_sp_kvdl_ops mlxsw_sp1_kvdl_ops = {
    377	.priv_size = sizeof(struct mlxsw_sp1_kvdl),
    378	.init = mlxsw_sp1_kvdl_init,
    379	.fini = mlxsw_sp1_kvdl_fini,
    380	.alloc = mlxsw_sp1_kvdl_alloc,
    381	.free = mlxsw_sp1_kvdl_free,
    382	.alloc_size_query = mlxsw_sp1_kvdl_alloc_size_query,
    383};
    384
    385int mlxsw_sp1_kvdl_resources_register(struct mlxsw_core *mlxsw_core)
    386{
    387	struct devlink *devlink = priv_to_devlink(mlxsw_core);
    388	static struct devlink_resource_size_params size_params;
    389	u32 kvdl_max_size;
    390	int err;
    391
    392	kvdl_max_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE) -
    393			MLXSW_CORE_RES_GET(mlxsw_core, KVD_SINGLE_MIN_SIZE) -
    394			MLXSW_CORE_RES_GET(mlxsw_core, KVD_DOUBLE_MIN_SIZE);
    395
    396	devlink_resource_size_params_init(&size_params, 0, kvdl_max_size,
    397					  MLXSW_SP1_KVDL_SINGLE_ALLOC_SIZE,
    398					  DEVLINK_RESOURCE_UNIT_ENTRY);
    399	err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_SINGLES,
    400					MLXSW_SP1_KVDL_SINGLE_SIZE,
    401					MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE,
    402					MLXSW_SP_RESOURCE_KVD_LINEAR,
    403					&size_params);
    404	if (err)
    405		return err;
    406
    407	devlink_resource_size_params_init(&size_params, 0, kvdl_max_size,
    408					  MLXSW_SP1_KVDL_CHUNKS_ALLOC_SIZE,
    409					  DEVLINK_RESOURCE_UNIT_ENTRY);
    410	err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_CHUNKS,
    411					MLXSW_SP1_KVDL_CHUNKS_SIZE,
    412					MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS,
    413					MLXSW_SP_RESOURCE_KVD_LINEAR,
    414					&size_params);
    415	if (err)
    416		return err;
    417
    418	devlink_resource_size_params_init(&size_params, 0, kvdl_max_size,
    419					  MLXSW_SP1_KVDL_LARGE_CHUNKS_ALLOC_SIZE,
    420					  DEVLINK_RESOURCE_UNIT_ENTRY);
    421	err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD_LINEAR_LARGE_CHUNKS,
    422					MLXSW_SP1_KVDL_LARGE_CHUNKS_SIZE,
    423					MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS,
    424					MLXSW_SP_RESOURCE_KVD_LINEAR,
    425					&size_params);
    426	return err;
    427}