master
c 108 lines 3.79 KB
Raw
1 /*
2 * Vhost-user generic virtio device PCI glue
3 *
4 * Copyright (c) 2023 Linaro Ltd
5 * Author: Alex Bennée <alex.bennee@linaro.org>
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "qemu/osdep.h"
11 #include "hw/core/qdev-properties.h"
12 #include "hw/virtio/vhost-user-base.h"
13 #include "hw/virtio/virtio-pci.h"
14
15 #define VIRTIO_DEVICE_PCI_SHMEM_BAR 4
16
17 struct VHostUserDevicePCI {
18 VirtIOPCIProxy parent_obj;
19
20 VHostUserBase vub;
21 MemoryRegion shmembar;
22 };
23
24 #define TYPE_VHOST_USER_TEST_DEVICE_PCI "vhost-user-test-device-pci-base"
25
26 OBJECT_DECLARE_SIMPLE_TYPE(VHostUserDevicePCI, VHOST_USER_TEST_DEVICE_PCI)
27
28 static void vhost_user_device_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
29 {
30 VHostUserDevicePCI *dev = VHOST_USER_TEST_DEVICE_PCI(vpci_dev);
31 DeviceState *dev_state = DEVICE(&dev->vub);
32 VirtIODevice *vdev = VIRTIO_DEVICE(dev_state);
33 VirtioSharedMemory *shmem;
34 uint64_t offset = 0, shmem_size = 0;
35
36 /* Keep modern 64-bit BARs (2 slots) away from the shared memory BAR. */
37 vpci_dev->modern_mem_bar_idx = 2;
38 vpci_dev->nvectors = 1;
39 if (!qdev_realize(dev_state, BUS(&vpci_dev->bus), errp)) {
40 return;
41 }
42
43 QSIMPLEQ_FOREACH(shmem, &vdev->shmem_list, entry) {
44 if (memory_region_size(&shmem->mr) > UINT64_MAX - shmem_size) {
45 error_setg(errp, "Total shared memory required overflow");
46 return;
47 }
48 shmem_size = shmem_size + memory_region_size(&shmem->mr);
49 }
50 if (shmem_size) {
51 if (vpci_dev->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY) {
52 error_setg(errp, "modern-pio-notify is not supported due to PCI BAR layout limitations");
53 return;
54 }
55 memory_region_init(&dev->shmembar, OBJECT(vpci_dev),
56 "vhost-device-pci-shmembar", shmem_size);
57 QSIMPLEQ_FOREACH(shmem, &vdev->shmem_list, entry) {
58 memory_region_add_subregion(&dev->shmembar, offset, &shmem->mr);
59 virtio_pci_add_shm_cap(vpci_dev, VIRTIO_DEVICE_PCI_SHMEM_BAR,
60 offset, memory_region_size(&shmem->mr),
61 shmem->shmid);
62 offset = offset + memory_region_size(&shmem->mr);
63 }
64 pci_register_bar(&vpci_dev->pci_dev, VIRTIO_DEVICE_PCI_SHMEM_BAR,
65 PCI_BASE_ADDRESS_SPACE_MEMORY |
66 PCI_BASE_ADDRESS_MEM_PREFETCH |
67 PCI_BASE_ADDRESS_MEM_TYPE_64,
68 &dev->shmembar);
69 }
70 }
71
72 static void vhost_user_device_pci_class_init(ObjectClass *klass,
73 const void *data)
74 {
75 DeviceClass *dc = DEVICE_CLASS(klass);
76 VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
77 PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
78
79 k->realize = vhost_user_device_pci_realize;
80 set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
81 pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
82 pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
83 pcidev_k->revision = 0x00;
84 pcidev_k->class_id = PCI_CLASS_COMMUNICATION_OTHER;
85 }
86
87 static void vhost_user_device_pci_instance_init(Object *obj)
88 {
89 VHostUserDevicePCI *dev = VHOST_USER_TEST_DEVICE_PCI(obj);
90
91 virtio_instance_init_common(obj, &dev->vub, sizeof(dev->vub),
92 TYPE_VHOST_USER_TEST_DEVICE);
93 }
94
95 static const VirtioPCIDeviceTypeInfo vhost_user_device_pci_info = {
96 .base_name = TYPE_VHOST_USER_TEST_DEVICE_PCI,
97 .non_transitional_name = "vhost-user-test-device-pci",
98 .instance_size = sizeof(VHostUserDevicePCI),
99 .instance_init = vhost_user_device_pci_instance_init,
100 .class_init = vhost_user_device_pci_class_init,
101 };
102
103 static void vhost_user_device_pci_register(void)
104 {
105 virtio_pci_types_register(&vhost_user_device_pci_info);
106 }
107
108 type_init(vhost_user_device_pci_register);