brintos

brintos / linux-shallow public Read only

0
0
Text · 11.9 KiB · 1e3fc98 Raw
428 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* 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 010#define MLXSW_SP1_KVDL_SINGLE_SIZE 1638411#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 4915217#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 128#define MLXSW_SP1_KVDL_CHUNKS_ALLOC_SIZE 3229#define MLXSW_SP1_KVDL_LARGE_CHUNKS_ALLOC_SIZE 51230 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 u32105mlxsw_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 int112mlxsw_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 the155	 * 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 = devl_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	devl_resource_occ_get_register(devlink,342				       MLXSW_SP_RESOURCE_KVD_LINEAR,343				       mlxsw_sp1_kvdl_occ_get,344				       kvdl);345	devl_resource_occ_get_register(devlink,346				       MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE,347				       mlxsw_sp1_kvdl_single_occ_get,348				       kvdl);349	devl_resource_occ_get_register(devlink,350				       MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS,351				       mlxsw_sp1_kvdl_chunks_occ_get,352				       kvdl);353	devl_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	devl_resource_occ_get_unregister(devlink,366					 MLXSW_SP_RESOURCE_KVD_LINEAR_LARGE_CHUNKS);367	devl_resource_occ_get_unregister(devlink,368					 MLXSW_SP_RESOURCE_KVD_LINEAR_CHUNKS);369	devl_resource_occ_get_unregister(devlink,370					 MLXSW_SP_RESOURCE_KVD_LINEAR_SINGLE);371	devl_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 = devl_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 = devl_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 = devl_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}428