xref: /linux/drivers/crypto/virtio/virtio_crypto_core.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2dbaf0624SGonglei  /* Driver for Virtio crypto device.
3dbaf0624SGonglei   *
4dbaf0624SGonglei   * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD.
5dbaf0624SGonglei   */
6dbaf0624SGonglei 
7dbaf0624SGonglei #include <linux/err.h>
8dbaf0624SGonglei #include <linux/module.h>
9dbaf0624SGonglei #include <linux/virtio_config.h>
10dbaf0624SGonglei #include <linux/cpu.h>
11dbaf0624SGonglei 
12dbaf0624SGonglei #include <uapi/linux/virtio_crypto.h>
13dbaf0624SGonglei #include "virtio_crypto_common.h"
14dbaf0624SGonglei 
15dbaf0624SGonglei 
16d79b5d0bSGonglei \(Arei\) void
virtcrypto_clear_request(struct virtio_crypto_request * vc_req)17dbaf0624SGonglei virtcrypto_clear_request(struct virtio_crypto_request *vc_req)
18dbaf0624SGonglei {
19dbaf0624SGonglei 	if (vc_req) {
20453431a5SWaiman Long 		kfree_sensitive(vc_req->req_data);
21dbaf0624SGonglei 		kfree(vc_req->sgs);
22dbaf0624SGonglei 	}
23dbaf0624SGonglei }
24dbaf0624SGonglei 
virtio_crypto_ctrlq_callback(struct virtio_crypto_ctrl_request * vc_ctrl_req)25977231e8Szhenwei pi static void virtio_crypto_ctrlq_callback(struct virtio_crypto_ctrl_request *vc_ctrl_req)
26977231e8Szhenwei pi {
27977231e8Szhenwei pi 	complete(&vc_ctrl_req->compl);
28977231e8Szhenwei pi }
29977231e8Szhenwei pi 
virtcrypto_ctrlq_callback(struct virtqueue * vq)30977231e8Szhenwei pi static void virtcrypto_ctrlq_callback(struct virtqueue *vq)
31977231e8Szhenwei pi {
32977231e8Szhenwei pi 	struct virtio_crypto *vcrypto = vq->vdev->priv;
33977231e8Szhenwei pi 	struct virtio_crypto_ctrl_request *vc_ctrl_req;
34977231e8Szhenwei pi 	unsigned long flags;
35977231e8Szhenwei pi 	unsigned int len;
36977231e8Szhenwei pi 
37977231e8Szhenwei pi 	spin_lock_irqsave(&vcrypto->ctrl_lock, flags);
38977231e8Szhenwei pi 	do {
39977231e8Szhenwei pi 		virtqueue_disable_cb(vq);
40977231e8Szhenwei pi 		while ((vc_ctrl_req = virtqueue_get_buf(vq, &len)) != NULL) {
41977231e8Szhenwei pi 			spin_unlock_irqrestore(&vcrypto->ctrl_lock, flags);
42977231e8Szhenwei pi 			virtio_crypto_ctrlq_callback(vc_ctrl_req);
43977231e8Szhenwei pi 			spin_lock_irqsave(&vcrypto->ctrl_lock, flags);
44977231e8Szhenwei pi 		}
45977231e8Szhenwei pi 	} while (!virtqueue_enable_cb(vq));
46977231e8Szhenwei pi 	spin_unlock_irqrestore(&vcrypto->ctrl_lock, flags);
47977231e8Szhenwei pi }
48977231e8Szhenwei pi 
virtio_crypto_ctrl_vq_request(struct virtio_crypto * vcrypto,struct scatterlist * sgs[],unsigned int out_sgs,unsigned int in_sgs,struct virtio_crypto_ctrl_request * vc_ctrl_req)49977231e8Szhenwei pi int virtio_crypto_ctrl_vq_request(struct virtio_crypto *vcrypto, struct scatterlist *sgs[],
50977231e8Szhenwei pi 		unsigned int out_sgs, unsigned int in_sgs,
51977231e8Szhenwei pi 		struct virtio_crypto_ctrl_request *vc_ctrl_req)
52977231e8Szhenwei pi {
53977231e8Szhenwei pi 	int err;
54977231e8Szhenwei pi 	unsigned long flags;
55977231e8Szhenwei pi 
56977231e8Szhenwei pi 	init_completion(&vc_ctrl_req->compl);
57977231e8Szhenwei pi 
58977231e8Szhenwei pi 	spin_lock_irqsave(&vcrypto->ctrl_lock, flags);
59977231e8Szhenwei pi 	err = virtqueue_add_sgs(vcrypto->ctrl_vq, sgs, out_sgs, in_sgs, vc_ctrl_req, GFP_ATOMIC);
60977231e8Szhenwei pi 	if (err < 0) {
61977231e8Szhenwei pi 		spin_unlock_irqrestore(&vcrypto->ctrl_lock, flags);
62977231e8Szhenwei pi 		return err;
63977231e8Szhenwei pi 	}
64977231e8Szhenwei pi 
65977231e8Szhenwei pi 	virtqueue_kick(vcrypto->ctrl_vq);
66977231e8Szhenwei pi 	spin_unlock_irqrestore(&vcrypto->ctrl_lock, flags);
67977231e8Szhenwei pi 
68977231e8Szhenwei pi 	wait_for_completion(&vc_ctrl_req->compl);
69977231e8Szhenwei pi 
70977231e8Szhenwei pi 	return 0;
71977231e8Szhenwei pi }
72977231e8Szhenwei pi 
virtcrypto_done_task(unsigned long data)73fed93fb6SGonglei (Arei) static void virtcrypto_done_task(unsigned long data)
74dbaf0624SGonglei {
75fed93fb6SGonglei (Arei) 	struct data_queue *data_vq = (struct data_queue *)data;
76fed93fb6SGonglei (Arei) 	struct virtqueue *vq = data_vq->vq;
77dbaf0624SGonglei 	struct virtio_crypto_request *vc_req;
78dbaf0624SGonglei 	unsigned int len;
79dbaf0624SGonglei 
80dbaf0624SGonglei 	do {
81dbaf0624SGonglei 		virtqueue_disable_cb(vq);
82dbaf0624SGonglei 		while ((vc_req = virtqueue_get_buf(vq, &len)) != NULL) {
83d31e7123SZeng, Xin 			if (vc_req->alg_cb)
84d31e7123SZeng, Xin 				vc_req->alg_cb(vc_req, len);
85dbaf0624SGonglei 		}
86dbaf0624SGonglei 	} while (!virtqueue_enable_cb(vq));
87fed93fb6SGonglei (Arei) }
88fed93fb6SGonglei (Arei) 
virtcrypto_dataq_callback(struct virtqueue * vq)89fed93fb6SGonglei (Arei) static void virtcrypto_dataq_callback(struct virtqueue *vq)
90fed93fb6SGonglei (Arei) {
91fed93fb6SGonglei (Arei) 	struct virtio_crypto *vcrypto = vq->vdev->priv;
92fed93fb6SGonglei (Arei) 	struct data_queue *dq = &vcrypto->data_vq[vq->index];
93fed93fb6SGonglei (Arei) 
94fed93fb6SGonglei (Arei) 	tasklet_schedule(&dq->done_task);
95dbaf0624SGonglei }
96dbaf0624SGonglei 
virtcrypto_find_vqs(struct virtio_crypto * vi)97dbaf0624SGonglei static int virtcrypto_find_vqs(struct virtio_crypto *vi)
98dbaf0624SGonglei {
99210a70f2SJiri Pirko 	struct virtqueue_info *vqs_info;
100dbaf0624SGonglei 	struct virtqueue **vqs;
101dbaf0624SGonglei 	int ret = -ENOMEM;
102dbaf0624SGonglei 	int i, total_vqs;
103d79b5d0bSGonglei \(Arei\) 	struct device *dev = &vi->vdev->dev;
104dbaf0624SGonglei 
105dbaf0624SGonglei 	/*
106dbaf0624SGonglei 	 * We expect 1 data virtqueue, followed by
107dbaf0624SGonglei 	 * possible N-1 data queues used in multiqueue mode,
108dbaf0624SGonglei 	 * followed by control vq.
109dbaf0624SGonglei 	 */
110dbaf0624SGonglei 	total_vqs = vi->max_data_queues + 1;
111dbaf0624SGonglei 
112dbaf0624SGonglei 	/* Allocate space for find_vqs parameters */
113dbaf0624SGonglei 	vqs = kcalloc(total_vqs, sizeof(*vqs), GFP_KERNEL);
114dbaf0624SGonglei 	if (!vqs)
115dbaf0624SGonglei 		goto err_vq;
116210a70f2SJiri Pirko 	vqs_info = kcalloc(total_vqs, sizeof(*vqs_info), GFP_KERNEL);
117210a70f2SJiri Pirko 	if (!vqs_info)
118210a70f2SJiri Pirko 		goto err_vqs_info;
119dbaf0624SGonglei 
120dbaf0624SGonglei 	/* Parameters for control virtqueue */
121210a70f2SJiri Pirko 	vqs_info[total_vqs - 1].callback = virtcrypto_ctrlq_callback;
122210a70f2SJiri Pirko 	vqs_info[total_vqs - 1].name = "controlq";
123dbaf0624SGonglei 
124dbaf0624SGonglei 	/* Allocate/initialize parameters for data virtqueues */
125dbaf0624SGonglei 	for (i = 0; i < vi->max_data_queues; i++) {
126210a70f2SJiri Pirko 		vqs_info[i].callback = virtcrypto_dataq_callback;
127dbaf0624SGonglei 		snprintf(vi->data_vq[i].name, sizeof(vi->data_vq[i].name),
128dbaf0624SGonglei 				"dataq.%d", i);
129210a70f2SJiri Pirko 		vqs_info[i].name = vi->data_vq[i].name;
130dbaf0624SGonglei 	}
131dbaf0624SGonglei 
132*6c85d6b6SJiri Pirko 	ret = virtio_find_vqs(vi->vdev, total_vqs, vqs, vqs_info, NULL);
133dbaf0624SGonglei 	if (ret)
134dbaf0624SGonglei 		goto err_find;
135dbaf0624SGonglei 
136dbaf0624SGonglei 	vi->ctrl_vq = vqs[total_vqs - 1];
137dbaf0624SGonglei 
138dbaf0624SGonglei 	for (i = 0; i < vi->max_data_queues; i++) {
139dbaf0624SGonglei 		spin_lock_init(&vi->data_vq[i].lock);
140dbaf0624SGonglei 		vi->data_vq[i].vq = vqs[i];
141d79b5d0bSGonglei \(Arei\) 		/* Initialize crypto engine */
1424e0d352aSlei he 		vi->data_vq[i].engine = crypto_engine_alloc_init_and_set(dev, true, NULL, true,
1434e0d352aSlei he 						virtqueue_get_vring_size(vqs[i]));
144d79b5d0bSGonglei \(Arei\) 		if (!vi->data_vq[i].engine) {
145d79b5d0bSGonglei \(Arei\) 			ret = -ENOMEM;
146d79b5d0bSGonglei \(Arei\) 			goto err_engine;
147d79b5d0bSGonglei \(Arei\) 		}
148fed93fb6SGonglei (Arei) 		tasklet_init(&vi->data_vq[i].done_task, virtcrypto_done_task,
149fed93fb6SGonglei (Arei) 				(unsigned long)&vi->data_vq[i]);
150dbaf0624SGonglei 	}
151dbaf0624SGonglei 
152210a70f2SJiri Pirko 	kfree(vqs_info);
153dbaf0624SGonglei 	kfree(vqs);
154dbaf0624SGonglei 
155dbaf0624SGonglei 	return 0;
156dbaf0624SGonglei 
157d79b5d0bSGonglei \(Arei\) err_engine:
158dbaf0624SGonglei err_find:
159210a70f2SJiri Pirko 	kfree(vqs_info);
160210a70f2SJiri Pirko err_vqs_info:
161dbaf0624SGonglei 	kfree(vqs);
162dbaf0624SGonglei err_vq:
163dbaf0624SGonglei 	return ret;
164dbaf0624SGonglei }
165dbaf0624SGonglei 
virtcrypto_alloc_queues(struct virtio_crypto * vi)166dbaf0624SGonglei static int virtcrypto_alloc_queues(struct virtio_crypto *vi)
167dbaf0624SGonglei {
168dbaf0624SGonglei 	vi->data_vq = kcalloc(vi->max_data_queues, sizeof(*vi->data_vq),
169dbaf0624SGonglei 				GFP_KERNEL);
170dbaf0624SGonglei 	if (!vi->data_vq)
171dbaf0624SGonglei 		return -ENOMEM;
172dbaf0624SGonglei 
173dbaf0624SGonglei 	return 0;
174dbaf0624SGonglei }
175dbaf0624SGonglei 
virtcrypto_clean_affinity(struct virtio_crypto * vi,long hcpu)176dbaf0624SGonglei static void virtcrypto_clean_affinity(struct virtio_crypto *vi, long hcpu)
177dbaf0624SGonglei {
178dbaf0624SGonglei 	int i;
179dbaf0624SGonglei 
180dbaf0624SGonglei 	if (vi->affinity_hint_set) {
181dbaf0624SGonglei 		for (i = 0; i < vi->max_data_queues; i++)
18219e226e8SCaleb Raitto 			virtqueue_set_affinity(vi->data_vq[i].vq, NULL);
183dbaf0624SGonglei 
184dbaf0624SGonglei 		vi->affinity_hint_set = false;
185dbaf0624SGonglei 	}
186dbaf0624SGonglei }
187dbaf0624SGonglei 
virtcrypto_set_affinity(struct virtio_crypto * vcrypto)188dbaf0624SGonglei static void virtcrypto_set_affinity(struct virtio_crypto *vcrypto)
189dbaf0624SGonglei {
190dbaf0624SGonglei 	int i = 0;
191dbaf0624SGonglei 	int cpu;
192dbaf0624SGonglei 
193dbaf0624SGonglei 	/*
194dbaf0624SGonglei 	 * In single queue mode, we don't set the cpu affinity.
195dbaf0624SGonglei 	 */
196dbaf0624SGonglei 	if (vcrypto->curr_queue == 1 || vcrypto->max_data_queues == 1) {
197dbaf0624SGonglei 		virtcrypto_clean_affinity(vcrypto, -1);
198dbaf0624SGonglei 		return;
199dbaf0624SGonglei 	}
200dbaf0624SGonglei 
201dbaf0624SGonglei 	/*
202dbaf0624SGonglei 	 * In multiqueue mode, we let the queue to be private to one cpu
203dbaf0624SGonglei 	 * by setting the affinity hint to eliminate the contention.
204dbaf0624SGonglei 	 *
205dbaf0624SGonglei 	 * TODO: adds cpu hotplug support by register cpu notifier.
206dbaf0624SGonglei 	 *
207dbaf0624SGonglei 	 */
208dbaf0624SGonglei 	for_each_online_cpu(cpu) {
20919e226e8SCaleb Raitto 		virtqueue_set_affinity(vcrypto->data_vq[i].vq, cpumask_of(cpu));
210dbaf0624SGonglei 		if (++i >= vcrypto->max_data_queues)
211dbaf0624SGonglei 			break;
212dbaf0624SGonglei 	}
213dbaf0624SGonglei 
214dbaf0624SGonglei 	vcrypto->affinity_hint_set = true;
215dbaf0624SGonglei }
216dbaf0624SGonglei 
virtcrypto_free_queues(struct virtio_crypto * vi)217dbaf0624SGonglei static void virtcrypto_free_queues(struct virtio_crypto *vi)
218dbaf0624SGonglei {
219dbaf0624SGonglei 	kfree(vi->data_vq);
220dbaf0624SGonglei }
221dbaf0624SGonglei 
virtcrypto_init_vqs(struct virtio_crypto * vi)222dbaf0624SGonglei static int virtcrypto_init_vqs(struct virtio_crypto *vi)
223dbaf0624SGonglei {
224dbaf0624SGonglei 	int ret;
225dbaf0624SGonglei 
226dbaf0624SGonglei 	/* Allocate send & receive queues */
227dbaf0624SGonglei 	ret = virtcrypto_alloc_queues(vi);
228dbaf0624SGonglei 	if (ret)
229dbaf0624SGonglei 		goto err;
230dbaf0624SGonglei 
231dbaf0624SGonglei 	ret = virtcrypto_find_vqs(vi);
232dbaf0624SGonglei 	if (ret)
233dbaf0624SGonglei 		goto err_free;
234dbaf0624SGonglei 
235d01a9f70SSebastian Andrzej Siewior 	cpus_read_lock();
236dbaf0624SGonglei 	virtcrypto_set_affinity(vi);
237d01a9f70SSebastian Andrzej Siewior 	cpus_read_unlock();
238dbaf0624SGonglei 
239dbaf0624SGonglei 	return 0;
240dbaf0624SGonglei 
241dbaf0624SGonglei err_free:
242dbaf0624SGonglei 	virtcrypto_free_queues(vi);
243dbaf0624SGonglei err:
244dbaf0624SGonglei 	return ret;
245dbaf0624SGonglei }
246dbaf0624SGonglei 
virtcrypto_update_status(struct virtio_crypto * vcrypto)247dbaf0624SGonglei static int virtcrypto_update_status(struct virtio_crypto *vcrypto)
248dbaf0624SGonglei {
249dbaf0624SGonglei 	u32 status;
250dbaf0624SGonglei 	int err;
251dbaf0624SGonglei 
252b13a5407SMichael S. Tsirkin 	virtio_cread_le(vcrypto->vdev,
253dbaf0624SGonglei 			struct virtio_crypto_config, status, &status);
254dbaf0624SGonglei 
255dbaf0624SGonglei 	/*
256dbaf0624SGonglei 	 * Unknown status bits would be a host error and the driver
257dbaf0624SGonglei 	 * should consider the device to be broken.
258dbaf0624SGonglei 	 */
259dbaf0624SGonglei 	if (status & (~VIRTIO_CRYPTO_S_HW_READY)) {
260dbaf0624SGonglei 		dev_warn(&vcrypto->vdev->dev,
261dbaf0624SGonglei 				"Unknown status bits: 0x%x\n", status);
262dbaf0624SGonglei 
263dbaf0624SGonglei 		virtio_break_device(vcrypto->vdev);
264dbaf0624SGonglei 		return -EPERM;
265dbaf0624SGonglei 	}
266dbaf0624SGonglei 
267dbaf0624SGonglei 	if (vcrypto->status == status)
268dbaf0624SGonglei 		return 0;
269dbaf0624SGonglei 
270dbaf0624SGonglei 	vcrypto->status = status;
271dbaf0624SGonglei 
272dbaf0624SGonglei 	if (vcrypto->status & VIRTIO_CRYPTO_S_HW_READY) {
273dbaf0624SGonglei 		err = virtcrypto_dev_start(vcrypto);
274dbaf0624SGonglei 		if (err) {
275dbaf0624SGonglei 			dev_err(&vcrypto->vdev->dev,
276dbaf0624SGonglei 				"Failed to start virtio crypto device.\n");
277dbaf0624SGonglei 
278dbaf0624SGonglei 			return -EPERM;
279dbaf0624SGonglei 		}
280d31e7123SZeng, Xin 		dev_info(&vcrypto->vdev->dev, "Accelerator device is ready\n");
281dbaf0624SGonglei 	} else {
282dbaf0624SGonglei 		virtcrypto_dev_stop(vcrypto);
283dbaf0624SGonglei 		dev_info(&vcrypto->vdev->dev, "Accelerator is not ready\n");
284dbaf0624SGonglei 	}
285dbaf0624SGonglei 
286dbaf0624SGonglei 	return 0;
287dbaf0624SGonglei }
288dbaf0624SGonglei 
virtcrypto_start_crypto_engines(struct virtio_crypto * vcrypto)289d79b5d0bSGonglei \(Arei\) static int virtcrypto_start_crypto_engines(struct virtio_crypto *vcrypto)
290d79b5d0bSGonglei \(Arei\) {
291d79b5d0bSGonglei \(Arei\) 	int32_t i;
292d79b5d0bSGonglei \(Arei\) 	int ret;
293d79b5d0bSGonglei \(Arei\) 
294d79b5d0bSGonglei \(Arei\) 	for (i = 0; i < vcrypto->max_data_queues; i++) {
295d79b5d0bSGonglei \(Arei\) 		if (vcrypto->data_vq[i].engine) {
296d79b5d0bSGonglei \(Arei\) 			ret = crypto_engine_start(vcrypto->data_vq[i].engine);
297d79b5d0bSGonglei \(Arei\) 			if (ret)
298d79b5d0bSGonglei \(Arei\) 				goto err;
299d79b5d0bSGonglei \(Arei\) 		}
300d79b5d0bSGonglei \(Arei\) 	}
301d79b5d0bSGonglei \(Arei\) 
302d79b5d0bSGonglei \(Arei\) 	return 0;
303d79b5d0bSGonglei \(Arei\) 
304d79b5d0bSGonglei \(Arei\) err:
305d79b5d0bSGonglei \(Arei\) 	while (--i >= 0)
306d79b5d0bSGonglei \(Arei\) 		if (vcrypto->data_vq[i].engine)
307d79b5d0bSGonglei \(Arei\) 			crypto_engine_exit(vcrypto->data_vq[i].engine);
308d79b5d0bSGonglei \(Arei\) 
309d79b5d0bSGonglei \(Arei\) 	return ret;
310d79b5d0bSGonglei \(Arei\) }
311d79b5d0bSGonglei \(Arei\) 
virtcrypto_clear_crypto_engines(struct virtio_crypto * vcrypto)312d79b5d0bSGonglei \(Arei\) static void virtcrypto_clear_crypto_engines(struct virtio_crypto *vcrypto)
313d79b5d0bSGonglei \(Arei\) {
314d79b5d0bSGonglei \(Arei\) 	u32 i;
315d79b5d0bSGonglei \(Arei\) 
316d79b5d0bSGonglei \(Arei\) 	for (i = 0; i < vcrypto->max_data_queues; i++)
317d79b5d0bSGonglei \(Arei\) 		if (vcrypto->data_vq[i].engine)
318d79b5d0bSGonglei \(Arei\) 			crypto_engine_exit(vcrypto->data_vq[i].engine);
319d79b5d0bSGonglei \(Arei\) }
320d79b5d0bSGonglei \(Arei\) 
virtcrypto_del_vqs(struct virtio_crypto * vcrypto)321dbaf0624SGonglei static void virtcrypto_del_vqs(struct virtio_crypto *vcrypto)
322dbaf0624SGonglei {
323dbaf0624SGonglei 	struct virtio_device *vdev = vcrypto->vdev;
324dbaf0624SGonglei 
325dbaf0624SGonglei 	virtcrypto_clean_affinity(vcrypto, -1);
326dbaf0624SGonglei 
327dbaf0624SGonglei 	vdev->config->del_vqs(vdev);
328dbaf0624SGonglei 
329dbaf0624SGonglei 	virtcrypto_free_queues(vcrypto);
330dbaf0624SGonglei }
331dbaf0624SGonglei 
vcrypto_config_changed_work(struct work_struct * work)332fa2e6947Szhenwei pi static void vcrypto_config_changed_work(struct work_struct *work)
333fa2e6947Szhenwei pi {
334fa2e6947Szhenwei pi 	struct virtio_crypto *vcrypto =
335fa2e6947Szhenwei pi 		container_of(work, struct virtio_crypto, config_work);
336fa2e6947Szhenwei pi 
337fa2e6947Szhenwei pi 	virtcrypto_update_status(vcrypto);
338fa2e6947Szhenwei pi }
339fa2e6947Szhenwei pi 
virtcrypto_probe(struct virtio_device * vdev)340dbaf0624SGonglei static int virtcrypto_probe(struct virtio_device *vdev)
341dbaf0624SGonglei {
342dbaf0624SGonglei 	int err = -EFAULT;
343dbaf0624SGonglei 	struct virtio_crypto *vcrypto;
344dbaf0624SGonglei 	u32 max_data_queues = 0, max_cipher_key_len = 0;
345dbaf0624SGonglei 	u32 max_auth_key_len = 0;
346dbaf0624SGonglei 	u64 max_size = 0;
347b551bac1SFarhan Ali 	u32 cipher_algo_l = 0;
348b551bac1SFarhan Ali 	u32 cipher_algo_h = 0;
349b551bac1SFarhan Ali 	u32 hash_algo = 0;
350b551bac1SFarhan Ali 	u32 mac_algo_l = 0;
351b551bac1SFarhan Ali 	u32 mac_algo_h = 0;
352b551bac1SFarhan Ali 	u32 aead_algo = 0;
35359ca6c93Szhenwei pi 	u32 akcipher_algo = 0;
354b551bac1SFarhan Ali 	u32 crypto_services = 0;
355dbaf0624SGonglei 
356dbaf0624SGonglei 	if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
357dbaf0624SGonglei 		return -ENODEV;
358dbaf0624SGonglei 
359dbaf0624SGonglei 	if (!vdev->config->get) {
360dbaf0624SGonglei 		dev_err(&vdev->dev, "%s failure: config access disabled\n",
361dbaf0624SGonglei 			__func__);
362dbaf0624SGonglei 		return -EINVAL;
363dbaf0624SGonglei 	}
364dbaf0624SGonglei 
365dbaf0624SGonglei 	if (num_possible_nodes() > 1 && dev_to_node(&vdev->dev) < 0) {
366dbaf0624SGonglei 		/*
367dbaf0624SGonglei 		 * If the accelerator is connected to a node with no memory
368dbaf0624SGonglei 		 * there is no point in using the accelerator since the remote
369dbaf0624SGonglei 		 * memory transaction will be very slow.
370dbaf0624SGonglei 		 */
371dbaf0624SGonglei 		dev_err(&vdev->dev, "Invalid NUMA configuration.\n");
372dbaf0624SGonglei 		return -EINVAL;
373dbaf0624SGonglei 	}
374dbaf0624SGonglei 
375dbaf0624SGonglei 	vcrypto = kzalloc_node(sizeof(*vcrypto), GFP_KERNEL,
376dbaf0624SGonglei 					dev_to_node(&vdev->dev));
377dbaf0624SGonglei 	if (!vcrypto)
378dbaf0624SGonglei 		return -ENOMEM;
379dbaf0624SGonglei 
380b13a5407SMichael S. Tsirkin 	virtio_cread_le(vdev, struct virtio_crypto_config,
381dbaf0624SGonglei 			max_dataqueues, &max_data_queues);
382dbaf0624SGonglei 	if (max_data_queues < 1)
383dbaf0624SGonglei 		max_data_queues = 1;
384dbaf0624SGonglei 
385b13a5407SMichael S. Tsirkin 	virtio_cread_le(vdev, struct virtio_crypto_config,
386dbaf0624SGonglei 			max_cipher_key_len, &max_cipher_key_len);
387b13a5407SMichael S. Tsirkin 	virtio_cread_le(vdev, struct virtio_crypto_config,
388dbaf0624SGonglei 			max_auth_key_len, &max_auth_key_len);
389b13a5407SMichael S. Tsirkin 	virtio_cread_le(vdev, struct virtio_crypto_config,
390dbaf0624SGonglei 			max_size, &max_size);
391b13a5407SMichael S. Tsirkin 	virtio_cread_le(vdev, struct virtio_crypto_config,
392b551bac1SFarhan Ali 			crypto_services, &crypto_services);
393b13a5407SMichael S. Tsirkin 	virtio_cread_le(vdev, struct virtio_crypto_config,
394b551bac1SFarhan Ali 			cipher_algo_l, &cipher_algo_l);
395b13a5407SMichael S. Tsirkin 	virtio_cread_le(vdev, struct virtio_crypto_config,
396b551bac1SFarhan Ali 			cipher_algo_h, &cipher_algo_h);
397b13a5407SMichael S. Tsirkin 	virtio_cread_le(vdev, struct virtio_crypto_config,
398b551bac1SFarhan Ali 			hash_algo, &hash_algo);
399b13a5407SMichael S. Tsirkin 	virtio_cread_le(vdev, struct virtio_crypto_config,
400b551bac1SFarhan Ali 			mac_algo_l, &mac_algo_l);
401b13a5407SMichael S. Tsirkin 	virtio_cread_le(vdev, struct virtio_crypto_config,
402b551bac1SFarhan Ali 			mac_algo_h, &mac_algo_h);
403b13a5407SMichael S. Tsirkin 	virtio_cread_le(vdev, struct virtio_crypto_config,
404b551bac1SFarhan Ali 			aead_algo, &aead_algo);
40559ca6c93Szhenwei pi 	if (crypto_services & (1 << VIRTIO_CRYPTO_SERVICE_AKCIPHER))
40659ca6c93Szhenwei pi 		virtio_cread_le(vdev, struct virtio_crypto_config,
40759ca6c93Szhenwei pi 				akcipher_algo, &akcipher_algo);
408dbaf0624SGonglei 
409dbaf0624SGonglei 	/* Add virtio crypto device to global table */
410dbaf0624SGonglei 	err = virtcrypto_devmgr_add_dev(vcrypto);
411dbaf0624SGonglei 	if (err) {
412dbaf0624SGonglei 		dev_err(&vdev->dev, "Failed to add new virtio crypto device.\n");
413dbaf0624SGonglei 		goto free;
414dbaf0624SGonglei 	}
415dbaf0624SGonglei 	vcrypto->owner = THIS_MODULE;
416dbaf0624SGonglei 	vcrypto = vdev->priv = vcrypto;
417dbaf0624SGonglei 	vcrypto->vdev = vdev;
418dbaf0624SGonglei 
419dbaf0624SGonglei 	spin_lock_init(&vcrypto->ctrl_lock);
420dbaf0624SGonglei 
421dbaf0624SGonglei 	/* Use single data queue as default */
422dbaf0624SGonglei 	vcrypto->curr_queue = 1;
423dbaf0624SGonglei 	vcrypto->max_data_queues = max_data_queues;
424dbaf0624SGonglei 	vcrypto->max_cipher_key_len = max_cipher_key_len;
425dbaf0624SGonglei 	vcrypto->max_auth_key_len = max_auth_key_len;
426dbaf0624SGonglei 	vcrypto->max_size = max_size;
427b551bac1SFarhan Ali 	vcrypto->crypto_services = crypto_services;
428b551bac1SFarhan Ali 	vcrypto->cipher_algo_l = cipher_algo_l;
429b551bac1SFarhan Ali 	vcrypto->cipher_algo_h = cipher_algo_h;
430b551bac1SFarhan Ali 	vcrypto->mac_algo_l = mac_algo_l;
431b551bac1SFarhan Ali 	vcrypto->mac_algo_h = mac_algo_h;
432b551bac1SFarhan Ali 	vcrypto->hash_algo = hash_algo;
433b551bac1SFarhan Ali 	vcrypto->aead_algo = aead_algo;
43459ca6c93Szhenwei pi 	vcrypto->akcipher_algo = akcipher_algo;
435dbaf0624SGonglei 
436dbaf0624SGonglei 	dev_info(&vdev->dev,
437dbaf0624SGonglei 		"max_queues: %u, max_cipher_key_len: %u, max_auth_key_len: %u, max_size 0x%llx\n",
438dbaf0624SGonglei 		vcrypto->max_data_queues,
439dbaf0624SGonglei 		vcrypto->max_cipher_key_len,
440dbaf0624SGonglei 		vcrypto->max_auth_key_len,
441dbaf0624SGonglei 		vcrypto->max_size);
442dbaf0624SGonglei 
443dbaf0624SGonglei 	err = virtcrypto_init_vqs(vcrypto);
444dbaf0624SGonglei 	if (err) {
445dbaf0624SGonglei 		dev_err(&vdev->dev, "Failed to initialize vqs.\n");
446dbaf0624SGonglei 		goto free_dev;
447dbaf0624SGonglei 	}
448d79b5d0bSGonglei \(Arei\) 
449d79b5d0bSGonglei \(Arei\) 	err = virtcrypto_start_crypto_engines(vcrypto);
450d79b5d0bSGonglei \(Arei\) 	if (err)
451d79b5d0bSGonglei \(Arei\) 		goto free_vqs;
452d79b5d0bSGonglei \(Arei\) 
453dbaf0624SGonglei 	virtio_device_ready(vdev);
454dbaf0624SGonglei 
455dbaf0624SGonglei 	err = virtcrypto_update_status(vcrypto);
456dbaf0624SGonglei 	if (err)
457d79b5d0bSGonglei \(Arei\) 		goto free_engines;
458dbaf0624SGonglei 
459fa2e6947Szhenwei pi 	INIT_WORK(&vcrypto->config_work, vcrypto_config_changed_work);
460fa2e6947Szhenwei pi 
461dbaf0624SGonglei 	return 0;
462dbaf0624SGonglei 
463d79b5d0bSGonglei \(Arei\) free_engines:
464d79b5d0bSGonglei \(Arei\) 	virtcrypto_clear_crypto_engines(vcrypto);
465dbaf0624SGonglei free_vqs:
466d9679d00SMichael S. Tsirkin 	virtio_reset_device(vdev);
467dbaf0624SGonglei 	virtcrypto_del_vqs(vcrypto);
468dbaf0624SGonglei free_dev:
469dbaf0624SGonglei 	virtcrypto_devmgr_rm_dev(vcrypto);
470dbaf0624SGonglei free:
471dbaf0624SGonglei 	kfree(vcrypto);
472dbaf0624SGonglei 	return err;
473dbaf0624SGonglei }
474dbaf0624SGonglei 
virtcrypto_free_unused_reqs(struct virtio_crypto * vcrypto)475dbaf0624SGonglei static void virtcrypto_free_unused_reqs(struct virtio_crypto *vcrypto)
476dbaf0624SGonglei {
477dbaf0624SGonglei 	struct virtio_crypto_request *vc_req;
478dbaf0624SGonglei 	int i;
479dbaf0624SGonglei 	struct virtqueue *vq;
480dbaf0624SGonglei 
481dbaf0624SGonglei 	for (i = 0; i < vcrypto->max_data_queues; i++) {
482dbaf0624SGonglei 		vq = vcrypto->data_vq[i].vq;
483dbaf0624SGonglei 		while ((vc_req = virtqueue_detach_unused_buf(vq)) != NULL) {
484dbaf0624SGonglei 			kfree(vc_req->req_data);
485dbaf0624SGonglei 			kfree(vc_req->sgs);
486dbaf0624SGonglei 		}
4877a5103b8SXianting Tian 		cond_resched();
488dbaf0624SGonglei 	}
489dbaf0624SGonglei }
490dbaf0624SGonglei 
virtcrypto_remove(struct virtio_device * vdev)491dbaf0624SGonglei static void virtcrypto_remove(struct virtio_device *vdev)
492dbaf0624SGonglei {
493dbaf0624SGonglei 	struct virtio_crypto *vcrypto = vdev->priv;
49467cc511eSwangyangxin 	int i;
495dbaf0624SGonglei 
496dbaf0624SGonglei 	dev_info(&vdev->dev, "Start virtcrypto_remove.\n");
497dbaf0624SGonglei 
498fa2e6947Szhenwei pi 	flush_work(&vcrypto->config_work);
499dbaf0624SGonglei 	if (virtcrypto_dev_started(vcrypto))
500dbaf0624SGonglei 		virtcrypto_dev_stop(vcrypto);
50167cc511eSwangyangxin 	for (i = 0; i < vcrypto->max_data_queues; i++)
50267cc511eSwangyangxin 		tasklet_kill(&vcrypto->data_vq[i].done_task);
503d9679d00SMichael S. Tsirkin 	virtio_reset_device(vdev);
504dbaf0624SGonglei 	virtcrypto_free_unused_reqs(vcrypto);
505d79b5d0bSGonglei \(Arei\) 	virtcrypto_clear_crypto_engines(vcrypto);
506dbaf0624SGonglei 	virtcrypto_del_vqs(vcrypto);
507dbaf0624SGonglei 	virtcrypto_devmgr_rm_dev(vcrypto);
508dbaf0624SGonglei 	kfree(vcrypto);
509dbaf0624SGonglei }
510dbaf0624SGonglei 
virtcrypto_config_changed(struct virtio_device * vdev)511dbaf0624SGonglei static void virtcrypto_config_changed(struct virtio_device *vdev)
512dbaf0624SGonglei {
513dbaf0624SGonglei 	struct virtio_crypto *vcrypto = vdev->priv;
514dbaf0624SGonglei 
515fa2e6947Szhenwei pi 	schedule_work(&vcrypto->config_work);
516dbaf0624SGonglei }
517dbaf0624SGonglei 
518dbaf0624SGonglei #ifdef CONFIG_PM_SLEEP
virtcrypto_freeze(struct virtio_device * vdev)519dbaf0624SGonglei static int virtcrypto_freeze(struct virtio_device *vdev)
520dbaf0624SGonglei {
521dbaf0624SGonglei 	struct virtio_crypto *vcrypto = vdev->priv;
522dbaf0624SGonglei 
523fa2e6947Szhenwei pi 	flush_work(&vcrypto->config_work);
524d9679d00SMichael S. Tsirkin 	virtio_reset_device(vdev);
525dbaf0624SGonglei 	virtcrypto_free_unused_reqs(vcrypto);
526dbaf0624SGonglei 	if (virtcrypto_dev_started(vcrypto))
527dbaf0624SGonglei 		virtcrypto_dev_stop(vcrypto);
528dbaf0624SGonglei 
529d79b5d0bSGonglei \(Arei\) 	virtcrypto_clear_crypto_engines(vcrypto);
530dbaf0624SGonglei 	virtcrypto_del_vqs(vcrypto);
531dbaf0624SGonglei 	return 0;
532dbaf0624SGonglei }
533dbaf0624SGonglei 
virtcrypto_restore(struct virtio_device * vdev)534dbaf0624SGonglei static int virtcrypto_restore(struct virtio_device *vdev)
535dbaf0624SGonglei {
536dbaf0624SGonglei 	struct virtio_crypto *vcrypto = vdev->priv;
537dbaf0624SGonglei 	int err;
538dbaf0624SGonglei 
539dbaf0624SGonglei 	err = virtcrypto_init_vqs(vcrypto);
540dbaf0624SGonglei 	if (err)
541dbaf0624SGonglei 		return err;
542dbaf0624SGonglei 
543d79b5d0bSGonglei \(Arei\) 	err = virtcrypto_start_crypto_engines(vcrypto);
544d79b5d0bSGonglei \(Arei\) 	if (err)
545d79b5d0bSGonglei \(Arei\) 		goto free_vqs;
546d79b5d0bSGonglei \(Arei\) 
547dbaf0624SGonglei 	virtio_device_ready(vdev);
548d79b5d0bSGonglei \(Arei\) 
549dbaf0624SGonglei 	err = virtcrypto_dev_start(vcrypto);
550dbaf0624SGonglei 	if (err) {
551dbaf0624SGonglei 		dev_err(&vdev->dev, "Failed to start virtio crypto device.\n");
552d79b5d0bSGonglei \(Arei\) 		goto free_engines;
553dbaf0624SGonglei 	}
554dbaf0624SGonglei 
555dbaf0624SGonglei 	return 0;
556d79b5d0bSGonglei \(Arei\) 
557d79b5d0bSGonglei \(Arei\) free_engines:
558d79b5d0bSGonglei \(Arei\) 	virtcrypto_clear_crypto_engines(vcrypto);
559d79b5d0bSGonglei \(Arei\) free_vqs:
560d9679d00SMichael S. Tsirkin 	virtio_reset_device(vdev);
561d79b5d0bSGonglei \(Arei\) 	virtcrypto_del_vqs(vcrypto);
562d79b5d0bSGonglei \(Arei\) 	return err;
563dbaf0624SGonglei }
564dbaf0624SGonglei #endif
565dbaf0624SGonglei 
566ad6a0664SRikard Falkeborn static const unsigned int features[] = {
567dbaf0624SGonglei 	/* none */
568dbaf0624SGonglei };
569dbaf0624SGonglei 
570ad6a0664SRikard Falkeborn static const struct virtio_device_id id_table[] = {
571dbaf0624SGonglei 	{ VIRTIO_ID_CRYPTO, VIRTIO_DEV_ANY_ID },
572dbaf0624SGonglei 	{ 0 },
573dbaf0624SGonglei };
574dbaf0624SGonglei 
575dbaf0624SGonglei static struct virtio_driver virtio_crypto_driver = {
576dbaf0624SGonglei 	.driver.name         = KBUILD_MODNAME,
577dbaf0624SGonglei 	.feature_table       = features,
578dbaf0624SGonglei 	.feature_table_size  = ARRAY_SIZE(features),
579dbaf0624SGonglei 	.id_table            = id_table,
580dbaf0624SGonglei 	.probe               = virtcrypto_probe,
581dbaf0624SGonglei 	.remove              = virtcrypto_remove,
582dbaf0624SGonglei 	.config_changed = virtcrypto_config_changed,
583dbaf0624SGonglei #ifdef CONFIG_PM_SLEEP
584dbaf0624SGonglei 	.freeze = virtcrypto_freeze,
585dbaf0624SGonglei 	.restore = virtcrypto_restore,
586dbaf0624SGonglei #endif
587dbaf0624SGonglei };
588dbaf0624SGonglei 
589dbaf0624SGonglei module_virtio_driver(virtio_crypto_driver);
590dbaf0624SGonglei 
591dbaf0624SGonglei MODULE_DEVICE_TABLE(virtio, id_table);
592dbaf0624SGonglei MODULE_DESCRIPTION("virtio crypto device driver");
593dbaf0624SGonglei MODULE_LICENSE("GPL");
594dbaf0624SGonglei MODULE_AUTHOR("Gonglei <arei.gonglei@huawei.com>");
595