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