xref: /OK3568_Linux_fs/kernel/drivers/crypto/virtio/virtio_crypto_mgr.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun  /* Management for virtio crypto devices (refer to adf_dev_mgr.c)
3*4882a593Smuzhiyun   *
4*4882a593Smuzhiyun   * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD.
5*4882a593Smuzhiyun   */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/mutex.h>
8*4882a593Smuzhiyun #include <linux/list.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <uapi/linux/virtio_crypto.h>
12*4882a593Smuzhiyun #include "virtio_crypto_common.h"
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun static LIST_HEAD(virtio_crypto_table);
15*4882a593Smuzhiyun static uint32_t num_devices;
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun /* The table_lock protects the above global list and num_devices */
18*4882a593Smuzhiyun static DEFINE_MUTEX(table_lock);
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define VIRTIO_CRYPTO_MAX_DEVICES 32
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun /*
24*4882a593Smuzhiyun  * virtcrypto_devmgr_add_dev() - Add vcrypto_dev to the acceleration
25*4882a593Smuzhiyun  * framework.
26*4882a593Smuzhiyun  * @vcrypto_dev:  Pointer to virtio crypto device.
27*4882a593Smuzhiyun  *
28*4882a593Smuzhiyun  * Function adds virtio crypto device to the global list.
29*4882a593Smuzhiyun  * To be used by virtio crypto device specific drivers.
30*4882a593Smuzhiyun  *
31*4882a593Smuzhiyun  * Return: 0 on success, error code othewise.
32*4882a593Smuzhiyun  */
virtcrypto_devmgr_add_dev(struct virtio_crypto * vcrypto_dev)33*4882a593Smuzhiyun int virtcrypto_devmgr_add_dev(struct virtio_crypto *vcrypto_dev)
34*4882a593Smuzhiyun {
35*4882a593Smuzhiyun 	struct list_head *itr;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	mutex_lock(&table_lock);
38*4882a593Smuzhiyun 	if (num_devices == VIRTIO_CRYPTO_MAX_DEVICES) {
39*4882a593Smuzhiyun 		pr_info("virtio_crypto: only support up to %d devices\n",
40*4882a593Smuzhiyun 			    VIRTIO_CRYPTO_MAX_DEVICES);
41*4882a593Smuzhiyun 		mutex_unlock(&table_lock);
42*4882a593Smuzhiyun 		return -EFAULT;
43*4882a593Smuzhiyun 	}
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	list_for_each(itr, &virtio_crypto_table) {
46*4882a593Smuzhiyun 		struct virtio_crypto *ptr =
47*4882a593Smuzhiyun 				list_entry(itr, struct virtio_crypto, list);
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 		if (ptr == vcrypto_dev) {
50*4882a593Smuzhiyun 			mutex_unlock(&table_lock);
51*4882a593Smuzhiyun 			return -EEXIST;
52*4882a593Smuzhiyun 		}
53*4882a593Smuzhiyun 	}
54*4882a593Smuzhiyun 	atomic_set(&vcrypto_dev->ref_count, 0);
55*4882a593Smuzhiyun 	list_add_tail(&vcrypto_dev->list, &virtio_crypto_table);
56*4882a593Smuzhiyun 	vcrypto_dev->dev_id = num_devices++;
57*4882a593Smuzhiyun 	mutex_unlock(&table_lock);
58*4882a593Smuzhiyun 	return 0;
59*4882a593Smuzhiyun }
60*4882a593Smuzhiyun 
virtcrypto_devmgr_get_head(void)61*4882a593Smuzhiyun struct list_head *virtcrypto_devmgr_get_head(void)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun 	return &virtio_crypto_table;
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun /*
67*4882a593Smuzhiyun  * virtcrypto_devmgr_rm_dev() - Remove vcrypto_dev from the acceleration
68*4882a593Smuzhiyun  * framework.
69*4882a593Smuzhiyun  * @vcrypto_dev:  Pointer to virtio crypto device.
70*4882a593Smuzhiyun  *
71*4882a593Smuzhiyun  * Function removes virtio crypto device from the acceleration framework.
72*4882a593Smuzhiyun  * To be used by virtio crypto device specific drivers.
73*4882a593Smuzhiyun  *
74*4882a593Smuzhiyun  * Return: void
75*4882a593Smuzhiyun  */
virtcrypto_devmgr_rm_dev(struct virtio_crypto * vcrypto_dev)76*4882a593Smuzhiyun void virtcrypto_devmgr_rm_dev(struct virtio_crypto *vcrypto_dev)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun 	mutex_lock(&table_lock);
79*4882a593Smuzhiyun 	list_del(&vcrypto_dev->list);
80*4882a593Smuzhiyun 	num_devices--;
81*4882a593Smuzhiyun 	mutex_unlock(&table_lock);
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun /*
85*4882a593Smuzhiyun  * virtcrypto_devmgr_get_first()
86*4882a593Smuzhiyun  *
87*4882a593Smuzhiyun  * Function returns the first virtio crypto device from the acceleration
88*4882a593Smuzhiyun  * framework.
89*4882a593Smuzhiyun  *
90*4882a593Smuzhiyun  * To be used by virtio crypto device specific drivers.
91*4882a593Smuzhiyun  *
92*4882a593Smuzhiyun  * Return: pointer to vcrypto_dev or NULL if not found.
93*4882a593Smuzhiyun  */
virtcrypto_devmgr_get_first(void)94*4882a593Smuzhiyun struct virtio_crypto *virtcrypto_devmgr_get_first(void)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	struct virtio_crypto *dev = NULL;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	mutex_lock(&table_lock);
99*4882a593Smuzhiyun 	if (!list_empty(&virtio_crypto_table))
100*4882a593Smuzhiyun 		dev = list_first_entry(&virtio_crypto_table,
101*4882a593Smuzhiyun 					struct virtio_crypto,
102*4882a593Smuzhiyun 				    list);
103*4882a593Smuzhiyun 	mutex_unlock(&table_lock);
104*4882a593Smuzhiyun 	return dev;
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun /*
108*4882a593Smuzhiyun  * virtcrypto_dev_in_use() - Check whether vcrypto_dev is currently in use
109*4882a593Smuzhiyun  * @vcrypto_dev: Pointer to virtio crypto device.
110*4882a593Smuzhiyun  *
111*4882a593Smuzhiyun  * To be used by virtio crypto device specific drivers.
112*4882a593Smuzhiyun  *
113*4882a593Smuzhiyun  * Return: 1 when device is in use, 0 otherwise.
114*4882a593Smuzhiyun  */
virtcrypto_dev_in_use(struct virtio_crypto * vcrypto_dev)115*4882a593Smuzhiyun int virtcrypto_dev_in_use(struct virtio_crypto *vcrypto_dev)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	return atomic_read(&vcrypto_dev->ref_count) != 0;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun /*
121*4882a593Smuzhiyun  * virtcrypto_dev_get() - Increment vcrypto_dev reference count
122*4882a593Smuzhiyun  * @vcrypto_dev: Pointer to virtio crypto device.
123*4882a593Smuzhiyun  *
124*4882a593Smuzhiyun  * Increment the vcrypto_dev refcount and if this is the first time
125*4882a593Smuzhiyun  * incrementing it during this period the vcrypto_dev is in use,
126*4882a593Smuzhiyun  * increment the module refcount too.
127*4882a593Smuzhiyun  * To be used by virtio crypto device specific drivers.
128*4882a593Smuzhiyun  *
129*4882a593Smuzhiyun  * Return: 0 when successful, EFAULT when fail to bump module refcount
130*4882a593Smuzhiyun  */
virtcrypto_dev_get(struct virtio_crypto * vcrypto_dev)131*4882a593Smuzhiyun int virtcrypto_dev_get(struct virtio_crypto *vcrypto_dev)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	if (atomic_add_return(1, &vcrypto_dev->ref_count) == 1)
134*4882a593Smuzhiyun 		if (!try_module_get(vcrypto_dev->owner))
135*4882a593Smuzhiyun 			return -EFAULT;
136*4882a593Smuzhiyun 	return 0;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun /*
140*4882a593Smuzhiyun  * virtcrypto_dev_put() - Decrement vcrypto_dev reference count
141*4882a593Smuzhiyun  * @vcrypto_dev: Pointer to virtio crypto device.
142*4882a593Smuzhiyun  *
143*4882a593Smuzhiyun  * Decrement the vcrypto_dev refcount and if this is the last time
144*4882a593Smuzhiyun  * decrementing it during this period the vcrypto_dev is in use,
145*4882a593Smuzhiyun  * decrement the module refcount too.
146*4882a593Smuzhiyun  * To be used by virtio crypto device specific drivers.
147*4882a593Smuzhiyun  *
148*4882a593Smuzhiyun  * Return: void
149*4882a593Smuzhiyun  */
virtcrypto_dev_put(struct virtio_crypto * vcrypto_dev)150*4882a593Smuzhiyun void virtcrypto_dev_put(struct virtio_crypto *vcrypto_dev)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun 	if (atomic_sub_return(1, &vcrypto_dev->ref_count) == 0)
153*4882a593Smuzhiyun 		module_put(vcrypto_dev->owner);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun /*
157*4882a593Smuzhiyun  * virtcrypto_dev_started() - Check whether device has started
158*4882a593Smuzhiyun  * @vcrypto_dev: Pointer to virtio crypto device.
159*4882a593Smuzhiyun  *
160*4882a593Smuzhiyun  * To be used by virtio crypto device specific drivers.
161*4882a593Smuzhiyun  *
162*4882a593Smuzhiyun  * Return: 1 when the device has started, 0 otherwise
163*4882a593Smuzhiyun  */
virtcrypto_dev_started(struct virtio_crypto * vcrypto_dev)164*4882a593Smuzhiyun int virtcrypto_dev_started(struct virtio_crypto *vcrypto_dev)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	return (vcrypto_dev->status & VIRTIO_CRYPTO_S_HW_READY);
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun /*
170*4882a593Smuzhiyun  * virtcrypto_get_dev_node() - Get vcrypto_dev on the node.
171*4882a593Smuzhiyun  * @node:  Node id the driver works.
172*4882a593Smuzhiyun  * @service: Crypto service that needs to be supported by the
173*4882a593Smuzhiyun  *	      dev
174*4882a593Smuzhiyun  * @algo: The algorithm number that needs to be supported by the
175*4882a593Smuzhiyun  *	  dev
176*4882a593Smuzhiyun  *
177*4882a593Smuzhiyun  * Function returns the virtio crypto device used fewest on the node,
178*4882a593Smuzhiyun  * and supports the given crypto service and algorithm.
179*4882a593Smuzhiyun  *
180*4882a593Smuzhiyun  * To be used by virtio crypto device specific drivers.
181*4882a593Smuzhiyun  *
182*4882a593Smuzhiyun  * Return: pointer to vcrypto_dev or NULL if not found.
183*4882a593Smuzhiyun  */
virtcrypto_get_dev_node(int node,uint32_t service,uint32_t algo)184*4882a593Smuzhiyun struct virtio_crypto *virtcrypto_get_dev_node(int node, uint32_t service,
185*4882a593Smuzhiyun 					      uint32_t algo)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun 	struct virtio_crypto *vcrypto_dev = NULL, *tmp_dev;
188*4882a593Smuzhiyun 	unsigned long best = ~0;
189*4882a593Smuzhiyun 	unsigned long ctr;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	mutex_lock(&table_lock);
192*4882a593Smuzhiyun 	list_for_each_entry(tmp_dev, virtcrypto_devmgr_get_head(), list) {
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 		if ((node == dev_to_node(&tmp_dev->vdev->dev) ||
195*4882a593Smuzhiyun 		     dev_to_node(&tmp_dev->vdev->dev) < 0) &&
196*4882a593Smuzhiyun 		    virtcrypto_dev_started(tmp_dev) &&
197*4882a593Smuzhiyun 		    virtcrypto_algo_is_supported(tmp_dev, service, algo)) {
198*4882a593Smuzhiyun 			ctr = atomic_read(&tmp_dev->ref_count);
199*4882a593Smuzhiyun 			if (best > ctr) {
200*4882a593Smuzhiyun 				vcrypto_dev = tmp_dev;
201*4882a593Smuzhiyun 				best = ctr;
202*4882a593Smuzhiyun 			}
203*4882a593Smuzhiyun 		}
204*4882a593Smuzhiyun 	}
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	if (!vcrypto_dev) {
207*4882a593Smuzhiyun 		pr_info("virtio_crypto: Could not find a device on node %d\n",
208*4882a593Smuzhiyun 				node);
209*4882a593Smuzhiyun 		/* Get any started device */
210*4882a593Smuzhiyun 		list_for_each_entry(tmp_dev,
211*4882a593Smuzhiyun 				virtcrypto_devmgr_get_head(), list) {
212*4882a593Smuzhiyun 			if (virtcrypto_dev_started(tmp_dev) &&
213*4882a593Smuzhiyun 			    virtcrypto_algo_is_supported(tmp_dev,
214*4882a593Smuzhiyun 			    service, algo)) {
215*4882a593Smuzhiyun 				vcrypto_dev = tmp_dev;
216*4882a593Smuzhiyun 				break;
217*4882a593Smuzhiyun 			}
218*4882a593Smuzhiyun 		}
219*4882a593Smuzhiyun 	}
220*4882a593Smuzhiyun 	mutex_unlock(&table_lock);
221*4882a593Smuzhiyun 	if (!vcrypto_dev)
222*4882a593Smuzhiyun 		return NULL;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	virtcrypto_dev_get(vcrypto_dev);
225*4882a593Smuzhiyun 	return vcrypto_dev;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun /*
229*4882a593Smuzhiyun  * virtcrypto_dev_start() - Start virtio crypto device
230*4882a593Smuzhiyun  * @vcrypto:    Pointer to virtio crypto device.
231*4882a593Smuzhiyun  *
232*4882a593Smuzhiyun  * Function notifies all the registered services that the virtio crypto device
233*4882a593Smuzhiyun  * is ready to be used.
234*4882a593Smuzhiyun  * To be used by virtio crypto device specific drivers.
235*4882a593Smuzhiyun  *
236*4882a593Smuzhiyun  * Return: 0 on success, EFAULT when fail to register algorithms
237*4882a593Smuzhiyun  */
virtcrypto_dev_start(struct virtio_crypto * vcrypto)238*4882a593Smuzhiyun int virtcrypto_dev_start(struct virtio_crypto *vcrypto)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	if (virtio_crypto_algs_register(vcrypto)) {
241*4882a593Smuzhiyun 		pr_err("virtio_crypto: Failed to register crypto algs\n");
242*4882a593Smuzhiyun 		return -EFAULT;
243*4882a593Smuzhiyun 	}
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	return 0;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun /*
249*4882a593Smuzhiyun  * virtcrypto_dev_stop() - Stop virtio crypto device
250*4882a593Smuzhiyun  * @vcrypto:    Pointer to virtio crypto device.
251*4882a593Smuzhiyun  *
252*4882a593Smuzhiyun  * Function notifies all the registered services that the virtio crypto device
253*4882a593Smuzhiyun  * is ready to be used.
254*4882a593Smuzhiyun  * To be used by virtio crypto device specific drivers.
255*4882a593Smuzhiyun  *
256*4882a593Smuzhiyun  * Return: void
257*4882a593Smuzhiyun  */
virtcrypto_dev_stop(struct virtio_crypto * vcrypto)258*4882a593Smuzhiyun void virtcrypto_dev_stop(struct virtio_crypto *vcrypto)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun 	virtio_crypto_algs_unregister(vcrypto);
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun /*
264*4882a593Smuzhiyun  * vcrypto_algo_is_supported()
265*4882a593Smuzhiyun  * @vcrypto: Pointer to virtio crypto device.
266*4882a593Smuzhiyun  * @service: The bit number for service validate.
267*4882a593Smuzhiyun  *	      See VIRTIO_CRYPTO_SERVICE_*
268*4882a593Smuzhiyun  * @algo : The bit number for the algorithm to validate.
269*4882a593Smuzhiyun  *
270*4882a593Smuzhiyun  *
271*4882a593Smuzhiyun  * Validate if the virtio crypto device supports a service and
272*4882a593Smuzhiyun  * algo.
273*4882a593Smuzhiyun  *
274*4882a593Smuzhiyun  * Return true if device supports a service and algo.
275*4882a593Smuzhiyun  */
276*4882a593Smuzhiyun 
virtcrypto_algo_is_supported(struct virtio_crypto * vcrypto,uint32_t service,uint32_t algo)277*4882a593Smuzhiyun bool virtcrypto_algo_is_supported(struct virtio_crypto *vcrypto,
278*4882a593Smuzhiyun 				  uint32_t service,
279*4882a593Smuzhiyun 				  uint32_t algo)
280*4882a593Smuzhiyun {
281*4882a593Smuzhiyun 	uint32_t service_mask = 1u << service;
282*4882a593Smuzhiyun 	uint32_t algo_mask = 0;
283*4882a593Smuzhiyun 	bool low = true;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	if (algo > 31) {
286*4882a593Smuzhiyun 		algo -= 32;
287*4882a593Smuzhiyun 		low = false;
288*4882a593Smuzhiyun 	}
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	if (!(vcrypto->crypto_services & service_mask))
291*4882a593Smuzhiyun 		return false;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	switch (service) {
294*4882a593Smuzhiyun 	case VIRTIO_CRYPTO_SERVICE_CIPHER:
295*4882a593Smuzhiyun 		if (low)
296*4882a593Smuzhiyun 			algo_mask = vcrypto->cipher_algo_l;
297*4882a593Smuzhiyun 		else
298*4882a593Smuzhiyun 			algo_mask = vcrypto->cipher_algo_h;
299*4882a593Smuzhiyun 		break;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	case VIRTIO_CRYPTO_SERVICE_HASH:
302*4882a593Smuzhiyun 		algo_mask = vcrypto->hash_algo;
303*4882a593Smuzhiyun 		break;
304*4882a593Smuzhiyun 
305*4882a593Smuzhiyun 	case VIRTIO_CRYPTO_SERVICE_MAC:
306*4882a593Smuzhiyun 		if (low)
307*4882a593Smuzhiyun 			algo_mask = vcrypto->mac_algo_l;
308*4882a593Smuzhiyun 		else
309*4882a593Smuzhiyun 			algo_mask = vcrypto->mac_algo_h;
310*4882a593Smuzhiyun 		break;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	case VIRTIO_CRYPTO_SERVICE_AEAD:
313*4882a593Smuzhiyun 		algo_mask = vcrypto->aead_algo;
314*4882a593Smuzhiyun 		break;
315*4882a593Smuzhiyun 	}
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	if (!(algo_mask & (1u << algo)))
318*4882a593Smuzhiyun 		return false;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	return true;
321*4882a593Smuzhiyun }
322