1*eee77809SAlex Bennée /* 2*eee77809SAlex Bennée * Generic vhost-user stub. This can be used to connect to any 3*eee77809SAlex Bennée * vhost-user backend. All configuration details must be handled by 4*eee77809SAlex Bennée * the vhost-user daemon itself 5*eee77809SAlex Bennée * 6*eee77809SAlex Bennée * Copyright (c) 2023 Linaro Ltd 7*eee77809SAlex Bennée * Author: Alex Bennée <alex.bennee@linaro.org> 8*eee77809SAlex Bennée * 9*eee77809SAlex Bennée * SPDX-License-Identifier: GPL-2.0-or-later 10*eee77809SAlex Bennée */ 11*eee77809SAlex Bennée 12*eee77809SAlex Bennée #include "qemu/osdep.h" 13*eee77809SAlex Bennée #include "qapi/error.h" 14*eee77809SAlex Bennée #include "hw/qdev-properties.h" 15*eee77809SAlex Bennée #include "hw/virtio/virtio-bus.h" 16*eee77809SAlex Bennée #include "hw/virtio/vhost-user-device.h" 17*eee77809SAlex Bennée #include "qemu/error-report.h" 18*eee77809SAlex Bennée 19*eee77809SAlex Bennée static void vub_start(VirtIODevice *vdev) 20*eee77809SAlex Bennée { 21*eee77809SAlex Bennée BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 22*eee77809SAlex Bennée VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 23*eee77809SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 24*eee77809SAlex Bennée int ret, i; 25*eee77809SAlex Bennée 26*eee77809SAlex Bennée if (!k->set_guest_notifiers) { 27*eee77809SAlex Bennée error_report("binding does not support guest notifiers"); 28*eee77809SAlex Bennée return; 29*eee77809SAlex Bennée } 30*eee77809SAlex Bennée 31*eee77809SAlex Bennée ret = vhost_dev_enable_notifiers(&vub->vhost_dev, vdev); 32*eee77809SAlex Bennée if (ret < 0) { 33*eee77809SAlex Bennée error_report("Error enabling host notifiers: %d", -ret); 34*eee77809SAlex Bennée return; 35*eee77809SAlex Bennée } 36*eee77809SAlex Bennée 37*eee77809SAlex Bennée ret = k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, true); 38*eee77809SAlex Bennée if (ret < 0) { 39*eee77809SAlex Bennée error_report("Error binding guest notifier: %d", -ret); 40*eee77809SAlex Bennée goto err_host_notifiers; 41*eee77809SAlex Bennée } 42*eee77809SAlex Bennée 43*eee77809SAlex Bennée vub->vhost_dev.acked_features = vdev->guest_features; 44*eee77809SAlex Bennée 45*eee77809SAlex Bennée ret = vhost_dev_start(&vub->vhost_dev, vdev, true); 46*eee77809SAlex Bennée if (ret < 0) { 47*eee77809SAlex Bennée error_report("Error starting vhost-user-device: %d", -ret); 48*eee77809SAlex Bennée goto err_guest_notifiers; 49*eee77809SAlex Bennée } 50*eee77809SAlex Bennée 51*eee77809SAlex Bennée /* 52*eee77809SAlex Bennée * guest_notifier_mask/pending not used yet, so just unmask 53*eee77809SAlex Bennée * everything here. virtio-pci will do the right thing by 54*eee77809SAlex Bennée * enabling/disabling irqfd. 55*eee77809SAlex Bennée */ 56*eee77809SAlex Bennée for (i = 0; i < vub->vhost_dev.nvqs; i++) { 57*eee77809SAlex Bennée vhost_virtqueue_mask(&vub->vhost_dev, vdev, i, false); 58*eee77809SAlex Bennée } 59*eee77809SAlex Bennée 60*eee77809SAlex Bennée return; 61*eee77809SAlex Bennée 62*eee77809SAlex Bennée err_guest_notifiers: 63*eee77809SAlex Bennée k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false); 64*eee77809SAlex Bennée err_host_notifiers: 65*eee77809SAlex Bennée vhost_dev_disable_notifiers(&vub->vhost_dev, vdev); 66*eee77809SAlex Bennée } 67*eee77809SAlex Bennée 68*eee77809SAlex Bennée static void vub_stop(VirtIODevice *vdev) 69*eee77809SAlex Bennée { 70*eee77809SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 71*eee77809SAlex Bennée BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 72*eee77809SAlex Bennée VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 73*eee77809SAlex Bennée int ret; 74*eee77809SAlex Bennée 75*eee77809SAlex Bennée if (!k->set_guest_notifiers) { 76*eee77809SAlex Bennée return; 77*eee77809SAlex Bennée } 78*eee77809SAlex Bennée 79*eee77809SAlex Bennée vhost_dev_stop(&vub->vhost_dev, vdev, true); 80*eee77809SAlex Bennée 81*eee77809SAlex Bennée ret = k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false); 82*eee77809SAlex Bennée if (ret < 0) { 83*eee77809SAlex Bennée error_report("vhost guest notifier cleanup failed: %d", ret); 84*eee77809SAlex Bennée return; 85*eee77809SAlex Bennée } 86*eee77809SAlex Bennée 87*eee77809SAlex Bennée vhost_dev_disable_notifiers(&vub->vhost_dev, vdev); 88*eee77809SAlex Bennée } 89*eee77809SAlex Bennée 90*eee77809SAlex Bennée static void vub_set_status(VirtIODevice *vdev, uint8_t status) 91*eee77809SAlex Bennée { 92*eee77809SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 93*eee77809SAlex Bennée bool should_start = virtio_device_should_start(vdev, status); 94*eee77809SAlex Bennée 95*eee77809SAlex Bennée if (vhost_dev_is_started(&vub->vhost_dev) == should_start) { 96*eee77809SAlex Bennée return; 97*eee77809SAlex Bennée } 98*eee77809SAlex Bennée 99*eee77809SAlex Bennée if (should_start) { 100*eee77809SAlex Bennée vub_start(vdev); 101*eee77809SAlex Bennée } else { 102*eee77809SAlex Bennée vub_stop(vdev); 103*eee77809SAlex Bennée } 104*eee77809SAlex Bennée } 105*eee77809SAlex Bennée 106*eee77809SAlex Bennée /* 107*eee77809SAlex Bennée * For an implementation where everything is delegated to the backend 108*eee77809SAlex Bennée * we don't do anything other than return the full feature set offered 109*eee77809SAlex Bennée * by the daemon (module the reserved feature bit). 110*eee77809SAlex Bennée */ 111*eee77809SAlex Bennée static uint64_t vub_get_features(VirtIODevice *vdev, 112*eee77809SAlex Bennée uint64_t requested_features, Error **errp) 113*eee77809SAlex Bennée { 114*eee77809SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 115*eee77809SAlex Bennée /* This should be set when the vhost connection initialises */ 116*eee77809SAlex Bennée g_assert(vub->vhost_dev.features); 117*eee77809SAlex Bennée return vub->vhost_dev.features & ~(1ULL << VHOST_USER_F_PROTOCOL_FEATURES); 118*eee77809SAlex Bennée } 119*eee77809SAlex Bennée 120*eee77809SAlex Bennée static void vub_handle_output(VirtIODevice *vdev, VirtQueue *vq) 121*eee77809SAlex Bennée { 122*eee77809SAlex Bennée /* 123*eee77809SAlex Bennée * Not normally called; it's the daemon that handles the queue; 124*eee77809SAlex Bennée * however virtio's cleanup path can call this. 125*eee77809SAlex Bennée */ 126*eee77809SAlex Bennée } 127*eee77809SAlex Bennée 128*eee77809SAlex Bennée static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserBase *vub) 129*eee77809SAlex Bennée { 130*eee77809SAlex Bennée vhost_user_cleanup(&vub->vhost_user); 131*eee77809SAlex Bennée 132*eee77809SAlex Bennée for (int i = 0; i < vub->num_vqs; i++) { 133*eee77809SAlex Bennée VirtQueue *vq = g_ptr_array_index(vub->vqs, i); 134*eee77809SAlex Bennée virtio_delete_queue(vq); 135*eee77809SAlex Bennée } 136*eee77809SAlex Bennée 137*eee77809SAlex Bennée virtio_cleanup(vdev); 138*eee77809SAlex Bennée } 139*eee77809SAlex Bennée 140*eee77809SAlex Bennée static int vub_connect(DeviceState *dev) 141*eee77809SAlex Bennée { 142*eee77809SAlex Bennée VirtIODevice *vdev = VIRTIO_DEVICE(dev); 143*eee77809SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 144*eee77809SAlex Bennée 145*eee77809SAlex Bennée if (vub->connected) { 146*eee77809SAlex Bennée return 0; 147*eee77809SAlex Bennée } 148*eee77809SAlex Bennée vub->connected = true; 149*eee77809SAlex Bennée 150*eee77809SAlex Bennée /* restore vhost state */ 151*eee77809SAlex Bennée if (virtio_device_started(vdev, vdev->status)) { 152*eee77809SAlex Bennée vub_start(vdev); 153*eee77809SAlex Bennée } 154*eee77809SAlex Bennée 155*eee77809SAlex Bennée return 0; 156*eee77809SAlex Bennée } 157*eee77809SAlex Bennée 158*eee77809SAlex Bennée static void vub_disconnect(DeviceState *dev) 159*eee77809SAlex Bennée { 160*eee77809SAlex Bennée VirtIODevice *vdev = VIRTIO_DEVICE(dev); 161*eee77809SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 162*eee77809SAlex Bennée 163*eee77809SAlex Bennée if (!vub->connected) { 164*eee77809SAlex Bennée return; 165*eee77809SAlex Bennée } 166*eee77809SAlex Bennée vub->connected = false; 167*eee77809SAlex Bennée 168*eee77809SAlex Bennée if (vhost_dev_is_started(&vub->vhost_dev)) { 169*eee77809SAlex Bennée vub_stop(vdev); 170*eee77809SAlex Bennée } 171*eee77809SAlex Bennée } 172*eee77809SAlex Bennée 173*eee77809SAlex Bennée static void vub_event(void *opaque, QEMUChrEvent event) 174*eee77809SAlex Bennée { 175*eee77809SAlex Bennée DeviceState *dev = opaque; 176*eee77809SAlex Bennée VirtIODevice *vdev = VIRTIO_DEVICE(dev); 177*eee77809SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(vdev); 178*eee77809SAlex Bennée 179*eee77809SAlex Bennée switch (event) { 180*eee77809SAlex Bennée case CHR_EVENT_OPENED: 181*eee77809SAlex Bennée if (vub_connect(dev) < 0) { 182*eee77809SAlex Bennée qemu_chr_fe_disconnect(&vub->chardev); 183*eee77809SAlex Bennée return; 184*eee77809SAlex Bennée } 185*eee77809SAlex Bennée break; 186*eee77809SAlex Bennée case CHR_EVENT_CLOSED: 187*eee77809SAlex Bennée vub_disconnect(dev); 188*eee77809SAlex Bennée break; 189*eee77809SAlex Bennée case CHR_EVENT_BREAK: 190*eee77809SAlex Bennée case CHR_EVENT_MUX_IN: 191*eee77809SAlex Bennée case CHR_EVENT_MUX_OUT: 192*eee77809SAlex Bennée /* Ignore */ 193*eee77809SAlex Bennée break; 194*eee77809SAlex Bennée } 195*eee77809SAlex Bennée } 196*eee77809SAlex Bennée 197*eee77809SAlex Bennée static void vub_device_realize(DeviceState *dev, Error **errp) 198*eee77809SAlex Bennée { 199*eee77809SAlex Bennée VirtIODevice *vdev = VIRTIO_DEVICE(dev); 200*eee77809SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(dev); 201*eee77809SAlex Bennée int ret; 202*eee77809SAlex Bennée 203*eee77809SAlex Bennée if (!vub->chardev.chr) { 204*eee77809SAlex Bennée error_setg(errp, "vhost-user-device: missing chardev"); 205*eee77809SAlex Bennée return; 206*eee77809SAlex Bennée } 207*eee77809SAlex Bennée 208*eee77809SAlex Bennée if (!vub->virtio_id) { 209*eee77809SAlex Bennée error_setg(errp, "vhost-user-device: need to define device id"); 210*eee77809SAlex Bennée return; 211*eee77809SAlex Bennée } 212*eee77809SAlex Bennée 213*eee77809SAlex Bennée if (!vub->num_vqs) { 214*eee77809SAlex Bennée vub->num_vqs = 1; /* reasonable default? */ 215*eee77809SAlex Bennée } 216*eee77809SAlex Bennée 217*eee77809SAlex Bennée if (!vhost_user_init(&vub->vhost_user, &vub->chardev, errp)) { 218*eee77809SAlex Bennée return; 219*eee77809SAlex Bennée } 220*eee77809SAlex Bennée 221*eee77809SAlex Bennée virtio_init(vdev, vub->virtio_id, 0); 222*eee77809SAlex Bennée 223*eee77809SAlex Bennée /* 224*eee77809SAlex Bennée * Disable guest notifiers, by default all notifications will be via the 225*eee77809SAlex Bennée * asynchronous vhost-user socket. 226*eee77809SAlex Bennée */ 227*eee77809SAlex Bennée vdev->use_guest_notifier_mask = false; 228*eee77809SAlex Bennée 229*eee77809SAlex Bennée /* Allocate queues */ 230*eee77809SAlex Bennée vub->vqs = g_ptr_array_sized_new(vub->num_vqs); 231*eee77809SAlex Bennée for (int i = 0; i < vub->num_vqs; i++) { 232*eee77809SAlex Bennée g_ptr_array_add(vub->vqs, 233*eee77809SAlex Bennée virtio_add_queue(vdev, 4, vub_handle_output)); 234*eee77809SAlex Bennée } 235*eee77809SAlex Bennée 236*eee77809SAlex Bennée vub->vhost_dev.nvqs = vub->num_vqs; 237*eee77809SAlex Bennée vub->vhost_dev.vqs = g_new0(struct vhost_virtqueue, vub->vhost_dev.nvqs); 238*eee77809SAlex Bennée 239*eee77809SAlex Bennée /* connect to backend */ 240*eee77809SAlex Bennée ret = vhost_dev_init(&vub->vhost_dev, &vub->vhost_user, 241*eee77809SAlex Bennée VHOST_BACKEND_TYPE_USER, 0, errp); 242*eee77809SAlex Bennée 243*eee77809SAlex Bennée if (ret < 0) { 244*eee77809SAlex Bennée do_vhost_user_cleanup(vdev, vub); 245*eee77809SAlex Bennée } 246*eee77809SAlex Bennée 247*eee77809SAlex Bennée qemu_chr_fe_set_handlers(&vub->chardev, NULL, NULL, vub_event, NULL, 248*eee77809SAlex Bennée dev, NULL, true); 249*eee77809SAlex Bennée } 250*eee77809SAlex Bennée 251*eee77809SAlex Bennée static void vub_device_unrealize(DeviceState *dev) 252*eee77809SAlex Bennée { 253*eee77809SAlex Bennée VirtIODevice *vdev = VIRTIO_DEVICE(dev); 254*eee77809SAlex Bennée VHostUserBase *vub = VHOST_USER_BASE(dev); 255*eee77809SAlex Bennée struct vhost_virtqueue *vhost_vqs = vub->vhost_dev.vqs; 256*eee77809SAlex Bennée 257*eee77809SAlex Bennée /* This will stop vhost backend if appropriate. */ 258*eee77809SAlex Bennée vub_set_status(vdev, 0); 259*eee77809SAlex Bennée vhost_dev_cleanup(&vub->vhost_dev); 260*eee77809SAlex Bennée g_free(vhost_vqs); 261*eee77809SAlex Bennée do_vhost_user_cleanup(vdev, vub); 262*eee77809SAlex Bennée } 263*eee77809SAlex Bennée 264*eee77809SAlex Bennée static void vub_class_init(ObjectClass *klass, void *data) 265*eee77809SAlex Bennée { 266*eee77809SAlex Bennée VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 267*eee77809SAlex Bennée 268*eee77809SAlex Bennée vdc->realize = vub_device_realize; 269*eee77809SAlex Bennée vdc->unrealize = vub_device_unrealize; 270*eee77809SAlex Bennée vdc->get_features = vub_get_features; 271*eee77809SAlex Bennée vdc->set_status = vub_set_status; 272*eee77809SAlex Bennée } 273*eee77809SAlex Bennée 274*eee77809SAlex Bennée static const TypeInfo vub_info = { 275*eee77809SAlex Bennée .name = TYPE_VHOST_USER_BASE, 276*eee77809SAlex Bennée .parent = TYPE_VIRTIO_DEVICE, 277*eee77809SAlex Bennée .instance_size = sizeof(VHostUserBase), 278*eee77809SAlex Bennée .class_init = vub_class_init, 279*eee77809SAlex Bennée .class_size = sizeof(VHostUserBaseClass), 280*eee77809SAlex Bennée .abstract = true 281*eee77809SAlex Bennée }; 282*eee77809SAlex Bennée 283*eee77809SAlex Bennée 284*eee77809SAlex Bennée /* 285*eee77809SAlex Bennée * The following is a concrete implementation of the base class which 286*eee77809SAlex Bennée * allows the user to define the key parameters via the command line. 287*eee77809SAlex Bennée */ 288*eee77809SAlex Bennée 289*eee77809SAlex Bennée static const VMStateDescription vud_vmstate = { 290*eee77809SAlex Bennée .name = "vhost-user-device", 291*eee77809SAlex Bennée .unmigratable = 1, 292*eee77809SAlex Bennée }; 293*eee77809SAlex Bennée 294*eee77809SAlex Bennée static Property vud_properties[] = { 295*eee77809SAlex Bennée DEFINE_PROP_CHR("chardev", VHostUserBase, chardev), 296*eee77809SAlex Bennée DEFINE_PROP_UINT16("virtio-id", VHostUserBase, virtio_id, 0), 297*eee77809SAlex Bennée DEFINE_PROP_UINT32("num_vqs", VHostUserBase, num_vqs, 1), 298*eee77809SAlex Bennée DEFINE_PROP_END_OF_LIST(), 299*eee77809SAlex Bennée }; 300*eee77809SAlex Bennée 301*eee77809SAlex Bennée static void vud_class_init(ObjectClass *klass, void *data) 302*eee77809SAlex Bennée { 303*eee77809SAlex Bennée DeviceClass *dc = DEVICE_CLASS(klass); 304*eee77809SAlex Bennée 305*eee77809SAlex Bennée device_class_set_props(dc, vud_properties); 306*eee77809SAlex Bennée dc->vmsd = &vud_vmstate; 307*eee77809SAlex Bennée set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 308*eee77809SAlex Bennée } 309*eee77809SAlex Bennée 310*eee77809SAlex Bennée static const TypeInfo vud_info = { 311*eee77809SAlex Bennée .name = TYPE_VHOST_USER_DEVICE, 312*eee77809SAlex Bennée .parent = TYPE_VHOST_USER_BASE, 313*eee77809SAlex Bennée .instance_size = sizeof(VHostUserBase), 314*eee77809SAlex Bennée .class_init = vud_class_init, 315*eee77809SAlex Bennée .class_size = sizeof(VHostUserBaseClass), 316*eee77809SAlex Bennée }; 317*eee77809SAlex Bennée 318*eee77809SAlex Bennée static void vu_register_types(void) 319*eee77809SAlex Bennée { 320*eee77809SAlex Bennée type_register_static(&vub_info); 321*eee77809SAlex Bennée type_register_static(&vud_info); 322*eee77809SAlex Bennée } 323*eee77809SAlex Bennée 324*eee77809SAlex Bennée type_init(vu_register_types) 325