18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
28c2ecf20Sopenharmony_ci/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/kernel.h>
58c2ecf20Sopenharmony_ci#include <linux/mutex.h>
68c2ecf20Sopenharmony_ci#include <linux/slab.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "spectrum.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_cistruct mlxsw_sp_kvdl {
118c2ecf20Sopenharmony_ci	const struct mlxsw_sp_kvdl_ops *kvdl_ops;
128c2ecf20Sopenharmony_ci	struct mutex kvdl_lock; /* Protects kvdl allocations */
138c2ecf20Sopenharmony_ci	unsigned long priv[];
148c2ecf20Sopenharmony_ci	/* priv has to be always the last item */
158c2ecf20Sopenharmony_ci};
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ciint mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	const struct mlxsw_sp_kvdl_ops *kvdl_ops = mlxsw_sp->kvdl_ops;
208c2ecf20Sopenharmony_ci	struct mlxsw_sp_kvdl *kvdl;
218c2ecf20Sopenharmony_ci	int err;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	kvdl = kzalloc(sizeof(*mlxsw_sp->kvdl) + kvdl_ops->priv_size,
248c2ecf20Sopenharmony_ci		       GFP_KERNEL);
258c2ecf20Sopenharmony_ci	if (!kvdl)
268c2ecf20Sopenharmony_ci		return -ENOMEM;
278c2ecf20Sopenharmony_ci	mutex_init(&kvdl->kvdl_lock);
288c2ecf20Sopenharmony_ci	kvdl->kvdl_ops = kvdl_ops;
298c2ecf20Sopenharmony_ci	mlxsw_sp->kvdl = kvdl;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	err = kvdl_ops->init(mlxsw_sp, kvdl->priv);
328c2ecf20Sopenharmony_ci	if (err)
338c2ecf20Sopenharmony_ci		goto err_init;
348c2ecf20Sopenharmony_ci	return 0;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cierr_init:
378c2ecf20Sopenharmony_ci	mutex_destroy(&kvdl->kvdl_lock);
388c2ecf20Sopenharmony_ci	kfree(kvdl);
398c2ecf20Sopenharmony_ci	return err;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_civoid mlxsw_sp_kvdl_fini(struct mlxsw_sp *mlxsw_sp)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	kvdl->kvdl_ops->fini(mlxsw_sp, kvdl->priv);
478c2ecf20Sopenharmony_ci	mutex_destroy(&kvdl->kvdl_lock);
488c2ecf20Sopenharmony_ci	kfree(kvdl);
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciint mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp,
528c2ecf20Sopenharmony_ci			enum mlxsw_sp_kvdl_entry_type type,
538c2ecf20Sopenharmony_ci			unsigned int entry_count, u32 *p_entry_index)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
568c2ecf20Sopenharmony_ci	int err;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	mutex_lock(&kvdl->kvdl_lock);
598c2ecf20Sopenharmony_ci	err = kvdl->kvdl_ops->alloc(mlxsw_sp, kvdl->priv, type,
608c2ecf20Sopenharmony_ci				    entry_count, p_entry_index);
618c2ecf20Sopenharmony_ci	mutex_unlock(&kvdl->kvdl_lock);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	return err;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_civoid mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp,
678c2ecf20Sopenharmony_ci			enum mlxsw_sp_kvdl_entry_type type,
688c2ecf20Sopenharmony_ci			unsigned int entry_count, int entry_index)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	mutex_lock(&kvdl->kvdl_lock);
738c2ecf20Sopenharmony_ci	kvdl->kvdl_ops->free(mlxsw_sp, kvdl->priv, type,
748c2ecf20Sopenharmony_ci			     entry_count, entry_index);
758c2ecf20Sopenharmony_ci	mutex_unlock(&kvdl->kvdl_lock);
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ciint mlxsw_sp_kvdl_alloc_count_query(struct mlxsw_sp *mlxsw_sp,
798c2ecf20Sopenharmony_ci				    enum mlxsw_sp_kvdl_entry_type type,
808c2ecf20Sopenharmony_ci				    unsigned int entry_count,
818c2ecf20Sopenharmony_ci				    unsigned int *p_alloc_count)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	return kvdl->kvdl_ops->alloc_size_query(mlxsw_sp, kvdl->priv, type,
868c2ecf20Sopenharmony_ci						entry_count, p_alloc_count);
878c2ecf20Sopenharmony_ci}
88