xref: /openbmc/qemu/backends/cryptodev-vhost.c (revision 9b878bd927fe32d73ef2d468a2bd154ff523abb6)
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