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 
10 struct 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 
17 int 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 
36 err_init:
37 	mutex_destroy(&kvdl->kvdl_lock);
38 	kfree(kvdl);
39 	return err;
40 }
41 
42 void 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 
51 int 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 
66 void 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 
78 int 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