]>
Commit | Line | Data |
---|---|---|
dbaf0624 G |
1 | /* Management for virtio crypto devices (refer to adf_dev_mgr.c) |
2 | * | |
3 | * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, see <http://www.gnu.org/licenses/>. | |
17 | */ | |
18 | ||
19 | #include <linux/mutex.h> | |
20 | #include <linux/list.h> | |
21 | #include <linux/module.h> | |
22 | ||
23 | #include <uapi/linux/virtio_crypto.h> | |
24 | #include "virtio_crypto_common.h" | |
25 | ||
26 | static LIST_HEAD(virtio_crypto_table); | |
27 | static uint32_t num_devices; | |
28 | ||
29 | /* The table_lock protects the above global list and num_devices */ | |
30 | static DEFINE_MUTEX(table_lock); | |
31 | ||
32 | #define VIRTIO_CRYPTO_MAX_DEVICES 32 | |
33 | ||
34 | ||
35 | /* | |
36 | * virtcrypto_devmgr_add_dev() - Add vcrypto_dev to the acceleration | |
37 | * framework. | |
38 | * @vcrypto_dev: Pointer to virtio crypto device. | |
39 | * | |
40 | * Function adds virtio crypto device to the global list. | |
41 | * To be used by virtio crypto device specific drivers. | |
42 | * | |
43 | * Return: 0 on success, error code othewise. | |
44 | */ | |
45 | int virtcrypto_devmgr_add_dev(struct virtio_crypto *vcrypto_dev) | |
46 | { | |
47 | struct list_head *itr; | |
48 | ||
49 | mutex_lock(&table_lock); | |
50 | if (num_devices == VIRTIO_CRYPTO_MAX_DEVICES) { | |
51 | pr_info("virtio_crypto: only support up to %d devices\n", | |
52 | VIRTIO_CRYPTO_MAX_DEVICES); | |
53 | mutex_unlock(&table_lock); | |
54 | return -EFAULT; | |
55 | } | |
56 | ||
57 | list_for_each(itr, &virtio_crypto_table) { | |
58 | struct virtio_crypto *ptr = | |
59 | list_entry(itr, struct virtio_crypto, list); | |
60 | ||
61 | if (ptr == vcrypto_dev) { | |
62 | mutex_unlock(&table_lock); | |
63 | return -EEXIST; | |
64 | } | |
65 | } | |
66 | atomic_set(&vcrypto_dev->ref_count, 0); | |
67 | list_add_tail(&vcrypto_dev->list, &virtio_crypto_table); | |
68 | vcrypto_dev->dev_id = num_devices++; | |
69 | mutex_unlock(&table_lock); | |
70 | return 0; | |
71 | } | |
72 | ||
73 | struct list_head *virtcrypto_devmgr_get_head(void) | |
74 | { | |
75 | return &virtio_crypto_table; | |
76 | } | |
77 | ||
78 | /* | |
79 | * virtcrypto_devmgr_rm_dev() - Remove vcrypto_dev from the acceleration | |
80 | * framework. | |
81 | * @vcrypto_dev: Pointer to virtio crypto device. | |
82 | * | |
83 | * Function removes virtio crypto device from the acceleration framework. | |
84 | * To be used by virtio crypto device specific drivers. | |
85 | * | |
86 | * Return: void | |
87 | */ | |
88 | void virtcrypto_devmgr_rm_dev(struct virtio_crypto *vcrypto_dev) | |
89 | { | |
90 | mutex_lock(&table_lock); | |
91 | list_del(&vcrypto_dev->list); | |
92 | num_devices--; | |
93 | mutex_unlock(&table_lock); | |
94 | } | |
95 | ||
96 | /* | |
97 | * virtcrypto_devmgr_get_first() | |
98 | * | |
99 | * Function returns the first virtio crypto device from the acceleration | |
100 | * framework. | |
101 | * | |
102 | * To be used by virtio crypto device specific drivers. | |
103 | * | |
104 | * Return: pointer to vcrypto_dev or NULL if not found. | |
105 | */ | |
106 | struct virtio_crypto *virtcrypto_devmgr_get_first(void) | |
107 | { | |
108 | struct virtio_crypto *dev = NULL; | |
109 | ||
110 | mutex_lock(&table_lock); | |
111 | if (!list_empty(&virtio_crypto_table)) | |
112 | dev = list_first_entry(&virtio_crypto_table, | |
113 | struct virtio_crypto, | |
114 | list); | |
115 | mutex_unlock(&table_lock); | |
116 | return dev; | |
117 | } | |
118 | ||
119 | /* | |
120 | * virtcrypto_dev_in_use() - Check whether vcrypto_dev is currently in use | |
121 | * @vcrypto_dev: Pointer to virtio crypto device. | |
122 | * | |
123 | * To be used by virtio crypto device specific drivers. | |
124 | * | |
125 | * Return: 1 when device is in use, 0 otherwise. | |
126 | */ | |
127 | int virtcrypto_dev_in_use(struct virtio_crypto *vcrypto_dev) | |
128 | { | |
129 | return atomic_read(&vcrypto_dev->ref_count) != 0; | |
130 | } | |
131 | ||
132 | /* | |
133 | * virtcrypto_dev_get() - Increment vcrypto_dev reference count | |
134 | * @vcrypto_dev: Pointer to virtio crypto device. | |
135 | * | |
136 | * Increment the vcrypto_dev refcount and if this is the first time | |
137 | * incrementing it during this period the vcrypto_dev is in use, | |
138 | * increment the module refcount too. | |
139 | * To be used by virtio crypto device specific drivers. | |
140 | * | |
141 | * Return: 0 when successful, EFAULT when fail to bump module refcount | |
142 | */ | |
143 | int virtcrypto_dev_get(struct virtio_crypto *vcrypto_dev) | |
144 | { | |
145 | if (atomic_add_return(1, &vcrypto_dev->ref_count) == 1) | |
146 | if (!try_module_get(vcrypto_dev->owner)) | |
147 | return -EFAULT; | |
148 | return 0; | |
149 | } | |
150 | ||
151 | /* | |
152 | * virtcrypto_dev_put() - Decrement vcrypto_dev reference count | |
153 | * @vcrypto_dev: Pointer to virtio crypto device. | |
154 | * | |
155 | * Decrement the vcrypto_dev refcount and if this is the last time | |
156 | * decrementing it during this period the vcrypto_dev is in use, | |
157 | * decrement the module refcount too. | |
158 | * To be used by virtio crypto device specific drivers. | |
159 | * | |
160 | * Return: void | |
161 | */ | |
162 | void virtcrypto_dev_put(struct virtio_crypto *vcrypto_dev) | |
163 | { | |
164 | if (atomic_sub_return(1, &vcrypto_dev->ref_count) == 0) | |
165 | module_put(vcrypto_dev->owner); | |
166 | } | |
167 | ||
168 | /* | |
169 | * virtcrypto_dev_started() - Check whether device has started | |
170 | * @vcrypto_dev: Pointer to virtio crypto device. | |
171 | * | |
172 | * To be used by virtio crypto device specific drivers. | |
173 | * | |
174 | * Return: 1 when the device has started, 0 otherwise | |
175 | */ | |
176 | int virtcrypto_dev_started(struct virtio_crypto *vcrypto_dev) | |
177 | { | |
178 | return (vcrypto_dev->status & VIRTIO_CRYPTO_S_HW_READY); | |
179 | } | |
180 | ||
181 | /* | |
182 | * virtcrypto_get_dev_node() - Get vcrypto_dev on the node. | |
183 | * @node: Node id the driver works. | |
184 | * | |
185 | * Function returns the virtio crypto device used fewest on the node. | |
186 | * | |
187 | * To be used by virtio crypto device specific drivers. | |
188 | * | |
189 | * Return: pointer to vcrypto_dev or NULL if not found. | |
190 | */ | |
191 | struct virtio_crypto *virtcrypto_get_dev_node(int node) | |
192 | { | |
193 | struct virtio_crypto *vcrypto_dev = NULL, *tmp_dev; | |
194 | unsigned long best = ~0; | |
195 | unsigned long ctr; | |
196 | ||
197 | mutex_lock(&table_lock); | |
198 | list_for_each_entry(tmp_dev, virtcrypto_devmgr_get_head(), list) { | |
199 | ||
200 | if ((node == dev_to_node(&tmp_dev->vdev->dev) || | |
201 | dev_to_node(&tmp_dev->vdev->dev) < 0) && | |
202 | virtcrypto_dev_started(tmp_dev)) { | |
203 | ctr = atomic_read(&tmp_dev->ref_count); | |
204 | if (best > ctr) { | |
205 | vcrypto_dev = tmp_dev; | |
206 | best = ctr; | |
207 | } | |
208 | } | |
209 | } | |
210 | ||
211 | if (!vcrypto_dev) { | |
212 | pr_info("virtio_crypto: Could not find a device on node %d\n", | |
213 | node); | |
214 | /* Get any started device */ | |
215 | list_for_each_entry(tmp_dev, | |
216 | virtcrypto_devmgr_get_head(), list) { | |
217 | if (virtcrypto_dev_started(tmp_dev)) { | |
218 | vcrypto_dev = tmp_dev; | |
219 | break; | |
220 | } | |
221 | } | |
222 | } | |
223 | mutex_unlock(&table_lock); | |
224 | if (!vcrypto_dev) | |
225 | return NULL; | |
226 | ||
227 | virtcrypto_dev_get(vcrypto_dev); | |
228 | return vcrypto_dev; | |
229 | } | |
230 | ||
231 | /* | |
232 | * virtcrypto_dev_start() - Start virtio crypto device | |
233 | * @vcrypto: Pointer to virtio crypto device. | |
234 | * | |
235 | * Function notifies all the registered services that the virtio crypto device | |
236 | * is ready to be used. | |
237 | * To be used by virtio crypto device specific drivers. | |
238 | * | |
239 | * Return: 0 on success, EFAULT when fail to register algorithms | |
240 | */ | |
241 | int virtcrypto_dev_start(struct virtio_crypto *vcrypto) | |
242 | { | |
243 | if (virtio_crypto_algs_register()) { | |
244 | pr_err("virtio_crypto: Failed to register crypto algs\n"); | |
245 | return -EFAULT; | |
246 | } | |
247 | ||
248 | return 0; | |
249 | } | |
250 | ||
251 | /* | |
252 | * virtcrypto_dev_stop() - Stop virtio crypto device | |
253 | * @vcrypto: Pointer to virtio crypto device. | |
254 | * | |
255 | * Function notifies all the registered services that the virtio crypto device | |
256 | * is ready to be used. | |
257 | * To be used by virtio crypto device specific drivers. | |
258 | * | |
259 | * Return: void | |
260 | */ | |
261 | void virtcrypto_dev_stop(struct virtio_crypto *vcrypto) | |
262 | { | |
263 | virtio_crypto_algs_unregister(); | |
264 | } |