1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
3
4#include <linux/kernel.h>
5#include <linux/mutex.h>
6#include <linux/slab.h>
7
8#include "spectrum.h"
9
10struct mlxsw_sp_kvdl {
11	const struct mlxsw_sp_kvdl_ops *kvdl_ops;
12	struct mutex kvdl_lock; /* Protects kvdl allocations */
13	unsigned long priv[];
14	/* priv has to be always the last item */
15};
16
17int mlxsw_sp_kvdl_init(struct mlxsw_sp *mlxsw_sp)
18{
19	const struct mlxsw_sp_kvdl_ops *kvdl_ops = mlxsw_sp->kvdl_ops;
20	struct mlxsw_sp_kvdl *kvdl;
21	int err;
22
23	kvdl = kzalloc(sizeof(*mlxsw_sp->kvdl) + kvdl_ops->priv_size,
24		       GFP_KERNEL);
25	if (!kvdl)
26		return -ENOMEM;
27	mutex_init(&kvdl->kvdl_lock);
28	kvdl->kvdl_ops = kvdl_ops;
29	mlxsw_sp->kvdl = kvdl;
30
31	err = kvdl_ops->init(mlxsw_sp, kvdl->priv);
32	if (err)
33		goto err_init;
34	return 0;
35
36err_init:
37	mutex_destroy(&kvdl->kvdl_lock);
38	kfree(kvdl);
39	return err;
40}
41
42void mlxsw_sp_kvdl_fini(struct mlxsw_sp *mlxsw_sp)
43{
44	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
45
46	kvdl->kvdl_ops->fini(mlxsw_sp, kvdl->priv);
47	mutex_destroy(&kvdl->kvdl_lock);
48	kfree(kvdl);
49}
50
51int mlxsw_sp_kvdl_alloc(struct mlxsw_sp *mlxsw_sp,
52			enum mlxsw_sp_kvdl_entry_type type,
53			unsigned int entry_count, u32 *p_entry_index)
54{
55	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
56	int err;
57
58	mutex_lock(&kvdl->kvdl_lock);
59	err = kvdl->kvdl_ops->alloc(mlxsw_sp, kvdl->priv, type,
60				    entry_count, p_entry_index);
61	mutex_unlock(&kvdl->kvdl_lock);
62
63	return err;
64}
65
66void mlxsw_sp_kvdl_free(struct mlxsw_sp *mlxsw_sp,
67			enum mlxsw_sp_kvdl_entry_type type,
68			unsigned int entry_count, int entry_index)
69{
70	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
71
72	mutex_lock(&kvdl->kvdl_lock);
73	kvdl->kvdl_ops->free(mlxsw_sp, kvdl->priv, type,
74			     entry_count, entry_index);
75	mutex_unlock(&kvdl->kvdl_lock);
76}
77
78int mlxsw_sp_kvdl_alloc_count_query(struct mlxsw_sp *mlxsw_sp,
79				    enum mlxsw_sp_kvdl_entry_type type,
80				    unsigned int entry_count,
81				    unsigned int *p_alloc_count)
82{
83	struct mlxsw_sp_kvdl *kvdl = mlxsw_sp->kvdl;
84
85	return kvdl->kvdl_ops->alloc_size_query(mlxsw_sp, kvdl->priv, type,
86						entry_count, p_alloc_count);
87}
88