xref: /qemu/hw/virtio/vhost-user-gpio.c (revision 27ba7b027f0f06479091bcfbcd308a6b272563a4)
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