xref: /openbmc/qemu/hw/virtio/vdpa-dev.c (revision bc0cd4ae881dff47e81581a8fea93a50b1d1dbe7)
1b430a2bdSLongpeng /*
2b430a2bdSLongpeng  * Vhost Vdpa Device
3b430a2bdSLongpeng  *
4b430a2bdSLongpeng  * Copyright (c) Huawei Technologies Co., Ltd. 2022. All Rights Reserved.
5b430a2bdSLongpeng  *
6b430a2bdSLongpeng  * Authors:
7b430a2bdSLongpeng  *   Longpeng <longpeng2@huawei.com>
8b430a2bdSLongpeng  *
9b430a2bdSLongpeng  * Largely based on the "vhost-user-blk-pci.c" and "vhost-user-blk.c"
10b430a2bdSLongpeng  * implemented by:
11b430a2bdSLongpeng  *   Changpeng Liu <changpeng.liu@intel.com>
12b430a2bdSLongpeng  *
13b430a2bdSLongpeng  * This work is licensed under the terms of the GNU LGPL, version 2 or later.
14b430a2bdSLongpeng  * See the COPYING.LIB file in the top-level directory.
15b430a2bdSLongpeng  */
16b430a2bdSLongpeng #include "qemu/osdep.h"
17b430a2bdSLongpeng #include <sys/ioctl.h>
18b430a2bdSLongpeng #include <linux/vhost.h>
19b430a2bdSLongpeng #include "qapi/error.h"
20b430a2bdSLongpeng #include "qemu/error-report.h"
21b430a2bdSLongpeng #include "qemu/cutils.h"
22b430a2bdSLongpeng #include "hw/qdev-core.h"
23b430a2bdSLongpeng #include "hw/qdev-properties.h"
24b430a2bdSLongpeng #include "hw/qdev-properties-system.h"
25b430a2bdSLongpeng #include "hw/virtio/vhost.h"
26b430a2bdSLongpeng #include "hw/virtio/virtio.h"
27b430a2bdSLongpeng #include "hw/virtio/virtio-bus.h"
28b430a2bdSLongpeng #include "hw/virtio/vdpa-dev.h"
29b430a2bdSLongpeng #include "sysemu/sysemu.h"
30b430a2bdSLongpeng #include "sysemu/runstate.h"
31b430a2bdSLongpeng 
32b430a2bdSLongpeng static void
vhost_vdpa_device_dummy_handle_output(VirtIODevice * vdev,VirtQueue * vq)33b430a2bdSLongpeng vhost_vdpa_device_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq)
34b430a2bdSLongpeng {
35b430a2bdSLongpeng     /* Nothing to do */
36b430a2bdSLongpeng }
37b430a2bdSLongpeng 
38b430a2bdSLongpeng static uint32_t
vhost_vdpa_device_get_u32(int fd,unsigned long int cmd,Error ** errp)39b430a2bdSLongpeng vhost_vdpa_device_get_u32(int fd, unsigned long int cmd, Error **errp)
40b430a2bdSLongpeng {
41b430a2bdSLongpeng     uint32_t val = (uint32_t)-1;
42b430a2bdSLongpeng 
43b430a2bdSLongpeng     if (ioctl(fd, cmd, &val) < 0) {
44b430a2bdSLongpeng         error_setg(errp, "vhost-vdpa-device: cmd 0x%lx failed: %s",
45b430a2bdSLongpeng                    cmd, strerror(errno));
46b430a2bdSLongpeng     }
47b430a2bdSLongpeng 
48b430a2bdSLongpeng     return val;
49b430a2bdSLongpeng }
50b430a2bdSLongpeng 
vhost_vdpa_device_realize(DeviceState * dev,Error ** errp)51b430a2bdSLongpeng static void vhost_vdpa_device_realize(DeviceState *dev, Error **errp)
52b430a2bdSLongpeng {
53b430a2bdSLongpeng     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
54b430a2bdSLongpeng     VhostVdpaDevice *v = VHOST_VDPA_DEVICE(vdev);
55c672f348SLongpeng     struct vhost_vdpa_iova_range iova_range;
56b430a2bdSLongpeng     uint16_t max_queue_size;
57b430a2bdSLongpeng     struct vhost_virtqueue *vqs;
58b430a2bdSLongpeng     int i, ret;
59b430a2bdSLongpeng 
60b430a2bdSLongpeng     if (!v->vhostdev) {
61b430a2bdSLongpeng         error_setg(errp, "vhost-vdpa-device: vhostdev are missing");
62b430a2bdSLongpeng         return;
63b430a2bdSLongpeng     }
64b430a2bdSLongpeng 
65b430a2bdSLongpeng     v->vhostfd = qemu_open(v->vhostdev, O_RDWR, errp);
66b430a2bdSLongpeng     if (*errp) {
67b430a2bdSLongpeng         return;
68b430a2bdSLongpeng     }
69b430a2bdSLongpeng 
70b430a2bdSLongpeng     v->vdev_id = vhost_vdpa_device_get_u32(v->vhostfd,
71b430a2bdSLongpeng                                            VHOST_VDPA_GET_DEVICE_ID, errp);
72b430a2bdSLongpeng     if (*errp) {
73b430a2bdSLongpeng         goto out;
74b430a2bdSLongpeng     }
75b430a2bdSLongpeng 
76b430a2bdSLongpeng     max_queue_size = vhost_vdpa_device_get_u32(v->vhostfd,
77b430a2bdSLongpeng                                                VHOST_VDPA_GET_VRING_NUM, errp);
78b430a2bdSLongpeng     if (*errp) {
79b430a2bdSLongpeng         goto out;
80b430a2bdSLongpeng     }
81b430a2bdSLongpeng 
82b430a2bdSLongpeng     if (v->queue_size > max_queue_size) {
83b430a2bdSLongpeng         error_setg(errp, "vhost-vdpa-device: invalid queue_size: %u (max:%u)",
84b430a2bdSLongpeng                    v->queue_size, max_queue_size);
85b430a2bdSLongpeng         goto out;
86b430a2bdSLongpeng     } else if (!v->queue_size) {
87b430a2bdSLongpeng         v->queue_size = max_queue_size;
88b430a2bdSLongpeng     }
89b430a2bdSLongpeng 
90b430a2bdSLongpeng     v->num_queues = vhost_vdpa_device_get_u32(v->vhostfd,
91b430a2bdSLongpeng                                               VHOST_VDPA_GET_VQS_COUNT, errp);
92b430a2bdSLongpeng     if (*errp) {
93b430a2bdSLongpeng         goto out;
94b430a2bdSLongpeng     }
95b430a2bdSLongpeng 
96b430a2bdSLongpeng     if (!v->num_queues || v->num_queues > VIRTIO_QUEUE_MAX) {
97b430a2bdSLongpeng         error_setg(errp, "invalid number of virtqueues: %u (max:%u)",
98b430a2bdSLongpeng                    v->num_queues, VIRTIO_QUEUE_MAX);
99b430a2bdSLongpeng         goto out;
100b430a2bdSLongpeng     }
101b430a2bdSLongpeng 
102b430a2bdSLongpeng     v->dev.nvqs = v->num_queues;
103b430a2bdSLongpeng     vqs = g_new0(struct vhost_virtqueue, v->dev.nvqs);
104b430a2bdSLongpeng     v->dev.vqs = vqs;
105b430a2bdSLongpeng     v->dev.vq_index = 0;
106b430a2bdSLongpeng     v->dev.vq_index_end = v->dev.nvqs;
107b430a2bdSLongpeng     v->dev.backend_features = 0;
108b430a2bdSLongpeng     v->started = false;
109b430a2bdSLongpeng 
110c672f348SLongpeng     ret = vhost_vdpa_get_iova_range(v->vhostfd, &iova_range);
111c672f348SLongpeng     if (ret < 0) {
112c672f348SLongpeng         error_setg(errp, "vhost-vdpa-device: get iova range failed: %s",
113c672f348SLongpeng                    strerror(-ret));
114c672f348SLongpeng         goto free_vqs;
115c672f348SLongpeng     }
116ae25ff41SEugenio Pérez     v->vdpa.shared = g_new0(VhostVDPAShared, 1);
117f12b2498SEugenio Pérez     v->vdpa.shared->device_fd = v->vhostfd;
118ae25ff41SEugenio Pérez     v->vdpa.shared->iova_range = iova_range;
119c672f348SLongpeng 
120b430a2bdSLongpeng     ret = vhost_dev_init(&v->dev, &v->vdpa, VHOST_BACKEND_TYPE_VDPA, 0, NULL);
121b430a2bdSLongpeng     if (ret < 0) {
122b430a2bdSLongpeng         error_setg(errp, "vhost-vdpa-device: vhost initialization failed: %s",
123b430a2bdSLongpeng                    strerror(-ret));
124b430a2bdSLongpeng         goto free_vqs;
125b430a2bdSLongpeng     }
126b430a2bdSLongpeng 
127b430a2bdSLongpeng     v->config_size = vhost_vdpa_device_get_u32(v->vhostfd,
128b430a2bdSLongpeng                                                VHOST_VDPA_GET_CONFIG_SIZE,
129b430a2bdSLongpeng                                                errp);
130b430a2bdSLongpeng     if (*errp) {
131b430a2bdSLongpeng         goto vhost_cleanup;
132b430a2bdSLongpeng     }
133b430a2bdSLongpeng 
134b430a2bdSLongpeng     /*
135b430a2bdSLongpeng      * Invoke .post_init() to initialize the transport-specific fields
136b430a2bdSLongpeng      * before calling virtio_init().
137b430a2bdSLongpeng      */
138b430a2bdSLongpeng     if (v->post_init && v->post_init(v, errp) < 0) {
139b430a2bdSLongpeng         goto vhost_cleanup;
140b430a2bdSLongpeng     }
141b430a2bdSLongpeng 
142b430a2bdSLongpeng     v->config = g_malloc0(v->config_size);
143b430a2bdSLongpeng 
144b430a2bdSLongpeng     ret = vhost_dev_get_config(&v->dev, v->config, v->config_size, NULL);
145b430a2bdSLongpeng     if (ret < 0) {
146b430a2bdSLongpeng         error_setg(errp, "vhost-vdpa-device: get config failed");
147b430a2bdSLongpeng         goto free_config;
148b430a2bdSLongpeng     }
149b430a2bdSLongpeng 
150b430a2bdSLongpeng     virtio_init(vdev, v->vdev_id, v->config_size);
151b430a2bdSLongpeng 
152b430a2bdSLongpeng     v->virtqs = g_new0(VirtQueue *, v->dev.nvqs);
153b430a2bdSLongpeng     for (i = 0; i < v->dev.nvqs; i++) {
154b430a2bdSLongpeng         v->virtqs[i] = virtio_add_queue(vdev, v->queue_size,
155b430a2bdSLongpeng                                         vhost_vdpa_device_dummy_handle_output);
156b430a2bdSLongpeng     }
157b430a2bdSLongpeng 
158b430a2bdSLongpeng     return;
159b430a2bdSLongpeng 
160b430a2bdSLongpeng free_config:
161b430a2bdSLongpeng     g_free(v->config);
162b430a2bdSLongpeng vhost_cleanup:
163b430a2bdSLongpeng     vhost_dev_cleanup(&v->dev);
164b430a2bdSLongpeng free_vqs:
165b430a2bdSLongpeng     g_free(vqs);
166ae25ff41SEugenio Pérez     g_free(v->vdpa.shared);
167b430a2bdSLongpeng out:
168b430a2bdSLongpeng     qemu_close(v->vhostfd);
169b430a2bdSLongpeng     v->vhostfd = -1;
170b430a2bdSLongpeng }
171b430a2bdSLongpeng 
vhost_vdpa_device_unrealize(DeviceState * dev)172b430a2bdSLongpeng static void vhost_vdpa_device_unrealize(DeviceState *dev)
173b430a2bdSLongpeng {
174b430a2bdSLongpeng     VirtIODevice *vdev = VIRTIO_DEVICE(dev);
175b430a2bdSLongpeng     VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev);
176b430a2bdSLongpeng     int i;
177b430a2bdSLongpeng 
178b430a2bdSLongpeng     virtio_set_status(vdev, 0);
179b430a2bdSLongpeng 
180b430a2bdSLongpeng     for (i = 0; i < s->num_queues; i++) {
181b430a2bdSLongpeng         virtio_delete_queue(s->virtqs[i]);
182b430a2bdSLongpeng     }
183b430a2bdSLongpeng     g_free(s->virtqs);
184b430a2bdSLongpeng     virtio_cleanup(vdev);
185b430a2bdSLongpeng 
186b430a2bdSLongpeng     g_free(s->config);
187b430a2bdSLongpeng     g_free(s->dev.vqs);
188b430a2bdSLongpeng     vhost_dev_cleanup(&s->dev);
189ae25ff41SEugenio Pérez     g_free(s->vdpa.shared);
190b430a2bdSLongpeng     qemu_close(s->vhostfd);
191b430a2bdSLongpeng     s->vhostfd = -1;
192b430a2bdSLongpeng }
193b430a2bdSLongpeng 
194b430a2bdSLongpeng static void
vhost_vdpa_device_get_config(VirtIODevice * vdev,uint8_t * config)195b430a2bdSLongpeng vhost_vdpa_device_get_config(VirtIODevice *vdev, uint8_t *config)
196b430a2bdSLongpeng {
197b430a2bdSLongpeng     VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev);
198*6ae72f60Slyx634449800     int ret;
199b430a2bdSLongpeng 
200*6ae72f60Slyx634449800     ret = vhost_dev_get_config(&s->dev, s->config, s->config_size,
201*6ae72f60Slyx634449800                             NULL);
202*6ae72f60Slyx634449800     if (ret < 0) {
203*6ae72f60Slyx634449800         error_report("get device config space failed");
204*6ae72f60Slyx634449800         return;
205*6ae72f60Slyx634449800     }
206b430a2bdSLongpeng     memcpy(config, s->config, s->config_size);
207b430a2bdSLongpeng }
208b430a2bdSLongpeng 
209b430a2bdSLongpeng static void
vhost_vdpa_device_set_config(VirtIODevice * vdev,const uint8_t * config)210b430a2bdSLongpeng vhost_vdpa_device_set_config(VirtIODevice *vdev, const uint8_t *config)
211b430a2bdSLongpeng {
212b430a2bdSLongpeng     VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev);
213b430a2bdSLongpeng     int ret;
214b430a2bdSLongpeng 
215b430a2bdSLongpeng     ret = vhost_dev_set_config(&s->dev, s->config, 0, s->config_size,
216f8ed3648SManos Pitsidianakis                                VHOST_SET_CONFIG_TYPE_FRONTEND);
217b430a2bdSLongpeng     if (ret) {
218b430a2bdSLongpeng         error_report("set device config space failed");
219b430a2bdSLongpeng         return;
220b430a2bdSLongpeng     }
221b430a2bdSLongpeng }
222b430a2bdSLongpeng 
vhost_vdpa_device_get_features(VirtIODevice * vdev,uint64_t features,Error ** errp)223b430a2bdSLongpeng static uint64_t vhost_vdpa_device_get_features(VirtIODevice *vdev,
224b430a2bdSLongpeng                                                uint64_t features,
225b430a2bdSLongpeng                                                Error **errp)
226b430a2bdSLongpeng {
227b430a2bdSLongpeng     VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev);
228b430a2bdSLongpeng     uint64_t backend_features = s->dev.features;
229b430a2bdSLongpeng 
230b430a2bdSLongpeng     if (!virtio_has_feature(features, VIRTIO_F_IOMMU_PLATFORM)) {
231b430a2bdSLongpeng         virtio_clear_feature(&backend_features, VIRTIO_F_IOMMU_PLATFORM);
232b430a2bdSLongpeng     }
233b430a2bdSLongpeng 
234b430a2bdSLongpeng     return backend_features;
235b430a2bdSLongpeng }
236b430a2bdSLongpeng 
vhost_vdpa_device_start(VirtIODevice * vdev,Error ** errp)237b430a2bdSLongpeng static int vhost_vdpa_device_start(VirtIODevice *vdev, Error **errp)
238b430a2bdSLongpeng {
239b430a2bdSLongpeng     VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev);
240b430a2bdSLongpeng     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
241b430a2bdSLongpeng     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
242b430a2bdSLongpeng     int i, ret;
243b430a2bdSLongpeng 
244b430a2bdSLongpeng     if (!k->set_guest_notifiers) {
245b430a2bdSLongpeng         error_setg(errp, "binding does not support guest notifiers");
246b430a2bdSLongpeng         return -ENOSYS;
247b430a2bdSLongpeng     }
248b430a2bdSLongpeng 
249b430a2bdSLongpeng     ret = vhost_dev_enable_notifiers(&s->dev, vdev);
250b430a2bdSLongpeng     if (ret < 0) {
251b430a2bdSLongpeng         error_setg_errno(errp, -ret, "Error enabling host notifiers");
252b430a2bdSLongpeng         return ret;
253b430a2bdSLongpeng     }
254b430a2bdSLongpeng 
255b430a2bdSLongpeng     ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, true);
256b430a2bdSLongpeng     if (ret < 0) {
257b430a2bdSLongpeng         error_setg_errno(errp, -ret, "Error binding guest notifier");
258b430a2bdSLongpeng         goto err_host_notifiers;
259b430a2bdSLongpeng     }
260b430a2bdSLongpeng 
261b430a2bdSLongpeng     s->dev.acked_features = vdev->guest_features;
262b430a2bdSLongpeng 
2632c66de61SKevin Wolf     ret = vhost_dev_start(&s->dev, vdev, true);
264b430a2bdSLongpeng     if (ret < 0) {
265b430a2bdSLongpeng         error_setg_errno(errp, -ret, "Error starting vhost");
266b430a2bdSLongpeng         goto err_guest_notifiers;
267b430a2bdSLongpeng     }
268b430a2bdSLongpeng     s->started = true;
269b430a2bdSLongpeng 
270b430a2bdSLongpeng     /*
271b430a2bdSLongpeng      * guest_notifier_mask/pending not used yet, so just unmask
272b430a2bdSLongpeng      * everything here. virtio-pci will do the right thing by
273b430a2bdSLongpeng      * enabling/disabling irqfd.
274b430a2bdSLongpeng      */
275b430a2bdSLongpeng     for (i = 0; i < s->dev.nvqs; i++) {
276b430a2bdSLongpeng         vhost_virtqueue_mask(&s->dev, vdev, i, false);
277b430a2bdSLongpeng     }
278b430a2bdSLongpeng 
279b430a2bdSLongpeng     return ret;
280b430a2bdSLongpeng 
281b430a2bdSLongpeng err_guest_notifiers:
282b430a2bdSLongpeng     k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
283b430a2bdSLongpeng err_host_notifiers:
284b430a2bdSLongpeng     vhost_dev_disable_notifiers(&s->dev, vdev);
285b430a2bdSLongpeng     return ret;
286b430a2bdSLongpeng }
287b430a2bdSLongpeng 
vhost_vdpa_device_stop(VirtIODevice * vdev)288b430a2bdSLongpeng static void vhost_vdpa_device_stop(VirtIODevice *vdev)
289b430a2bdSLongpeng {
290b430a2bdSLongpeng     VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev);
291b430a2bdSLongpeng     BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
292b430a2bdSLongpeng     VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
293b430a2bdSLongpeng     int ret;
294b430a2bdSLongpeng 
295b430a2bdSLongpeng     if (!s->started) {
296b430a2bdSLongpeng         return;
297b430a2bdSLongpeng     }
298b430a2bdSLongpeng     s->started = false;
299b430a2bdSLongpeng 
300b430a2bdSLongpeng     if (!k->set_guest_notifiers) {
301b430a2bdSLongpeng         return;
302b430a2bdSLongpeng     }
303b430a2bdSLongpeng 
304b430a2bdSLongpeng     vhost_dev_stop(&s->dev, vdev, false);
305b430a2bdSLongpeng 
306b430a2bdSLongpeng     ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false);
307b430a2bdSLongpeng     if (ret < 0) {
308b430a2bdSLongpeng         error_report("vhost guest notifier cleanup failed: %d", ret);
309b430a2bdSLongpeng         return;
310b430a2bdSLongpeng     }
311b430a2bdSLongpeng 
312b430a2bdSLongpeng     vhost_dev_disable_notifiers(&s->dev, vdev);
313b430a2bdSLongpeng }
314b430a2bdSLongpeng 
vhost_vdpa_device_set_status(VirtIODevice * vdev,uint8_t status)315b430a2bdSLongpeng static void vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status)
316b430a2bdSLongpeng {
317b430a2bdSLongpeng     VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev);
318b430a2bdSLongpeng     bool should_start = virtio_device_started(vdev, status);
319b430a2bdSLongpeng     Error *local_err = NULL;
320b430a2bdSLongpeng     int ret;
321b430a2bdSLongpeng 
322b430a2bdSLongpeng     if (!vdev->vm_running) {
323b430a2bdSLongpeng         should_start = false;
324b430a2bdSLongpeng     }
325b430a2bdSLongpeng 
326b430a2bdSLongpeng     if (s->started == should_start) {
327b430a2bdSLongpeng         return;
328b430a2bdSLongpeng     }
329b430a2bdSLongpeng 
330b430a2bdSLongpeng     if (should_start) {
331b430a2bdSLongpeng         ret = vhost_vdpa_device_start(vdev, &local_err);
332b430a2bdSLongpeng         if (ret < 0) {
333b430a2bdSLongpeng             error_reportf_err(local_err, "vhost-vdpa-device: start failed: ");
334b430a2bdSLongpeng         }
335b430a2bdSLongpeng     } else {
336b430a2bdSLongpeng         vhost_vdpa_device_stop(vdev);
337b430a2bdSLongpeng     }
338b430a2bdSLongpeng }
339b430a2bdSLongpeng 
340b430a2bdSLongpeng static Property vhost_vdpa_device_properties[] = {
341b430a2bdSLongpeng     DEFINE_PROP_STRING("vhostdev", VhostVdpaDevice, vhostdev),
342b430a2bdSLongpeng     DEFINE_PROP_UINT16("queue-size", VhostVdpaDevice, queue_size, 0),
343b430a2bdSLongpeng     DEFINE_PROP_END_OF_LIST(),
344b430a2bdSLongpeng };
345b430a2bdSLongpeng 
346b430a2bdSLongpeng static const VMStateDescription vmstate_vhost_vdpa_device = {
347b430a2bdSLongpeng     .name = "vhost-vdpa-device",
348dd18a230SLongpeng     .unmigratable = 1,
349b430a2bdSLongpeng     .minimum_version_id = 1,
350b430a2bdSLongpeng     .version_id = 1,
351ca02a170SRichard Henderson     .fields = (const VMStateField[]) {
352b430a2bdSLongpeng         VMSTATE_VIRTIO_DEVICE,
353b430a2bdSLongpeng         VMSTATE_END_OF_LIST()
354b430a2bdSLongpeng     },
355b430a2bdSLongpeng };
356b430a2bdSLongpeng 
vhost_vdpa_device_class_init(ObjectClass * klass,void * data)357b430a2bdSLongpeng static void vhost_vdpa_device_class_init(ObjectClass *klass, void *data)
358b430a2bdSLongpeng {
359b430a2bdSLongpeng     DeviceClass *dc = DEVICE_CLASS(klass);
360b430a2bdSLongpeng     VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
361b430a2bdSLongpeng 
362b430a2bdSLongpeng     device_class_set_props(dc, vhost_vdpa_device_properties);
363b430a2bdSLongpeng     dc->desc = "VDPA-based generic device assignment";
364b430a2bdSLongpeng     dc->vmsd = &vmstate_vhost_vdpa_device;
365b430a2bdSLongpeng     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
366b430a2bdSLongpeng     vdc->realize = vhost_vdpa_device_realize;
367b430a2bdSLongpeng     vdc->unrealize = vhost_vdpa_device_unrealize;
368b430a2bdSLongpeng     vdc->get_config = vhost_vdpa_device_get_config;
369b430a2bdSLongpeng     vdc->set_config = vhost_vdpa_device_set_config;
370b430a2bdSLongpeng     vdc->get_features = vhost_vdpa_device_get_features;
371b430a2bdSLongpeng     vdc->set_status = vhost_vdpa_device_set_status;
372b430a2bdSLongpeng }
373b430a2bdSLongpeng 
vhost_vdpa_device_instance_init(Object * obj)374b430a2bdSLongpeng static void vhost_vdpa_device_instance_init(Object *obj)
375b430a2bdSLongpeng {
376b430a2bdSLongpeng     VhostVdpaDevice *s = VHOST_VDPA_DEVICE(obj);
377b430a2bdSLongpeng 
378b430a2bdSLongpeng     device_add_bootindex_property(obj, &s->bootindex, "bootindex",
379b430a2bdSLongpeng                                   NULL, DEVICE(obj));
380b430a2bdSLongpeng }
381b430a2bdSLongpeng 
382b430a2bdSLongpeng static const TypeInfo vhost_vdpa_device_info = {
383b430a2bdSLongpeng     .name = TYPE_VHOST_VDPA_DEVICE,
384b430a2bdSLongpeng     .parent = TYPE_VIRTIO_DEVICE,
385b430a2bdSLongpeng     .instance_size = sizeof(VhostVdpaDevice),
386b430a2bdSLongpeng     .class_init = vhost_vdpa_device_class_init,
387b430a2bdSLongpeng     .instance_init = vhost_vdpa_device_instance_init,
388b430a2bdSLongpeng };
389b430a2bdSLongpeng 
register_vhost_vdpa_device_type(void)390b430a2bdSLongpeng static void register_vhost_vdpa_device_type(void)
391b430a2bdSLongpeng {
392b430a2bdSLongpeng     type_register_static(&vhost_vdpa_device_info);
393b430a2bdSLongpeng }
394b430a2bdSLongpeng 
395b430a2bdSLongpeng type_init(register_vhost_vdpa_device_type);
396