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 "qemu/error-report.h" 17f24bb728SMarc-André Lureau #include "qom/object_interfaces.h" 1832cad1ffSPhilippe Mathieu-Daudé #include "system/vhost-user-backend.h" 1932cad1ffSPhilippe Mathieu-Daudé #include "system/kvm.h" 20f24bb728SMarc-André Lureau #include "io/channel-command.h" 21f24bb728SMarc-André Lureau #include "hw/virtio/virtio-bus.h" 22f24bb728SMarc-André Lureau 23f24bb728SMarc-André Lureau int 24f24bb728SMarc-André Lureau vhost_user_backend_dev_init(VhostUserBackend *b, VirtIODevice *vdev, 25f24bb728SMarc-André Lureau unsigned nvqs, Error **errp) 26f24bb728SMarc-André Lureau { 27f24bb728SMarc-André Lureau int ret; 28f24bb728SMarc-André Lureau 29f24bb728SMarc-André Lureau assert(!b->vdev && vdev); 30f24bb728SMarc-André Lureau 31f24bb728SMarc-André Lureau if (!vhost_user_init(&b->vhost_user, &b->chr, errp)) { 32f24bb728SMarc-André Lureau return -1; 33f24bb728SMarc-André Lureau } 34f24bb728SMarc-André Lureau 35f24bb728SMarc-André Lureau b->vdev = vdev; 36f24bb728SMarc-André Lureau b->dev.nvqs = nvqs; 37b8487a35SRaphael Norwitz b->dev.vqs = g_new0(struct vhost_virtqueue, nvqs); 38f24bb728SMarc-André Lureau 39a6945f22SKevin Wolf ret = vhost_dev_init(&b->dev, &b->vhost_user, VHOST_BACKEND_TYPE_USER, 0, 40a6945f22SKevin Wolf errp); 41f24bb728SMarc-André Lureau if (ret < 0) { 42f24bb728SMarc-André Lureau return -1; 43f24bb728SMarc-André Lureau } 44f24bb728SMarc-André Lureau 45f24bb728SMarc-André Lureau return 0; 46f24bb728SMarc-André Lureau } 47f24bb728SMarc-André Lureau 48f24bb728SMarc-André Lureau void 49f24bb728SMarc-André Lureau vhost_user_backend_start(VhostUserBackend *b) 50f24bb728SMarc-André Lureau { 51f24bb728SMarc-André Lureau BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(b->vdev))); 52f24bb728SMarc-André Lureau VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 53f24bb728SMarc-André Lureau int ret, i ; 54f24bb728SMarc-André Lureau 55f24bb728SMarc-André Lureau if (b->started) { 56f24bb728SMarc-André Lureau return; 57f24bb728SMarc-André Lureau } 58f24bb728SMarc-André Lureau 59f24bb728SMarc-André Lureau if (!k->set_guest_notifiers) { 60f24bb728SMarc-André Lureau error_report("binding does not support guest notifiers"); 61f24bb728SMarc-André Lureau return; 62f24bb728SMarc-André Lureau } 63f24bb728SMarc-André Lureau 64f24bb728SMarc-André Lureau ret = vhost_dev_enable_notifiers(&b->dev, b->vdev); 65f24bb728SMarc-André Lureau if (ret < 0) { 66f24bb728SMarc-André Lureau return; 67f24bb728SMarc-André Lureau } 68f24bb728SMarc-André Lureau 69f24bb728SMarc-André Lureau ret = k->set_guest_notifiers(qbus->parent, b->dev.nvqs, true); 70f24bb728SMarc-André Lureau if (ret < 0) { 71f24bb728SMarc-André Lureau error_report("Error binding guest notifier"); 72f24bb728SMarc-André Lureau goto err_host_notifiers; 73f24bb728SMarc-André Lureau } 74f24bb728SMarc-André Lureau 75f24bb728SMarc-André Lureau b->dev.acked_features = b->vdev->guest_features; 764daa5054SStefano Garzarella ret = vhost_dev_start(&b->dev, b->vdev, true); 77f24bb728SMarc-André Lureau if (ret < 0) { 78f24bb728SMarc-André Lureau error_report("Error start vhost dev"); 79f24bb728SMarc-André Lureau goto err_guest_notifiers; 80f24bb728SMarc-André Lureau } 81f24bb728SMarc-André Lureau 82f24bb728SMarc-André Lureau /* guest_notifier_mask/pending not used yet, so just unmask 83f24bb728SMarc-André Lureau * everything here. virtio-pci will do the right thing by 84f24bb728SMarc-André Lureau * enabling/disabling irqfd. 85f24bb728SMarc-André Lureau */ 86f24bb728SMarc-André Lureau for (i = 0; i < b->dev.nvqs; i++) { 87f24bb728SMarc-André Lureau vhost_virtqueue_mask(&b->dev, b->vdev, 88f24bb728SMarc-André Lureau b->dev.vq_index + i, false); 89f24bb728SMarc-André Lureau } 90f24bb728SMarc-André Lureau 91f24bb728SMarc-André Lureau b->started = true; 92f24bb728SMarc-André Lureau return; 93f24bb728SMarc-André Lureau 94f24bb728SMarc-André Lureau err_guest_notifiers: 95f24bb728SMarc-André Lureau k->set_guest_notifiers(qbus->parent, b->dev.nvqs, false); 96f24bb728SMarc-André Lureau err_host_notifiers: 97f24bb728SMarc-André Lureau vhost_dev_disable_notifiers(&b->dev, b->vdev); 98f24bb728SMarc-André Lureau } 99f24bb728SMarc-André Lureau 100*bc85aae4SHaoqian He int 101f24bb728SMarc-André Lureau vhost_user_backend_stop(VhostUserBackend *b) 102f24bb728SMarc-André Lureau { 103f24bb728SMarc-André Lureau BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(b->vdev))); 104f24bb728SMarc-André Lureau VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 105*bc85aae4SHaoqian He int ret; 106f24bb728SMarc-André Lureau 107f24bb728SMarc-André Lureau if (!b->started) { 108*bc85aae4SHaoqian He return 0; 109f24bb728SMarc-André Lureau } 110f24bb728SMarc-André Lureau 111*bc85aae4SHaoqian He ret = vhost_dev_stop(&b->dev, b->vdev, true); 112f24bb728SMarc-André Lureau 113*bc85aae4SHaoqian He if (k->set_guest_notifiers && 114*bc85aae4SHaoqian He k->set_guest_notifiers(qbus->parent, b->dev.nvqs, false) < 0) { 115f24bb728SMarc-André Lureau error_report("vhost guest notifier cleanup failed: %d", ret); 116*bc85aae4SHaoqian He return -1; 117f24bb728SMarc-André Lureau } 118f24bb728SMarc-André Lureau 119f24bb728SMarc-André Lureau vhost_dev_disable_notifiers(&b->dev, b->vdev); 120f24bb728SMarc-André Lureau b->started = false; 121*bc85aae4SHaoqian He return ret; 122f24bb728SMarc-André Lureau } 123f24bb728SMarc-André Lureau 124f24bb728SMarc-André Lureau static void set_chardev(Object *obj, const char *value, Error **errp) 125f24bb728SMarc-André Lureau { 126f24bb728SMarc-André Lureau VhostUserBackend *b = VHOST_USER_BACKEND(obj); 127f24bb728SMarc-André Lureau Chardev *chr; 128f24bb728SMarc-André Lureau 129f24bb728SMarc-André Lureau if (b->completed) { 130ff924448SMarkus Armbruster error_setg(errp, "Property 'chardev' can no longer be set"); 131f24bb728SMarc-André Lureau return; 132f24bb728SMarc-André Lureau } 133f24bb728SMarc-André Lureau 134f24bb728SMarc-André Lureau g_free(b->chr_name); 135f24bb728SMarc-André Lureau b->chr_name = g_strdup(value); 136f24bb728SMarc-André Lureau 137f24bb728SMarc-André Lureau chr = qemu_chr_find(b->chr_name); 138f24bb728SMarc-André Lureau if (chr == NULL) { 139f24bb728SMarc-André Lureau error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND, 140f24bb728SMarc-André Lureau "Chardev '%s' not found", b->chr_name); 141f24bb728SMarc-André Lureau return; 142f24bb728SMarc-André Lureau } 143f24bb728SMarc-André Lureau 144f24bb728SMarc-André Lureau if (!qemu_chr_fe_init(&b->chr, chr, errp)) { 145f24bb728SMarc-André Lureau return; 146f24bb728SMarc-André Lureau } 147f24bb728SMarc-André Lureau 148f24bb728SMarc-André Lureau b->completed = true; 149f24bb728SMarc-André Lureau /* could call vhost_dev_init() so early message can be exchanged */ 150f24bb728SMarc-André Lureau } 151f24bb728SMarc-André Lureau 152f24bb728SMarc-André Lureau static char *get_chardev(Object *obj, Error **errp) 153f24bb728SMarc-André Lureau { 154f24bb728SMarc-André Lureau VhostUserBackend *b = VHOST_USER_BACKEND(obj); 155f24bb728SMarc-André Lureau Chardev *chr = qemu_chr_fe_get_driver(&b->chr); 156f24bb728SMarc-André Lureau 157f24bb728SMarc-André Lureau if (chr && chr->label) { 158f24bb728SMarc-André Lureau return g_strdup(chr->label); 159f24bb728SMarc-André Lureau } 160f24bb728SMarc-André Lureau 161f24bb728SMarc-André Lureau return NULL; 162f24bb728SMarc-André Lureau } 163f24bb728SMarc-André Lureau 16412d1a768SPhilippe Mathieu-Daudé static void vhost_user_backend_class_init(ObjectClass *oc, const void *data) 165f24bb728SMarc-André Lureau { 166abb93698SEduardo Habkost object_class_property_add_str(oc, "chardev", get_chardev, set_chardev); 167f24bb728SMarc-André Lureau } 168f24bb728SMarc-André Lureau 169f24bb728SMarc-André Lureau static void vhost_user_backend_finalize(Object *obj) 170f24bb728SMarc-André Lureau { 171f24bb728SMarc-André Lureau VhostUserBackend *b = VHOST_USER_BACKEND(obj); 172f24bb728SMarc-André Lureau 173f24bb728SMarc-André Lureau g_free(b->dev.vqs); 174f24bb728SMarc-André Lureau g_free(b->chr_name); 175f24bb728SMarc-André Lureau 176f24bb728SMarc-André Lureau vhost_user_cleanup(&b->vhost_user); 177f24bb728SMarc-André Lureau qemu_chr_fe_deinit(&b->chr, true); 178f24bb728SMarc-André Lureau } 179f24bb728SMarc-André Lureau 180f24bb728SMarc-André Lureau static const TypeInfo vhost_user_backend_info = { 181f24bb728SMarc-André Lureau .name = TYPE_VHOST_USER_BACKEND, 182f24bb728SMarc-André Lureau .parent = TYPE_OBJECT, 183f24bb728SMarc-André Lureau .instance_size = sizeof(VhostUserBackend), 184abb93698SEduardo Habkost .class_init = vhost_user_backend_class_init, 185f24bb728SMarc-André Lureau .instance_finalize = vhost_user_backend_finalize, 186f24bb728SMarc-André Lureau }; 187f24bb728SMarc-André Lureau 188f24bb728SMarc-André Lureau static void register_types(void) 189f24bb728SMarc-André Lureau { 190f24bb728SMarc-André Lureau type_register_static(&vhost_user_backend_info); 191f24bb728SMarc-André Lureau } 192f24bb728SMarc-André Lureau 193f24bb728SMarc-André Lureau type_init(register_types); 194