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