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