2 * Virtio MEM PCI device
4 * Copyright (C) 2020 Red Hat, Inc.
7 * David Hildenbrand <david@redhat.com>
9 * This work is licensed under the terms of the GNU GPL, version 2.
10 * See the COPYING file in the top-level directory.
13 #include "qemu/osdep.h"
14 #include "virtio-mem-pci.h"
15 #include "hw/mem/memory-device.h"
16 #include "qapi/error.h"
17 #include "qapi/qapi-events-machine.h"
18 #include "qapi/qapi-events-misc.h"
20 static void virtio_mem_pci_realize(VirtIOPCIProxy
*vpci_dev
, Error
**errp
)
22 VirtIOMEMPCI
*mem_pci
= VIRTIO_MEM_PCI(vpci_dev
);
23 DeviceState
*vdev
= DEVICE(&mem_pci
->vdev
);
25 virtio_pci_force_virtio_1(vpci_dev
);
26 qdev_realize(vdev
, BUS(&vpci_dev
->bus
), errp
);
29 static void virtio_mem_pci_set_addr(MemoryDeviceState
*md
, uint64_t addr
,
32 object_property_set_uint(OBJECT(md
), VIRTIO_MEM_ADDR_PROP
, addr
, errp
);
35 static uint64_t virtio_mem_pci_get_addr(const MemoryDeviceState
*md
)
37 return object_property_get_uint(OBJECT(md
), VIRTIO_MEM_ADDR_PROP
,
41 static MemoryRegion
*virtio_mem_pci_get_memory_region(MemoryDeviceState
*md
,
44 VirtIOMEMPCI
*pci_mem
= VIRTIO_MEM_PCI(md
);
45 VirtIOMEM
*vmem
= &pci_mem
->vdev
;
46 VirtIOMEMClass
*vmc
= VIRTIO_MEM_GET_CLASS(vmem
);
48 return vmc
->get_memory_region(vmem
, errp
);
51 static uint64_t virtio_mem_pci_get_plugged_size(const MemoryDeviceState
*md
,
54 return object_property_get_uint(OBJECT(md
), VIRTIO_MEM_SIZE_PROP
,
58 static void virtio_mem_pci_fill_device_info(const MemoryDeviceState
*md
,
59 MemoryDeviceInfo
*info
)
61 VirtioMEMDeviceInfo
*vi
= g_new0(VirtioMEMDeviceInfo
, 1);
62 VirtIOMEMPCI
*pci_mem
= VIRTIO_MEM_PCI(md
);
63 VirtIOMEM
*vmem
= &pci_mem
->vdev
;
64 VirtIOMEMClass
*vpc
= VIRTIO_MEM_GET_CLASS(vmem
);
65 DeviceState
*dev
= DEVICE(md
);
68 vi
->id
= g_strdup(dev
->id
);
71 /* let the real device handle everything else */
72 vpc
->fill_device_info(vmem
, vi
);
74 info
->u
.virtio_mem
.data
= vi
;
75 info
->type
= MEMORY_DEVICE_INFO_KIND_VIRTIO_MEM
;
78 static uint64_t virtio_mem_pci_get_min_alignment(const MemoryDeviceState
*md
)
80 return object_property_get_uint(OBJECT(md
), VIRTIO_MEM_BLOCK_SIZE_PROP
,
84 static void virtio_mem_pci_size_change_notify(Notifier
*notifier
, void *data
)
86 VirtIOMEMPCI
*pci_mem
= container_of(notifier
, VirtIOMEMPCI
,
87 size_change_notifier
);
88 DeviceState
*dev
= DEVICE(pci_mem
);
89 char *qom_path
= object_get_canonical_path(OBJECT(dev
));
90 const uint64_t * const size_p
= data
;
92 qapi_event_send_memory_device_size_change(dev
->id
, *size_p
, qom_path
);
96 static void virtio_mem_pci_unplug_request_check(VirtIOMDPCI
*vmd
, Error
**errp
)
98 VirtIOMEMPCI
*pci_mem
= VIRTIO_MEM_PCI(vmd
);
99 VirtIOMEM
*vmem
= &pci_mem
->vdev
;
100 VirtIOMEMClass
*vpc
= VIRTIO_MEM_GET_CLASS(vmem
);
102 vpc
->unplug_request_check(vmem
, errp
);
105 static void virtio_mem_pci_get_requested_size(Object
*obj
, Visitor
*v
,
106 const char *name
, void *opaque
,
109 VirtIOMEMPCI
*pci_mem
= VIRTIO_MEM_PCI(obj
);
111 object_property_get(OBJECT(&pci_mem
->vdev
), name
, v
, errp
);
114 static void virtio_mem_pci_set_requested_size(Object
*obj
, Visitor
*v
,
115 const char *name
, void *opaque
,
118 VirtIOMEMPCI
*pci_mem
= VIRTIO_MEM_PCI(obj
);
119 DeviceState
*dev
= DEVICE(obj
);
122 * If we passed virtio_mem_pci_unplug_request_check(), making sure that
123 * the requested size is 0, don't allow modifying the requested size
124 * anymore, otherwise the VM might end up hotplugging memory before
125 * handling the unplug request.
127 if (dev
->pending_deleted_event
) {
128 error_setg(errp
, "'%s' cannot be changed if the device is in the"
129 " process of unplug", name
);
133 object_property_set(OBJECT(&pci_mem
->vdev
), name
, v
, errp
);
136 static void virtio_mem_pci_class_init(ObjectClass
*klass
, void *data
)
138 DeviceClass
*dc
= DEVICE_CLASS(klass
);
139 VirtioPCIClass
*k
= VIRTIO_PCI_CLASS(klass
);
140 PCIDeviceClass
*pcidev_k
= PCI_DEVICE_CLASS(klass
);
141 MemoryDeviceClass
*mdc
= MEMORY_DEVICE_CLASS(klass
);
142 VirtIOMDPCIClass
*vmdc
= VIRTIO_MD_PCI_CLASS(klass
);
144 k
->realize
= virtio_mem_pci_realize
;
145 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
146 pcidev_k
->revision
= VIRTIO_PCI_ABI_VERSION
;
147 pcidev_k
->class_id
= PCI_CLASS_OTHERS
;
149 mdc
->get_addr
= virtio_mem_pci_get_addr
;
150 mdc
->set_addr
= virtio_mem_pci_set_addr
;
151 mdc
->get_plugged_size
= virtio_mem_pci_get_plugged_size
;
152 mdc
->get_memory_region
= virtio_mem_pci_get_memory_region
;
153 mdc
->fill_device_info
= virtio_mem_pci_fill_device_info
;
154 mdc
->get_min_alignment
= virtio_mem_pci_get_min_alignment
;
156 vmdc
->unplug_request_check
= virtio_mem_pci_unplug_request_check
;
159 static void virtio_mem_pci_instance_init(Object
*obj
)
161 VirtIOMEMPCI
*dev
= VIRTIO_MEM_PCI(obj
);
165 virtio_instance_init_common(obj
, &dev
->vdev
, sizeof(dev
->vdev
),
168 dev
->size_change_notifier
.notify
= virtio_mem_pci_size_change_notify
;
170 vmc
= VIRTIO_MEM_GET_CLASS(vmem
);
172 * We never remove the notifier again, as we expect both devices to
173 * disappear at the same time.
175 vmc
->add_size_change_notifier(vmem
, &dev
->size_change_notifier
);
177 object_property_add_alias(obj
, VIRTIO_MEM_BLOCK_SIZE_PROP
,
178 OBJECT(&dev
->vdev
), VIRTIO_MEM_BLOCK_SIZE_PROP
);
179 object_property_add_alias(obj
, VIRTIO_MEM_SIZE_PROP
, OBJECT(&dev
->vdev
),
180 VIRTIO_MEM_SIZE_PROP
);
181 object_property_add(obj
, VIRTIO_MEM_REQUESTED_SIZE_PROP
, "size",
182 virtio_mem_pci_get_requested_size
,
183 virtio_mem_pci_set_requested_size
, NULL
, NULL
);
186 static const VirtioPCIDeviceTypeInfo virtio_mem_pci_info
= {
187 .base_name
= TYPE_VIRTIO_MEM_PCI
,
188 .parent
= TYPE_VIRTIO_MD_PCI
,
189 .generic_name
= "virtio-mem-pci",
190 .instance_size
= sizeof(VirtIOMEMPCI
),
191 .instance_init
= virtio_mem_pci_instance_init
,
192 .class_init
= virtio_mem_pci_class_init
,
195 static void virtio_mem_pci_register_types(void)
197 virtio_pci_types_register(&virtio_mem_pci_info
);
199 type_init(virtio_mem_pci_register_types
)