Merge branch 'for-v5.13-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/ebieder...
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_kvdl.c
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 }