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(size: 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(lock: &kvdl->kvdl_lock); |
38 | kfree(objp: 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(lock: &kvdl->kvdl_lock); |
48 | kfree(objp: 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(lock: &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(lock: &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 | |