1*27ba7b02SViresh Kumar /* 2*27ba7b02SViresh Kumar * Vhost-user GPIO virtio device 3*27ba7b02SViresh Kumar * 4*27ba7b02SViresh Kumar * Copyright (c) 2022 Viresh Kumar <viresh.kumar@linaro.org> 5*27ba7b02SViresh Kumar * 6*27ba7b02SViresh Kumar * SPDX-License-Identifier: GPL-2.0-or-later 7*27ba7b02SViresh Kumar */ 8*27ba7b02SViresh Kumar 9*27ba7b02SViresh Kumar #include "qemu/osdep.h" 10*27ba7b02SViresh Kumar #include "qapi/error.h" 11*27ba7b02SViresh Kumar #include "hw/qdev-properties.h" 12*27ba7b02SViresh Kumar #include "hw/virtio/virtio-bus.h" 13*27ba7b02SViresh Kumar #include "hw/virtio/vhost-user-gpio.h" 14*27ba7b02SViresh Kumar #include "qemu/error-report.h" 15*27ba7b02SViresh Kumar #include "standard-headers/linux/virtio_ids.h" 16*27ba7b02SViresh Kumar #include "trace.h" 17*27ba7b02SViresh Kumar 18*27ba7b02SViresh Kumar #define REALIZE_CONNECTION_RETRIES 3 19*27ba7b02SViresh Kumar 20*27ba7b02SViresh Kumar /* Features required from VirtIO */ 21*27ba7b02SViresh Kumar static const int feature_bits[] = { 22*27ba7b02SViresh Kumar VIRTIO_F_VERSION_1, 23*27ba7b02SViresh Kumar VIRTIO_F_NOTIFY_ON_EMPTY, 24*27ba7b02SViresh Kumar VIRTIO_RING_F_INDIRECT_DESC, 25*27ba7b02SViresh Kumar VIRTIO_RING_F_EVENT_IDX, 26*27ba7b02SViresh Kumar VIRTIO_GPIO_F_IRQ, 27*27ba7b02SViresh Kumar VHOST_INVALID_FEATURE_BIT 28*27ba7b02SViresh Kumar }; 29*27ba7b02SViresh Kumar 30*27ba7b02SViresh Kumar static void vu_gpio_get_config(VirtIODevice *vdev, uint8_t *config) 31*27ba7b02SViresh Kumar { 32*27ba7b02SViresh Kumar VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); 33*27ba7b02SViresh Kumar 34*27ba7b02SViresh Kumar memcpy(config, &gpio->config, sizeof(gpio->config)); 35*27ba7b02SViresh Kumar } 36*27ba7b02SViresh Kumar 37*27ba7b02SViresh Kumar static int vu_gpio_config_notifier(struct vhost_dev *dev) 38*27ba7b02SViresh Kumar { 39*27ba7b02SViresh Kumar VHostUserGPIO *gpio = VHOST_USER_GPIO(dev->vdev); 40*27ba7b02SViresh Kumar 41*27ba7b02SViresh Kumar memcpy(dev->vdev->config, &gpio->config, sizeof(gpio->config)); 42*27ba7b02SViresh Kumar virtio_notify_config(dev->vdev); 43*27ba7b02SViresh Kumar 44*27ba7b02SViresh Kumar return 0; 45*27ba7b02SViresh Kumar } 46*27ba7b02SViresh Kumar 47*27ba7b02SViresh Kumar const VhostDevConfigOps gpio_ops = { 48*27ba7b02SViresh Kumar .vhost_dev_config_notifier = vu_gpio_config_notifier, 49*27ba7b02SViresh Kumar }; 50*27ba7b02SViresh Kumar 51*27ba7b02SViresh Kumar static int vu_gpio_start(VirtIODevice *vdev) 52*27ba7b02SViresh Kumar { 53*27ba7b02SViresh Kumar BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 54*27ba7b02SViresh Kumar VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 55*27ba7b02SViresh Kumar VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); 56*27ba7b02SViresh Kumar struct vhost_dev *vhost_dev = &gpio->vhost_dev; 57*27ba7b02SViresh Kumar int ret, i; 58*27ba7b02SViresh Kumar 59*27ba7b02SViresh Kumar if (!k->set_guest_notifiers) { 60*27ba7b02SViresh Kumar error_report("binding does not support guest notifiers"); 61*27ba7b02SViresh Kumar return -ENOSYS; 62*27ba7b02SViresh Kumar } 63*27ba7b02SViresh Kumar 64*27ba7b02SViresh Kumar ret = vhost_dev_enable_notifiers(vhost_dev, vdev); 65*27ba7b02SViresh Kumar if (ret < 0) { 66*27ba7b02SViresh Kumar error_report("Error enabling host notifiers: %d", ret); 67*27ba7b02SViresh Kumar return ret; 68*27ba7b02SViresh Kumar } 69*27ba7b02SViresh Kumar 70*27ba7b02SViresh Kumar ret = k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, true); 71*27ba7b02SViresh Kumar if (ret < 0) { 72*27ba7b02SViresh Kumar error_report("Error binding guest notifier: %d", ret); 73*27ba7b02SViresh Kumar goto err_host_notifiers; 74*27ba7b02SViresh Kumar } 75*27ba7b02SViresh Kumar 76*27ba7b02SViresh Kumar /* 77*27ba7b02SViresh Kumar * Before we start up we need to ensure we have the final feature 78*27ba7b02SViresh Kumar * set needed for the vhost configuration. The backend may also 79*27ba7b02SViresh Kumar * apply backend_features when the feature set is sent. 80*27ba7b02SViresh Kumar */ 81*27ba7b02SViresh Kumar vhost_ack_features(&gpio->vhost_dev, feature_bits, vdev->guest_features); 82*27ba7b02SViresh Kumar 83*27ba7b02SViresh Kumar ret = vhost_dev_start(&gpio->vhost_dev, vdev); 84*27ba7b02SViresh Kumar if (ret < 0) { 85*27ba7b02SViresh Kumar error_report("Error starting vhost-user-gpio: %d", ret); 86*27ba7b02SViresh Kumar goto err_guest_notifiers; 87*27ba7b02SViresh Kumar } 88*27ba7b02SViresh Kumar 89*27ba7b02SViresh Kumar /* 90*27ba7b02SViresh Kumar * guest_notifier_mask/pending not used yet, so just unmask 91*27ba7b02SViresh Kumar * everything here. virtio-pci will do the right thing by 92*27ba7b02SViresh Kumar * enabling/disabling irqfd. 93*27ba7b02SViresh Kumar */ 94*27ba7b02SViresh Kumar for (i = 0; i < gpio->vhost_dev.nvqs; i++) { 95*27ba7b02SViresh Kumar vhost_virtqueue_mask(&gpio->vhost_dev, vdev, i, false); 96*27ba7b02SViresh Kumar } 97*27ba7b02SViresh Kumar 98*27ba7b02SViresh Kumar /* 99*27ba7b02SViresh Kumar * As we must have VHOST_USER_F_PROTOCOL_FEATURES (because 100*27ba7b02SViresh Kumar * VHOST_USER_GET_CONFIG requires it) we need to explicitly enable 101*27ba7b02SViresh Kumar * the vrings. 102*27ba7b02SViresh Kumar */ 103*27ba7b02SViresh Kumar g_assert(vhost_dev->vhost_ops && 104*27ba7b02SViresh Kumar vhost_dev->vhost_ops->vhost_set_vring_enable); 105*27ba7b02SViresh Kumar ret = vhost_dev->vhost_ops->vhost_set_vring_enable(vhost_dev, true); 106*27ba7b02SViresh Kumar if (ret == 0) { 107*27ba7b02SViresh Kumar return 0; 108*27ba7b02SViresh Kumar } 109*27ba7b02SViresh Kumar 110*27ba7b02SViresh Kumar error_report("Failed to start vrings for vhost-user-gpio: %d", ret); 111*27ba7b02SViresh Kumar 112*27ba7b02SViresh Kumar err_guest_notifiers: 113*27ba7b02SViresh Kumar k->set_guest_notifiers(qbus->parent, gpio->vhost_dev.nvqs, false); 114*27ba7b02SViresh Kumar err_host_notifiers: 115*27ba7b02SViresh Kumar vhost_dev_disable_notifiers(&gpio->vhost_dev, vdev); 116*27ba7b02SViresh Kumar 117*27ba7b02SViresh Kumar return ret; 118*27ba7b02SViresh Kumar } 119*27ba7b02SViresh Kumar 120*27ba7b02SViresh Kumar static void vu_gpio_stop(VirtIODevice *vdev) 121*27ba7b02SViresh Kumar { 122*27ba7b02SViresh Kumar VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); 123*27ba7b02SViresh Kumar BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); 124*27ba7b02SViresh Kumar VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); 125*27ba7b02SViresh Kumar struct vhost_dev *vhost_dev = &gpio->vhost_dev; 126*27ba7b02SViresh Kumar int ret; 127*27ba7b02SViresh Kumar 128*27ba7b02SViresh Kumar if (!k->set_guest_notifiers) { 129*27ba7b02SViresh Kumar return; 130*27ba7b02SViresh Kumar } 131*27ba7b02SViresh Kumar 132*27ba7b02SViresh Kumar /* 133*27ba7b02SViresh Kumar * We can call vu_gpio_stop multiple times, for example from 134*27ba7b02SViresh Kumar * vm_state_notify and the final object finalisation. Check we 135*27ba7b02SViresh Kumar * aren't already stopped before doing so. 136*27ba7b02SViresh Kumar */ 137*27ba7b02SViresh Kumar if (!vhost_dev_is_started(vhost_dev)) { 138*27ba7b02SViresh Kumar return; 139*27ba7b02SViresh Kumar } 140*27ba7b02SViresh Kumar 141*27ba7b02SViresh Kumar vhost_dev_stop(vhost_dev, vdev); 142*27ba7b02SViresh Kumar 143*27ba7b02SViresh Kumar ret = k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, false); 144*27ba7b02SViresh Kumar if (ret < 0) { 145*27ba7b02SViresh Kumar error_report("vhost guest notifier cleanup failed: %d", ret); 146*27ba7b02SViresh Kumar return; 147*27ba7b02SViresh Kumar } 148*27ba7b02SViresh Kumar 149*27ba7b02SViresh Kumar vhost_dev_disable_notifiers(vhost_dev, vdev); 150*27ba7b02SViresh Kumar } 151*27ba7b02SViresh Kumar 152*27ba7b02SViresh Kumar static void vu_gpio_set_status(VirtIODevice *vdev, uint8_t status) 153*27ba7b02SViresh Kumar { 154*27ba7b02SViresh Kumar VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); 155*27ba7b02SViresh Kumar bool should_start = virtio_device_started(vdev, status); 156*27ba7b02SViresh Kumar 157*27ba7b02SViresh Kumar trace_virtio_gpio_set_status(status); 158*27ba7b02SViresh Kumar 159*27ba7b02SViresh Kumar if (!gpio->connected) { 160*27ba7b02SViresh Kumar return; 161*27ba7b02SViresh Kumar } 162*27ba7b02SViresh Kumar 163*27ba7b02SViresh Kumar if (vhost_dev_is_started(&gpio->vhost_dev) == should_start) { 164*27ba7b02SViresh Kumar return; 165*27ba7b02SViresh Kumar } 166*27ba7b02SViresh Kumar 167*27ba7b02SViresh Kumar if (should_start) { 168*27ba7b02SViresh Kumar if (vu_gpio_start(vdev)) { 169*27ba7b02SViresh Kumar qemu_chr_fe_disconnect(&gpio->chardev); 170*27ba7b02SViresh Kumar } 171*27ba7b02SViresh Kumar } else { 172*27ba7b02SViresh Kumar vu_gpio_stop(vdev); 173*27ba7b02SViresh Kumar } 174*27ba7b02SViresh Kumar } 175*27ba7b02SViresh Kumar 176*27ba7b02SViresh Kumar static uint64_t vu_gpio_get_features(VirtIODevice *vdev, uint64_t features, 177*27ba7b02SViresh Kumar Error **errp) 178*27ba7b02SViresh Kumar { 179*27ba7b02SViresh Kumar VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); 180*27ba7b02SViresh Kumar 181*27ba7b02SViresh Kumar return vhost_get_features(&gpio->vhost_dev, feature_bits, features); 182*27ba7b02SViresh Kumar } 183*27ba7b02SViresh Kumar 184*27ba7b02SViresh Kumar static void vu_gpio_handle_output(VirtIODevice *vdev, VirtQueue *vq) 185*27ba7b02SViresh Kumar { 186*27ba7b02SViresh Kumar /* 187*27ba7b02SViresh Kumar * Not normally called; it's the daemon that handles the queue; 188*27ba7b02SViresh Kumar * however virtio's cleanup path can call this. 189*27ba7b02SViresh Kumar */ 190*27ba7b02SViresh Kumar } 191*27ba7b02SViresh Kumar 192*27ba7b02SViresh Kumar static void vu_gpio_guest_notifier_mask(VirtIODevice *vdev, int idx, bool mask) 193*27ba7b02SViresh Kumar { 194*27ba7b02SViresh Kumar VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); 195*27ba7b02SViresh Kumar 196*27ba7b02SViresh Kumar vhost_virtqueue_mask(&gpio->vhost_dev, vdev, idx, mask); 197*27ba7b02SViresh Kumar } 198*27ba7b02SViresh Kumar 199*27ba7b02SViresh Kumar static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserGPIO *gpio) 200*27ba7b02SViresh Kumar { 201*27ba7b02SViresh Kumar virtio_delete_queue(gpio->command_vq); 202*27ba7b02SViresh Kumar virtio_delete_queue(gpio->interrupt_vq); 203*27ba7b02SViresh Kumar g_free(gpio->vhost_dev.vqs); 204*27ba7b02SViresh Kumar gpio->vhost_dev.vqs = NULL; 205*27ba7b02SViresh Kumar virtio_cleanup(vdev); 206*27ba7b02SViresh Kumar vhost_user_cleanup(&gpio->vhost_user); 207*27ba7b02SViresh Kumar } 208*27ba7b02SViresh Kumar 209*27ba7b02SViresh Kumar static int vu_gpio_connect(DeviceState *dev, Error **errp) 210*27ba7b02SViresh Kumar { 211*27ba7b02SViresh Kumar VirtIODevice *vdev = VIRTIO_DEVICE(dev); 212*27ba7b02SViresh Kumar VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); 213*27ba7b02SViresh Kumar struct vhost_dev *vhost_dev = &gpio->vhost_dev; 214*27ba7b02SViresh Kumar int ret; 215*27ba7b02SViresh Kumar 216*27ba7b02SViresh Kumar if (gpio->connected) { 217*27ba7b02SViresh Kumar return 0; 218*27ba7b02SViresh Kumar } 219*27ba7b02SViresh Kumar gpio->connected = true; 220*27ba7b02SViresh Kumar 221*27ba7b02SViresh Kumar vhost_dev_set_config_notifier(vhost_dev, &gpio_ops); 222*27ba7b02SViresh Kumar gpio->vhost_user.supports_config = true; 223*27ba7b02SViresh Kumar 224*27ba7b02SViresh Kumar ret = vhost_dev_init(vhost_dev, &gpio->vhost_user, 225*27ba7b02SViresh Kumar VHOST_BACKEND_TYPE_USER, 0, errp); 226*27ba7b02SViresh Kumar if (ret < 0) { 227*27ba7b02SViresh Kumar return ret; 228*27ba7b02SViresh Kumar } 229*27ba7b02SViresh Kumar 230*27ba7b02SViresh Kumar /* restore vhost state */ 231*27ba7b02SViresh Kumar if (virtio_device_started(vdev, vdev->status)) { 232*27ba7b02SViresh Kumar vu_gpio_start(vdev); 233*27ba7b02SViresh Kumar } 234*27ba7b02SViresh Kumar 235*27ba7b02SViresh Kumar return 0; 236*27ba7b02SViresh Kumar } 237*27ba7b02SViresh Kumar 238*27ba7b02SViresh Kumar static void vu_gpio_disconnect(DeviceState *dev) 239*27ba7b02SViresh Kumar { 240*27ba7b02SViresh Kumar VirtIODevice *vdev = VIRTIO_DEVICE(dev); 241*27ba7b02SViresh Kumar VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); 242*27ba7b02SViresh Kumar 243*27ba7b02SViresh Kumar if (!gpio->connected) { 244*27ba7b02SViresh Kumar return; 245*27ba7b02SViresh Kumar } 246*27ba7b02SViresh Kumar gpio->connected = false; 247*27ba7b02SViresh Kumar 248*27ba7b02SViresh Kumar vu_gpio_stop(vdev); 249*27ba7b02SViresh Kumar vhost_dev_cleanup(&gpio->vhost_dev); 250*27ba7b02SViresh Kumar } 251*27ba7b02SViresh Kumar 252*27ba7b02SViresh Kumar static void vu_gpio_event(void *opaque, QEMUChrEvent event) 253*27ba7b02SViresh Kumar { 254*27ba7b02SViresh Kumar DeviceState *dev = opaque; 255*27ba7b02SViresh Kumar VirtIODevice *vdev = VIRTIO_DEVICE(dev); 256*27ba7b02SViresh Kumar VHostUserGPIO *gpio = VHOST_USER_GPIO(vdev); 257*27ba7b02SViresh Kumar Error *local_err = NULL; 258*27ba7b02SViresh Kumar 259*27ba7b02SViresh Kumar switch (event) { 260*27ba7b02SViresh Kumar case CHR_EVENT_OPENED: 261*27ba7b02SViresh Kumar if (vu_gpio_connect(dev, &local_err) < 0) { 262*27ba7b02SViresh Kumar qemu_chr_fe_disconnect(&gpio->chardev); 263*27ba7b02SViresh Kumar return; 264*27ba7b02SViresh Kumar } 265*27ba7b02SViresh Kumar break; 266*27ba7b02SViresh Kumar case CHR_EVENT_CLOSED: 267*27ba7b02SViresh Kumar vu_gpio_disconnect(dev); 268*27ba7b02SViresh Kumar break; 269*27ba7b02SViresh Kumar case CHR_EVENT_BREAK: 270*27ba7b02SViresh Kumar case CHR_EVENT_MUX_IN: 271*27ba7b02SViresh Kumar case CHR_EVENT_MUX_OUT: 272*27ba7b02SViresh Kumar /* Ignore */ 273*27ba7b02SViresh Kumar break; 274*27ba7b02SViresh Kumar } 275*27ba7b02SViresh Kumar } 276*27ba7b02SViresh Kumar 277*27ba7b02SViresh Kumar static int vu_gpio_realize_connect(VHostUserGPIO *gpio, Error **errp) 278*27ba7b02SViresh Kumar { 279*27ba7b02SViresh Kumar VirtIODevice *vdev = &gpio->parent_obj; 280*27ba7b02SViresh Kumar DeviceState *dev = &vdev->parent_obj; 281*27ba7b02SViresh Kumar struct vhost_dev *vhost_dev = &gpio->vhost_dev; 282*27ba7b02SViresh Kumar int ret; 283*27ba7b02SViresh Kumar 284*27ba7b02SViresh Kumar ret = qemu_chr_fe_wait_connected(&gpio->chardev, errp); 285*27ba7b02SViresh Kumar if (ret < 0) { 286*27ba7b02SViresh Kumar return ret; 287*27ba7b02SViresh Kumar } 288*27ba7b02SViresh Kumar 289*27ba7b02SViresh Kumar /* 290*27ba7b02SViresh Kumar * vu_gpio_connect() may have already connected (via the event 291*27ba7b02SViresh Kumar * callback) in which case it will just report success. 292*27ba7b02SViresh Kumar */ 293*27ba7b02SViresh Kumar ret = vu_gpio_connect(dev, errp); 294*27ba7b02SViresh Kumar if (ret < 0) { 295*27ba7b02SViresh Kumar qemu_chr_fe_disconnect(&gpio->chardev); 296*27ba7b02SViresh Kumar return ret; 297*27ba7b02SViresh Kumar } 298*27ba7b02SViresh Kumar g_assert(gpio->connected); 299*27ba7b02SViresh Kumar 300*27ba7b02SViresh Kumar ret = vhost_dev_get_config(vhost_dev, (uint8_t *)&gpio->config, 301*27ba7b02SViresh Kumar sizeof(gpio->config), errp); 302*27ba7b02SViresh Kumar 303*27ba7b02SViresh Kumar if (ret < 0) { 304*27ba7b02SViresh Kumar error_report("vhost-user-gpio: get config failed"); 305*27ba7b02SViresh Kumar 306*27ba7b02SViresh Kumar qemu_chr_fe_disconnect(&gpio->chardev); 307*27ba7b02SViresh Kumar vhost_dev_cleanup(vhost_dev); 308*27ba7b02SViresh Kumar return ret; 309*27ba7b02SViresh Kumar } 310*27ba7b02SViresh Kumar 311*27ba7b02SViresh Kumar return 0; 312*27ba7b02SViresh Kumar } 313*27ba7b02SViresh Kumar 314*27ba7b02SViresh Kumar static void vu_gpio_device_realize(DeviceState *dev, Error **errp) 315*27ba7b02SViresh Kumar { 316*27ba7b02SViresh Kumar ERRP_GUARD(); 317*27ba7b02SViresh Kumar 318*27ba7b02SViresh Kumar VirtIODevice *vdev = VIRTIO_DEVICE(dev); 319*27ba7b02SViresh Kumar VHostUserGPIO *gpio = VHOST_USER_GPIO(dev); 320*27ba7b02SViresh Kumar int retries, ret; 321*27ba7b02SViresh Kumar 322*27ba7b02SViresh Kumar if (!gpio->chardev.chr) { 323*27ba7b02SViresh Kumar error_setg(errp, "vhost-user-gpio: chardev is mandatory"); 324*27ba7b02SViresh Kumar return; 325*27ba7b02SViresh Kumar } 326*27ba7b02SViresh Kumar 327*27ba7b02SViresh Kumar if (!vhost_user_init(&gpio->vhost_user, &gpio->chardev, errp)) { 328*27ba7b02SViresh Kumar return; 329*27ba7b02SViresh Kumar } 330*27ba7b02SViresh Kumar 331*27ba7b02SViresh Kumar virtio_init(vdev, VIRTIO_ID_GPIO, sizeof(gpio->config)); 332*27ba7b02SViresh Kumar 333*27ba7b02SViresh Kumar gpio->vhost_dev.nvqs = 2; 334*27ba7b02SViresh Kumar gpio->command_vq = virtio_add_queue(vdev, 256, vu_gpio_handle_output); 335*27ba7b02SViresh Kumar gpio->interrupt_vq = virtio_add_queue(vdev, 256, vu_gpio_handle_output); 336*27ba7b02SViresh Kumar gpio->vhost_dev.vqs = g_new0(struct vhost_virtqueue, gpio->vhost_dev.nvqs); 337*27ba7b02SViresh Kumar 338*27ba7b02SViresh Kumar gpio->connected = false; 339*27ba7b02SViresh Kumar 340*27ba7b02SViresh Kumar qemu_chr_fe_set_handlers(&gpio->chardev, NULL, NULL, vu_gpio_event, NULL, 341*27ba7b02SViresh Kumar dev, NULL, true); 342*27ba7b02SViresh Kumar 343*27ba7b02SViresh Kumar retries = REALIZE_CONNECTION_RETRIES; 344*27ba7b02SViresh Kumar g_assert(!*errp); 345*27ba7b02SViresh Kumar do { 346*27ba7b02SViresh Kumar if (*errp) { 347*27ba7b02SViresh Kumar error_prepend(errp, "Reconnecting after error: "); 348*27ba7b02SViresh Kumar error_report_err(*errp); 349*27ba7b02SViresh Kumar *errp = NULL; 350*27ba7b02SViresh Kumar } 351*27ba7b02SViresh Kumar ret = vu_gpio_realize_connect(gpio, errp); 352*27ba7b02SViresh Kumar } while (ret < 0 && retries--); 353*27ba7b02SViresh Kumar 354*27ba7b02SViresh Kumar if (ret < 0) { 355*27ba7b02SViresh Kumar do_vhost_user_cleanup(vdev, gpio); 356*27ba7b02SViresh Kumar } 357*27ba7b02SViresh Kumar 358*27ba7b02SViresh Kumar return; 359*27ba7b02SViresh Kumar } 360*27ba7b02SViresh Kumar 361*27ba7b02SViresh Kumar static void vu_gpio_device_unrealize(DeviceState *dev) 362*27ba7b02SViresh Kumar { 363*27ba7b02SViresh Kumar VirtIODevice *vdev = VIRTIO_DEVICE(dev); 364*27ba7b02SViresh Kumar VHostUserGPIO *gpio = VHOST_USER_GPIO(dev); 365*27ba7b02SViresh Kumar 366*27ba7b02SViresh Kumar vu_gpio_set_status(vdev, 0); 367*27ba7b02SViresh Kumar qemu_chr_fe_set_handlers(&gpio->chardev, NULL, NULL, NULL, NULL, NULL, NULL, 368*27ba7b02SViresh Kumar false); 369*27ba7b02SViresh Kumar vhost_dev_cleanup(&gpio->vhost_dev); 370*27ba7b02SViresh Kumar do_vhost_user_cleanup(vdev, gpio); 371*27ba7b02SViresh Kumar } 372*27ba7b02SViresh Kumar 373*27ba7b02SViresh Kumar static const VMStateDescription vu_gpio_vmstate = { 374*27ba7b02SViresh Kumar .name = "vhost-user-gpio", 375*27ba7b02SViresh Kumar .unmigratable = 1, 376*27ba7b02SViresh Kumar }; 377*27ba7b02SViresh Kumar 378*27ba7b02SViresh Kumar static Property vu_gpio_properties[] = { 379*27ba7b02SViresh Kumar DEFINE_PROP_CHR("chardev", VHostUserGPIO, chardev), 380*27ba7b02SViresh Kumar DEFINE_PROP_END_OF_LIST(), 381*27ba7b02SViresh Kumar }; 382*27ba7b02SViresh Kumar 383*27ba7b02SViresh Kumar static void vu_gpio_class_init(ObjectClass *klass, void *data) 384*27ba7b02SViresh Kumar { 385*27ba7b02SViresh Kumar DeviceClass *dc = DEVICE_CLASS(klass); 386*27ba7b02SViresh Kumar VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); 387*27ba7b02SViresh Kumar 388*27ba7b02SViresh Kumar device_class_set_props(dc, vu_gpio_properties); 389*27ba7b02SViresh Kumar dc->vmsd = &vu_gpio_vmstate; 390*27ba7b02SViresh Kumar set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 391*27ba7b02SViresh Kumar vdc->realize = vu_gpio_device_realize; 392*27ba7b02SViresh Kumar vdc->unrealize = vu_gpio_device_unrealize; 393*27ba7b02SViresh Kumar vdc->get_features = vu_gpio_get_features; 394*27ba7b02SViresh Kumar vdc->get_config = vu_gpio_get_config; 395*27ba7b02SViresh Kumar vdc->set_status = vu_gpio_set_status; 396*27ba7b02SViresh Kumar vdc->guest_notifier_mask = vu_gpio_guest_notifier_mask; 397*27ba7b02SViresh Kumar } 398*27ba7b02SViresh Kumar 399*27ba7b02SViresh Kumar static const TypeInfo vu_gpio_info = { 400*27ba7b02SViresh Kumar .name = TYPE_VHOST_USER_GPIO, 401*27ba7b02SViresh Kumar .parent = TYPE_VIRTIO_DEVICE, 402*27ba7b02SViresh Kumar .instance_size = sizeof(VHostUserGPIO), 403*27ba7b02SViresh Kumar .class_init = vu_gpio_class_init, 404*27ba7b02SViresh Kumar }; 405*27ba7b02SViresh Kumar 406*27ba7b02SViresh Kumar static void vu_gpio_register_types(void) 407*27ba7b02SViresh Kumar { 408*27ba7b02SViresh Kumar type_register_static(&vu_gpio_info); 409*27ba7b02SViresh Kumar } 410*27ba7b02SViresh Kumar 411*27ba7b02SViresh Kumar type_init(vu_gpio_register_types) 412