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" 2932cad1ffSPhilippe Mathieu-Daudé #include "system/system.h" 3032cad1ffSPhilippe Mathieu-Daudé #include "system/runstate.h" 31b430a2bdSLongpeng 32b430a2bdSLongpeng static void 33b430a2bdSLongpeng vhost_vdpa_device_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) 34b430a2bdSLongpeng { 35b430a2bdSLongpeng /* Nothing to do */ 36b430a2bdSLongpeng } 37b430a2bdSLongpeng 38b430a2bdSLongpeng static uint32_t 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 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 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 195b430a2bdSLongpeng vhost_vdpa_device_get_config(VirtIODevice *vdev, uint8_t *config) 196b430a2bdSLongpeng { 197b430a2bdSLongpeng VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); 1986ae72f60Slyx634449800 int ret; 199b430a2bdSLongpeng 2006ae72f60Slyx634449800 ret = vhost_dev_get_config(&s->dev, s->config, s->config_size, 2016ae72f60Slyx634449800 NULL); 2026ae72f60Slyx634449800 if (ret < 0) { 2036ae72f60Slyx634449800 error_report("get device config space failed"); 2046ae72f60Slyx634449800 return; 2056ae72f60Slyx634449800 } 206b430a2bdSLongpeng memcpy(config, s->config, s->config_size); 207b430a2bdSLongpeng } 208b430a2bdSLongpeng 209b430a2bdSLongpeng static void 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 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 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 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 315*bc85aae4SHaoqian He static int 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) { 327*bc85aae4SHaoqian He return 0; 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 } 338*bc85aae4SHaoqian He return 0; 339b430a2bdSLongpeng } 340b430a2bdSLongpeng 3411577a918SRichard Henderson static const Property vhost_vdpa_device_properties[] = { 342b430a2bdSLongpeng DEFINE_PROP_STRING("vhostdev", VhostVdpaDevice, vhostdev), 343b430a2bdSLongpeng DEFINE_PROP_UINT16("queue-size", VhostVdpaDevice, queue_size, 0), 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 35712d1a768SPhilippe Mathieu-Daudé static void vhost_vdpa_device_class_init(ObjectClass *klass, const 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 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 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