1042cea27SGonglei /*
2042cea27SGonglei * QEMU Cryptodev backend for QEMU cipher APIs
3042cea27SGonglei *
4042cea27SGonglei * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
5042cea27SGonglei *
6042cea27SGonglei * Authors:
7042cea27SGonglei * Gonglei <arei.gonglei@huawei.com>
8042cea27SGonglei * Jay Zhou <jianjay.zhou@huawei.com>
9042cea27SGonglei *
10042cea27SGonglei * This library is free software; you can redistribute it and/or
11042cea27SGonglei * modify it under the terms of the GNU Lesser General Public
12042cea27SGonglei * License as published by the Free Software Foundation; either
130dda001bSChetan Pant * version 2.1 of the License, or (at your option) any later version.
14042cea27SGonglei *
15042cea27SGonglei * This library is distributed in the hope that it will be useful,
16042cea27SGonglei * but WITHOUT ANY WARRANTY; without even the implied warranty of
17042cea27SGonglei * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18042cea27SGonglei * Lesser General Public License for more details.
19042cea27SGonglei *
20042cea27SGonglei * You should have received a copy of the GNU Lesser General Public
21042cea27SGonglei * License along with this library; if not, see <http://www.gnu.org/licenses/>.
22042cea27SGonglei *
23042cea27SGonglei */
24042cea27SGonglei
25042cea27SGonglei #include "qemu/osdep.h"
265da73dabSGonglei #include "hw/virtio/virtio-bus.h"
27042cea27SGonglei #include "sysemu/cryptodev-vhost.h"
28042cea27SGonglei
29042cea27SGonglei #ifdef CONFIG_VHOST_CRYPTO
305da73dabSGonglei #include "qapi/error.h"
315da73dabSGonglei #include "qemu/error-report.h"
325da73dabSGonglei #include "hw/virtio/virtio-crypto.h"
335da73dabSGonglei #include "sysemu/cryptodev-vhost-user.h"
345da73dabSGonglei
35042cea27SGonglei uint64_t
cryptodev_vhost_get_max_queues(CryptoDevBackendVhost * crypto)36042cea27SGonglei cryptodev_vhost_get_max_queues(
37042cea27SGonglei CryptoDevBackendVhost *crypto)
38042cea27SGonglei {
39042cea27SGonglei return crypto->dev.max_queues;
40042cea27SGonglei }
41042cea27SGonglei
cryptodev_vhost_cleanup(CryptoDevBackendVhost * crypto)42042cea27SGonglei void cryptodev_vhost_cleanup(CryptoDevBackendVhost *crypto)
43042cea27SGonglei {
44042cea27SGonglei vhost_dev_cleanup(&crypto->dev);
45042cea27SGonglei g_free(crypto);
46042cea27SGonglei }
47042cea27SGonglei
48042cea27SGonglei struct CryptoDevBackendVhost *
cryptodev_vhost_init(CryptoDevBackendVhostOptions * options)49042cea27SGonglei cryptodev_vhost_init(
50042cea27SGonglei CryptoDevBackendVhostOptions *options)
51042cea27SGonglei {
52042cea27SGonglei int r;
53042cea27SGonglei CryptoDevBackendVhost *crypto;
54a6945f22SKevin Wolf Error *local_err = NULL;
55042cea27SGonglei
56*9b878bd9SStefano Garzarella crypto = g_new0(CryptoDevBackendVhost, 1);
57042cea27SGonglei crypto->dev.max_queues = 1;
58042cea27SGonglei crypto->dev.nvqs = 1;
59042cea27SGonglei crypto->dev.vqs = crypto->vqs;
60042cea27SGonglei
61042cea27SGonglei crypto->cc = options->cc;
62042cea27SGonglei
63042cea27SGonglei crypto->dev.protocol_features = 0;
64042cea27SGonglei crypto->backend = -1;
65042cea27SGonglei
66042cea27SGonglei /* vhost-user needs vq_index to initiate a specific queue pair */
67042cea27SGonglei crypto->dev.vq_index = crypto->cc->queue_index * crypto->dev.nvqs;
68042cea27SGonglei
69a6945f22SKevin Wolf r = vhost_dev_init(&crypto->dev, options->opaque, options->backend_type, 0,
70a6945f22SKevin Wolf &local_err);
71042cea27SGonglei if (r < 0) {
72a6945f22SKevin Wolf error_report_err(local_err);
73042cea27SGonglei goto fail;
74042cea27SGonglei }
75042cea27SGonglei
76042cea27SGonglei return crypto;
77042cea27SGonglei fail:
78042cea27SGonglei g_free(crypto);
79042cea27SGonglei return NULL;
80042cea27SGonglei }
81042cea27SGonglei
825da73dabSGonglei static int
cryptodev_vhost_start_one(CryptoDevBackendVhost * crypto,VirtIODevice * dev)835da73dabSGonglei cryptodev_vhost_start_one(CryptoDevBackendVhost *crypto,
845da73dabSGonglei VirtIODevice *dev)
855da73dabSGonglei {
865da73dabSGonglei int r;
875da73dabSGonglei
885da73dabSGonglei crypto->dev.nvqs = 1;
895da73dabSGonglei crypto->dev.vqs = crypto->vqs;
905da73dabSGonglei
915da73dabSGonglei r = vhost_dev_enable_notifiers(&crypto->dev, dev);
925da73dabSGonglei if (r < 0) {
935da73dabSGonglei goto fail_notifiers;
945da73dabSGonglei }
955da73dabSGonglei
964daa5054SStefano Garzarella r = vhost_dev_start(&crypto->dev, dev, false);
975da73dabSGonglei if (r < 0) {
985da73dabSGonglei goto fail_start;
995da73dabSGonglei }
1005da73dabSGonglei
1015da73dabSGonglei return 0;
1025da73dabSGonglei
1035da73dabSGonglei fail_start:
1045da73dabSGonglei vhost_dev_disable_notifiers(&crypto->dev, dev);
1055da73dabSGonglei fail_notifiers:
1065da73dabSGonglei return r;
1075da73dabSGonglei }
1085da73dabSGonglei
1095da73dabSGonglei static void
cryptodev_vhost_stop_one(CryptoDevBackendVhost * crypto,VirtIODevice * dev)1105da73dabSGonglei cryptodev_vhost_stop_one(CryptoDevBackendVhost *crypto,
1115da73dabSGonglei VirtIODevice *dev)
1125da73dabSGonglei {
1134daa5054SStefano Garzarella vhost_dev_stop(&crypto->dev, dev, false);
1145da73dabSGonglei vhost_dev_disable_notifiers(&crypto->dev, dev);
1155da73dabSGonglei }
1165da73dabSGonglei
1175da73dabSGonglei CryptoDevBackendVhost *
cryptodev_get_vhost(CryptoDevBackendClient * cc,CryptoDevBackend * b,uint16_t queue)1185da73dabSGonglei cryptodev_get_vhost(CryptoDevBackendClient *cc,
1195da73dabSGonglei CryptoDevBackend *b,
1205da73dabSGonglei uint16_t queue)
1215da73dabSGonglei {
1225da73dabSGonglei CryptoDevBackendVhost *vhost_crypto = NULL;
1235da73dabSGonglei
1245da73dabSGonglei if (!cc) {
1255da73dabSGonglei return NULL;
1265da73dabSGonglei }
1275da73dabSGonglei
1285da73dabSGonglei switch (cc->type) {
1295da73dabSGonglei #if defined(CONFIG_VHOST_USER) && defined(CONFIG_LINUX)
13014c9fd16Szhenwei pi case QCRYPTODEV_BACKEND_TYPE_VHOST_USER:
1315da73dabSGonglei vhost_crypto = cryptodev_vhost_user_get_vhost(cc, b, queue);
1325da73dabSGonglei break;
1335da73dabSGonglei #endif
1345da73dabSGonglei default:
1355da73dabSGonglei break;
1365da73dabSGonglei }
1375da73dabSGonglei
1385da73dabSGonglei return vhost_crypto;
1395da73dabSGonglei }
1405da73dabSGonglei
1415da73dabSGonglei static void
cryptodev_vhost_set_vq_index(CryptoDevBackendVhost * crypto,int vq_index)1425da73dabSGonglei cryptodev_vhost_set_vq_index(CryptoDevBackendVhost *crypto,
1435da73dabSGonglei int vq_index)
1445da73dabSGonglei {
1455da73dabSGonglei crypto->dev.vq_index = vq_index;
1465da73dabSGonglei }
1475da73dabSGonglei
1485da73dabSGonglei static int
vhost_set_vring_enable(CryptoDevBackendClient * cc,CryptoDevBackend * b,uint16_t queue,int enable)1495da73dabSGonglei vhost_set_vring_enable(CryptoDevBackendClient *cc,
1505da73dabSGonglei CryptoDevBackend *b,
1515da73dabSGonglei uint16_t queue, int enable)
1525da73dabSGonglei {
1535da73dabSGonglei CryptoDevBackendVhost *crypto =
1545da73dabSGonglei cryptodev_get_vhost(cc, b, queue);
1555da73dabSGonglei const VhostOps *vhost_ops;
1565da73dabSGonglei
1575da73dabSGonglei cc->vring_enable = enable;
1585da73dabSGonglei
1595da73dabSGonglei if (!crypto) {
1605da73dabSGonglei return 0;
1615da73dabSGonglei }
1625da73dabSGonglei
1635da73dabSGonglei vhost_ops = crypto->dev.vhost_ops;
1645da73dabSGonglei if (vhost_ops->vhost_set_vring_enable) {
1655da73dabSGonglei return vhost_ops->vhost_set_vring_enable(&crypto->dev, enable);
1665da73dabSGonglei }
1675da73dabSGonglei
1685da73dabSGonglei return 0;
1695da73dabSGonglei }
1705da73dabSGonglei
cryptodev_vhost_start(VirtIODevice * dev,int total_queues)1715da73dabSGonglei int cryptodev_vhost_start(VirtIODevice *dev, int total_queues)
1725da73dabSGonglei {
1735da73dabSGonglei VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev);
1745da73dabSGonglei BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
1755da73dabSGonglei VirtioBusState *vbus = VIRTIO_BUS(qbus);
1765da73dabSGonglei VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
1775da73dabSGonglei int r, e;
1785da73dabSGonglei int i;
1795da73dabSGonglei CryptoDevBackend *b = vcrypto->cryptodev;
1805da73dabSGonglei CryptoDevBackendVhost *vhost_crypto;
1815da73dabSGonglei CryptoDevBackendClient *cc;
1825da73dabSGonglei
1835da73dabSGonglei if (!k->set_guest_notifiers) {
1845da73dabSGonglei error_report("binding does not support guest notifiers");
1855da73dabSGonglei return -ENOSYS;
1865da73dabSGonglei }
1875da73dabSGonglei
1885da73dabSGonglei for (i = 0; i < total_queues; i++) {
1895da73dabSGonglei cc = b->conf.peers.ccs[i];
1905da73dabSGonglei
1915da73dabSGonglei vhost_crypto = cryptodev_get_vhost(cc, b, i);
1925da73dabSGonglei cryptodev_vhost_set_vq_index(vhost_crypto, i);
1935da73dabSGonglei
1945da73dabSGonglei /* Suppress the masking guest notifiers on vhost user
1955da73dabSGonglei * because vhost user doesn't interrupt masking/unmasking
1965da73dabSGonglei * properly.
1975da73dabSGonglei */
19814c9fd16Szhenwei pi if (cc->type == QCRYPTODEV_BACKEND_TYPE_VHOST_USER) {
1995da73dabSGonglei dev->use_guest_notifier_mask = false;
2005da73dabSGonglei }
2015da73dabSGonglei }
2025da73dabSGonglei
2035da73dabSGonglei r = k->set_guest_notifiers(qbus->parent, total_queues, true);
2045da73dabSGonglei if (r < 0) {
2055da73dabSGonglei error_report("error binding guest notifier: %d", -r);
2065da73dabSGonglei goto err;
2075da73dabSGonglei }
2085da73dabSGonglei
2095da73dabSGonglei for (i = 0; i < total_queues; i++) {
2105da73dabSGonglei cc = b->conf.peers.ccs[i];
2115da73dabSGonglei
2125da73dabSGonglei vhost_crypto = cryptodev_get_vhost(cc, b, i);
2135da73dabSGonglei r = cryptodev_vhost_start_one(vhost_crypto, dev);
2145da73dabSGonglei
2155da73dabSGonglei if (r < 0) {
2165da73dabSGonglei goto err_start;
2175da73dabSGonglei }
2185da73dabSGonglei
2195da73dabSGonglei if (cc->vring_enable) {
2205da73dabSGonglei /* restore vring enable state */
2215da73dabSGonglei r = vhost_set_vring_enable(cc, b, i, cc->vring_enable);
2225da73dabSGonglei
2235da73dabSGonglei if (r < 0) {
2245da73dabSGonglei goto err_start;
2255da73dabSGonglei }
2265da73dabSGonglei }
2275da73dabSGonglei }
2285da73dabSGonglei
2295da73dabSGonglei return 0;
2305da73dabSGonglei
2315da73dabSGonglei err_start:
2325da73dabSGonglei while (--i >= 0) {
2335da73dabSGonglei cc = b->conf.peers.ccs[i];
2345da73dabSGonglei vhost_crypto = cryptodev_get_vhost(cc, b, i);
2355da73dabSGonglei cryptodev_vhost_stop_one(vhost_crypto, dev);
2365da73dabSGonglei }
2375da73dabSGonglei e = k->set_guest_notifiers(qbus->parent, total_queues, false);
2385da73dabSGonglei if (e < 0) {
2395da73dabSGonglei error_report("vhost guest notifier cleanup failed: %d", e);
2405da73dabSGonglei }
2415da73dabSGonglei err:
2425da73dabSGonglei return r;
2435da73dabSGonglei }
2445da73dabSGonglei
cryptodev_vhost_stop(VirtIODevice * dev,int total_queues)2455da73dabSGonglei void cryptodev_vhost_stop(VirtIODevice *dev, int total_queues)
2465da73dabSGonglei {
2475da73dabSGonglei BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(dev)));
2485da73dabSGonglei VirtioBusState *vbus = VIRTIO_BUS(qbus);
2495da73dabSGonglei VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
2505da73dabSGonglei VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev);
2515da73dabSGonglei CryptoDevBackend *b = vcrypto->cryptodev;
2525da73dabSGonglei CryptoDevBackendVhost *vhost_crypto;
2535da73dabSGonglei CryptoDevBackendClient *cc;
2545da73dabSGonglei size_t i;
2555da73dabSGonglei int r;
2565da73dabSGonglei
2575da73dabSGonglei for (i = 0; i < total_queues; i++) {
2585da73dabSGonglei cc = b->conf.peers.ccs[i];
2595da73dabSGonglei
2605da73dabSGonglei vhost_crypto = cryptodev_get_vhost(cc, b, i);
2615da73dabSGonglei cryptodev_vhost_stop_one(vhost_crypto, dev);
2625da73dabSGonglei }
2635da73dabSGonglei
2645da73dabSGonglei r = k->set_guest_notifiers(qbus->parent, total_queues, false);
2655da73dabSGonglei if (r < 0) {
2665da73dabSGonglei error_report("vhost guest notifier cleanup failed: %d", r);
2675da73dabSGonglei }
2685da73dabSGonglei assert(r >= 0);
2695da73dabSGonglei }
2705da73dabSGonglei
cryptodev_vhost_virtqueue_mask(VirtIODevice * dev,int queue,int idx,bool mask)2715da73dabSGonglei void cryptodev_vhost_virtqueue_mask(VirtIODevice *dev,
2725da73dabSGonglei int queue,
2735da73dabSGonglei int idx, bool mask)
2745da73dabSGonglei {
2755da73dabSGonglei VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev);
2765da73dabSGonglei CryptoDevBackend *b = vcrypto->cryptodev;
2775da73dabSGonglei CryptoDevBackendVhost *vhost_crypto;
2785da73dabSGonglei CryptoDevBackendClient *cc;
2795da73dabSGonglei
2805da73dabSGonglei assert(queue < MAX_CRYPTO_QUEUE_NUM);
2815da73dabSGonglei
2825da73dabSGonglei cc = b->conf.peers.ccs[queue];
2835da73dabSGonglei vhost_crypto = cryptodev_get_vhost(cc, b, queue);
2845da73dabSGonglei
2855da73dabSGonglei vhost_virtqueue_mask(&vhost_crypto->dev, dev, idx, mask);
2865da73dabSGonglei }
2875da73dabSGonglei
cryptodev_vhost_virtqueue_pending(VirtIODevice * dev,int queue,int idx)2885da73dabSGonglei bool cryptodev_vhost_virtqueue_pending(VirtIODevice *dev,
2895da73dabSGonglei int queue, int idx)
2905da73dabSGonglei {
2915da73dabSGonglei VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(dev);
2925da73dabSGonglei CryptoDevBackend *b = vcrypto->cryptodev;
2935da73dabSGonglei CryptoDevBackendVhost *vhost_crypto;
2945da73dabSGonglei CryptoDevBackendClient *cc;
2955da73dabSGonglei
2965da73dabSGonglei assert(queue < MAX_CRYPTO_QUEUE_NUM);
2975da73dabSGonglei
2985da73dabSGonglei cc = b->conf.peers.ccs[queue];
2995da73dabSGonglei vhost_crypto = cryptodev_get_vhost(cc, b, queue);
3005da73dabSGonglei
3015da73dabSGonglei return vhost_virtqueue_pending(&vhost_crypto->dev, idx);
3025da73dabSGonglei }
3035da73dabSGonglei
304042cea27SGonglei #else
305042cea27SGonglei uint64_t
cryptodev_vhost_get_max_queues(CryptoDevBackendVhost * crypto)306042cea27SGonglei cryptodev_vhost_get_max_queues(CryptoDevBackendVhost *crypto)
307042cea27SGonglei {
308042cea27SGonglei return 0;
309042cea27SGonglei }
310042cea27SGonglei
cryptodev_vhost_cleanup(CryptoDevBackendVhost * crypto)311042cea27SGonglei void cryptodev_vhost_cleanup(CryptoDevBackendVhost *crypto)
312042cea27SGonglei {
313042cea27SGonglei }
314042cea27SGonglei
315042cea27SGonglei struct CryptoDevBackendVhost *
cryptodev_vhost_init(CryptoDevBackendVhostOptions * options)316042cea27SGonglei cryptodev_vhost_init(CryptoDevBackendVhostOptions *options)
317042cea27SGonglei {
318042cea27SGonglei return NULL;
319042cea27SGonglei }
3205da73dabSGonglei
3215da73dabSGonglei CryptoDevBackendVhost *
cryptodev_get_vhost(CryptoDevBackendClient * cc,CryptoDevBackend * b,uint16_t queue)3225da73dabSGonglei cryptodev_get_vhost(CryptoDevBackendClient *cc,
3235da73dabSGonglei CryptoDevBackend *b,
3245da73dabSGonglei uint16_t queue)
3255da73dabSGonglei {
3265da73dabSGonglei return NULL;
3275da73dabSGonglei }
3285da73dabSGonglei
cryptodev_vhost_start(VirtIODevice * dev,int total_queues)3295da73dabSGonglei int cryptodev_vhost_start(VirtIODevice *dev, int total_queues)
3305da73dabSGonglei {
3315da73dabSGonglei return -1;
3325da73dabSGonglei }
3335da73dabSGonglei
cryptodev_vhost_stop(VirtIODevice * dev,int total_queues)3345da73dabSGonglei void cryptodev_vhost_stop(VirtIODevice *dev, int total_queues)
3355da73dabSGonglei {
3365da73dabSGonglei }
3375da73dabSGonglei
cryptodev_vhost_virtqueue_mask(VirtIODevice * dev,int queue,int idx,bool mask)3385da73dabSGonglei void cryptodev_vhost_virtqueue_mask(VirtIODevice *dev,
3395da73dabSGonglei int queue,
3405da73dabSGonglei int idx, bool mask)
3415da73dabSGonglei {
3425da73dabSGonglei }
3435da73dabSGonglei
cryptodev_vhost_virtqueue_pending(VirtIODevice * dev,int queue,int idx)3445da73dabSGonglei bool cryptodev_vhost_virtqueue_pending(VirtIODevice *dev,
3455da73dabSGonglei int queue, int idx)
3465da73dabSGonglei {
3475da73dabSGonglei return false;
3485da73dabSGonglei }
349042cea27SGonglei #endif
350