162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/kernel.h>
562306a36Sopenharmony_ci#include <linux/mutex.h>
662306a36Sopenharmony_ci#include <linux/slab.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "spectrum.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cistruct mlxsw_sp_kvdl {
1162306a36Sopenharmony_ci	const struct mlxsw_sp_kvdl_ops *kvdl_ops;
1262306a36Sopenharmony_ci	struct mutex kvdl_lock; /* Protects kvdl allocations */
1362306a36Sopenharmony_ci	unsigned long priv[];
1462306a36Sopenharmony_ci	/* priv has to be always the last item */
1562306a36Sopenharmony_ci};
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ciint mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	const struct mlxsw_sp_kvdl_ops *kvdl_ops = mlxsw_sp->kvdl_ops;
2062306a36Sopenharmony_ci	struct mlxsw_sp_kvdl *kvdl;
2162306a36Sopenharmony_ci	int err;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	kvdl = kzalloc(sizeof(*mlxsw_sp->kvdl) + kvdl_ops->priv_size,
2462306a36Sopenharmony_ci		       GFP_KERNEL);
2562306a36Sopenharmony_ci	if (!kvdl)
2662306a36Sopenharmony_ci		return -ENOMEM;
2762306a36Sopenharmony_ci	mutex_init(&kvdl->kvdl_lock);
2862306a36Sopenharmony_ci	kvdl->kvdl_ops = kvdl_ops;
2962306a36Sopenharmony_ci	mlxsw_sp->kvdl = kvdl;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	err = kvdl_ops->init(mlxsw_sp, kvdl->priv);
3262306a36Sopenharmony_ci	if (err)
3362306a36Sopenharmony_ci		goto err_init;
3462306a36Sopenharmony_ci	return 0;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cierr_init:
3762306a36Sopenharmony_ci	mutex_destroy(&kvdl->kvdl_lock);
3862306a36Sopenharmony_ci	kfree(kvdl);
3962306a36Sopenharmony_ci	return err;
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_civoid mlxsw_sp_kvdl_fini(struct mlxsw_sp *mlxsw_sp)
4362306a36Sopenharmony_ci{
4462306a36Sopenharmony_ci	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	kvdl->kvdl_ops->fini(mlxsw_sp, kvdl->priv);
4762306a36Sopenharmony_ci	mutex_destroy(&kvdl->kvdl_lock);
4862306a36Sopenharmony_ci	kfree(kvdl);
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciint mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp,
5262306a36Sopenharmony_ci			enum mlxsw_sp_kvdl_entry_type type,
5362306a36Sopenharmony_ci			unsigned int entry_count, u32 *p_entry_index)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
5662306a36Sopenharmony_ci	int err;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	mutex_lock(&kvdl->kvdl_lock);
5962306a36Sopenharmony_ci	err = kvdl->kvdl_ops->alloc(mlxsw_sp, kvdl->priv, type,
6062306a36Sopenharmony_ci				    entry_count, p_entry_index);
6162306a36Sopenharmony_ci	mutex_unlock(&kvdl->kvdl_lock);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	return err;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_civoid mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp,
6762306a36Sopenharmony_ci			enum mlxsw_sp_kvdl_entry_type type,
6862306a36Sopenharmony_ci			unsigned int entry_count, int entry_index)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	mutex_lock(&kvdl->kvdl_lock);
7362306a36Sopenharmony_ci	kvdl->kvdl_ops->free(mlxsw_sp, kvdl->priv, type,
7462306a36Sopenharmony_ci			     entry_count, entry_index);
7562306a36Sopenharmony_ci	mutex_unlock(&kvdl->kvdl_lock);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciint mlxsw_sp_kvdl_alloc_count_query(struct mlxsw_sp *mlxsw_sp,
7962306a36Sopenharmony_ci				    enum mlxsw_sp_kvdl_entry_type type,
8062306a36Sopenharmony_ci				    unsigned int entry_count,
8162306a36Sopenharmony_ci				    unsigned int *p_alloc_count)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return kvdl->kvdl_ops->alloc_size_query(mlxsw_sp, kvdl->priv, type,
8662306a36Sopenharmony_ci						entry_count, p_alloc_count);
8762306a36Sopenharmony_ci}
88