1f24bb728SMarc-André Lureau /* 2f24bb728SMarc-André Lureau * QEMU vhost-user backend 3f24bb728SMarc-André Lureau * 4f24bb728SMarc-André Lureau * Copyright (C) 2018 Red Hat Inc 5f24bb728SMarc-André Lureau * 6f24bb728SMarc-André Lureau * Authors: 7f24bb728SMarc-André Lureau * Marc-André Lureau <marcandre.lureau@redhat.com> 8f24bb728SMarc-André Lureau * 9f24bb728SMarc-André Lureau * This work is licensed under the terms of the GNU GPL, version 2 or later. 10f24bb728SMarc-André Lureau * See the COPYING file in the top-level directory. 11f24bb728SMarc-André Lureau */ 12f24bb728SMarc-André Lureau 13f24bb728SMarc-André Lureau 14f24bb728SMarc-André Lureau #include "qemu/osdep.h" 15f24bb728SMarc-André Lureau #include "qapi/error.h" 16f24bb728SMarc-André Lureau #include "qapi/qmp/qerror.h" 17f24bb728SMarc-André Lureau #include "qemu/error-report.h" 18f24bb728SMarc-André Lureau #include "qom/object_interfaces.h" 19f24bb728SMarc-André Lureau #include "sysemu/vhost-user-backend.h" 20f24bb728SMarc-André Lureau #include "sysemu/kvm.h" 21f24bb728SMarc-André Lureau #include "io/channel-command.h" 22f24bb728SMarc-André Lureau #include "hw/virtio/virtio-bus.h" 23f24bb728SMarc-André Lureau 24f24bb728SMarc-André Lureau static bool 25f24bb728SMarc-André Lureau ioeventfd_enabled(void) 26f24bb728SMarc-André Lureau { 27f24bb728SMarc-André Lureau return kvm_enabled() && kvm_eventfds_enabled(); 28f24bb728SMarc-André Lureau } 29f24bb728SMarc-André Lureau 30f24bb728SMarc-André Lureau int 31f24bb728SMarc-André Lureau vhost_user_backend_dev_init(VhostUserBackend *b, VirtIODevice *vdev, 32f24bb728SMarc-André Lureau unsigned nvqs, Error **errp) 33f24bb728SMarc-André Lureau { 34f24bb728SMarc-André Lureau int ret; 35f24bb728SMarc-André Lureau 36f24bb728SMarc-André Lureau assert(!b->vdev && vdev); 37f24bb728SMarc-André Lureau 38f24bb728SMarc-André Lureau if (!ioeventfd_enabled()) { 39f24bb728SMarc-André Lureau error_setg(errp, "vhost initialization failed: requires kvm"); 40f24bb728SMarc-André Lureau return -1; 41f24bb728SMarc-André Lureau } 42f24bb728SMarc-André Lureau 43f24bb728SMarc-André Lureau if (!vhost_user_init(&b->vhost_user, &b->chr, errp)) { 44f24bb728SMarc-André Lureau return -1; 45f24bb728SMarc-André Lureau } 46f24bb728SMarc-André Lureau 47f24bb728SMarc-André Lureau b->vdev = vdev; 48f24bb728SMarc-André Lureau b->dev.nvqs = nvqs; 49b8487a35SRaphael Norwitz b->dev.vqs = g_new0(struct vhost_virtqueue, nvqs); 50f24bb728SMarc-André Lureau 51*a6945f22SKevin Wolf ret = vhost_dev_init(&b->dev, &b->vhost_user, VHOST_BACKEND_TYPE_USER, 0, 52*a6945f22SKevin Wolf errp); 53f24bb728SMarc-André Lureau if (ret < 0) { 54f24bb728SMarc-André Lureau return -1; 55f24bb728SMarc-André Lureau } 56f24bb728SMarc-André Lureau 57f24bb728SMarc-André Lureau return 0; 58f24bb728SMarc-André Lureau } 59f24bb728SMarc-André Lureau 60f24bb728SMarc-André Lureau void 61f24bb728SMarc-André Lureau vhost_user_backend_start(VhostUserBackend *b) 62f24bb728SMarc-André Lureau { 63f24bb728SMarc-André Lureau BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(b->vdev))); 64f24bb728SMarc-André Lureau VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 65f24bb728SMarc-André Lureau int ret, i ; 66f24bb728SMarc-André Lureau 67f24bb728SMarc-André Lureau if (b->started) { 68f24bb728SMarc-André Lureau return; 69f24bb728SMarc-André Lureau } 70f24bb728SMarc-André Lureau 71f24bb728SMarc-André Lureau if (!k->set_guest_notifiers) { 72f24bb728SMarc-André Lureau error_report("binding does not support guest notifiers"); 73f24bb728SMarc-André Lureau return; 74f24bb728SMarc-André Lureau } 75f24bb728SMarc-André Lureau 76f24bb728SMarc-André Lureau ret = vhost_dev_enable_notifiers(&b->dev, b->vdev); 77f24bb728SMarc-André Lureau if (ret < 0) { 78f24bb728SMarc-André Lureau return; 79f24bb728SMarc-André Lureau } 80f24bb728SMarc-André Lureau 81f24bb728SMarc-André Lureau ret = k->set_guest_notifiers(qbus->parent, b->dev.nvqs, true); 82f24bb728SMarc-André Lureau if (ret < 0) { 83f24bb728SMarc-André Lureau error_report("Error binding guest notifier"); 84f24bb728SMarc-André Lureau goto err_host_notifiers; 85f24bb728SMarc-André Lureau } 86f24bb728SMarc-André Lureau 87f24bb728SMarc-André Lureau b->dev.acked_features = b->vdev->guest_features; 88f24bb728SMarc-André Lureau ret = vhost_dev_start(&b->dev, b->vdev); 89f24bb728SMarc-André Lureau if (ret < 0) { 90f24bb728SMarc-André Lureau error_report("Error start vhost dev"); 91f24bb728SMarc-André Lureau goto err_guest_notifiers; 92f24bb728SMarc-André Lureau } 93f24bb728SMarc-André Lureau 94f24bb728SMarc-André Lureau /* guest_notifier_mask/pending not used yet, so just unmask 95f24bb728SMarc-André Lureau * everything here. virtio-pci will do the right thing by 96f24bb728SMarc-André Lureau * enabling/disabling irqfd. 97f24bb728SMarc-André Lureau */ 98f24bb728SMarc-André Lureau for (i = 0; i < b->dev.nvqs; i++) { 99f24bb728SMarc-André Lureau vhost_virtqueue_mask(&b->dev, b->vdev, 100f24bb728SMarc-André Lureau b->dev.vq_index + i, false); 101f24bb728SMarc-André Lureau } 102f24bb728SMarc-André Lureau 103f24bb728SMarc-André Lureau b->started = true; 104f24bb728SMarc-André Lureau return; 105f24bb728SMarc-André Lureau 106f24bb728SMarc-André Lureau err_guest_notifiers: 107f24bb728SMarc-André Lureau k->set_guest_notifiers(qbus->parent, b->dev.nvqs, false); 108f24bb728SMarc-André Lureau err_host_notifiers: 109f24bb728SMarc-André Lureau vhost_dev_disable_notifiers(&b->dev, b->vdev); 110f24bb728SMarc-André Lureau } 111f24bb728SMarc-André Lureau 112f24bb728SMarc-André Lureau void 113f24bb728SMarc-André Lureau vhost_user_backend_stop(VhostUserBackend *b) 114f24bb728SMarc-André Lureau { 115f24bb728SMarc-André Lureau BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(b->vdev))); 116f24bb728SMarc-André Lureau VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 117f24bb728SMarc-André Lureau int ret = 0; 118f24bb728SMarc-André Lureau 119f24bb728SMarc-André Lureau if (!b->started) { 120f24bb728SMarc-André Lureau return; 121f24bb728SMarc-André Lureau } 122f24bb728SMarc-André Lureau 123f24bb728SMarc-André Lureau vhost_dev_stop(&b->dev, b->vdev); 124f24bb728SMarc-André Lureau 125f24bb728SMarc-André Lureau if (k->set_guest_notifiers) { 126f24bb728SMarc-André Lureau ret = k->set_guest_notifiers(qbus->parent, 127f24bb728SMarc-André Lureau b->dev.nvqs, false); 128f24bb728SMarc-André Lureau if (ret < 0) { 129f24bb728SMarc-André Lureau error_report("vhost guest notifier cleanup failed: %d", ret); 130f24bb728SMarc-André Lureau } 131f24bb728SMarc-André Lureau } 132f24bb728SMarc-André Lureau assert(ret >= 0); 133f24bb728SMarc-André Lureau 134f24bb728SMarc-André Lureau vhost_dev_disable_notifiers(&b->dev, b->vdev); 135f24bb728SMarc-André Lureau b->started = false; 136f24bb728SMarc-André Lureau } 137f24bb728SMarc-André Lureau 138f24bb728SMarc-André Lureau static void set_chardev(Object *obj, const char *value, Error **errp) 139f24bb728SMarc-André Lureau { 140f24bb728SMarc-André Lureau VhostUserBackend *b = VHOST_USER_BACKEND(obj); 141f24bb728SMarc-André Lureau Chardev *chr; 142f24bb728SMarc-André Lureau 143f24bb728SMarc-André Lureau if (b->completed) { 144f24bb728SMarc-André Lureau error_setg(errp, QERR_PERMISSION_DENIED); 145f24bb728SMarc-André Lureau return; 146f24bb728SMarc-André Lureau } 147f24bb728SMarc-André Lureau 148f24bb728SMarc-André Lureau g_free(b->chr_name); 149f24bb728SMarc-André Lureau b->chr_name = g_strdup(value); 150f24bb728SMarc-André Lureau 151f24bb728SMarc-André Lureau chr = qemu_chr_find(b->chr_name); 152f24bb728SMarc-André Lureau if (chr == NULL) { 153f24bb728SMarc-André Lureau error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 154f24bb728SMarc-André Lureau "Chardev '%s' not found", b->chr_name); 155f24bb728SMarc-André Lureau return; 156f24bb728SMarc-André Lureau } 157f24bb728SMarc-André Lureau 158f24bb728SMarc-André Lureau if (!qemu_chr_fe_init(&b->chr, chr, errp)) { 159f24bb728SMarc-André Lureau return; 160f24bb728SMarc-André Lureau } 161f24bb728SMarc-André Lureau 162f24bb728SMarc-André Lureau b->completed = true; 163f24bb728SMarc-André Lureau /* could call vhost_dev_init() so early message can be exchanged */ 164f24bb728SMarc-André Lureau } 165f24bb728SMarc-André Lureau 166f24bb728SMarc-André Lureau static char *get_chardev(Object *obj, Error **errp) 167f24bb728SMarc-André Lureau { 168f24bb728SMarc-André Lureau VhostUserBackend *b = VHOST_USER_BACKEND(obj); 169f24bb728SMarc-André Lureau Chardev *chr = qemu_chr_fe_get_driver(&b->chr); 170f24bb728SMarc-André Lureau 171f24bb728SMarc-André Lureau if (chr && chr->label) { 172f24bb728SMarc-André Lureau return g_strdup(chr->label); 173f24bb728SMarc-André Lureau } 174f24bb728SMarc-André Lureau 175f24bb728SMarc-André Lureau return NULL; 176f24bb728SMarc-André Lureau } 177f24bb728SMarc-André Lureau 178abb93698SEduardo Habkost static void vhost_user_backend_class_init(ObjectClass *oc, void *data) 179f24bb728SMarc-André Lureau { 180abb93698SEduardo Habkost object_class_property_add_str(oc, "chardev", get_chardev, set_chardev); 181f24bb728SMarc-André Lureau } 182f24bb728SMarc-André Lureau 183f24bb728SMarc-André Lureau static void vhost_user_backend_finalize(Object *obj) 184f24bb728SMarc-André Lureau { 185f24bb728SMarc-André Lureau VhostUserBackend *b = VHOST_USER_BACKEND(obj); 186f24bb728SMarc-André Lureau 187f24bb728SMarc-André Lureau g_free(b->dev.vqs); 188f24bb728SMarc-André Lureau g_free(b->chr_name); 189f24bb728SMarc-André Lureau 190f24bb728SMarc-André Lureau vhost_user_cleanup(&b->vhost_user); 191f24bb728SMarc-André Lureau qemu_chr_fe_deinit(&b->chr, true); 192f24bb728SMarc-André Lureau } 193f24bb728SMarc-André Lureau 194f24bb728SMarc-André Lureau static const TypeInfo vhost_user_backend_info = { 195f24bb728SMarc-André Lureau .name = TYPE_VHOST_USER_BACKEND, 196f24bb728SMarc-André Lureau .parent = TYPE_OBJECT, 197f24bb728SMarc-André Lureau .instance_size = sizeof(VhostUserBackend), 198abb93698SEduardo Habkost .class_init = vhost_user_backend_class_init, 199f24bb728SMarc-André Lureau .instance_finalize = vhost_user_backend_finalize, 200f24bb728SMarc-André Lureau }; 201f24bb728SMarc-André Lureau 202f24bb728SMarc-André Lureau static void register_types(void) 203f24bb728SMarc-André Lureau { 204f24bb728SMarc-André Lureau type_register_static(&vhost_user_backend_info); 205f24bb728SMarc-André Lureau } 206f24bb728SMarc-André Lureau 207f24bb728SMarc-André Lureau type_init(register_types); 208