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 void virtio_mem_pci_decide_memslots(MemoryDeviceState
*md
,
54 VirtIOMEMPCI
*pci_mem
= VIRTIO_MEM_PCI(md
);
55 VirtIOMEM
*vmem
= VIRTIO_MEM(&pci_mem
->vdev
);
56 VirtIOMEMClass
*vmc
= VIRTIO_MEM_GET_CLASS(vmem
);
58 vmc
->decide_memslots(vmem
, limit
);
61 static unsigned int virtio_mem_pci_get_memslots(MemoryDeviceState
*md
)
63 VirtIOMEMPCI
*pci_mem
= VIRTIO_MEM_PCI(md
);
64 VirtIOMEM
*vmem
= VIRTIO_MEM(&pci_mem
->vdev
);
65 VirtIOMEMClass
*vmc
= VIRTIO_MEM_GET_CLASS(vmem
);
67 return vmc
->get_memslots(vmem
);
70 static uint64_t virtio_mem_pci_get_plugged_size(const MemoryDeviceState
*md
,
73 return object_property_get_uint(OBJECT(md
), VIRTIO_MEM_SIZE_PROP
,
77 static void virtio_mem_pci_fill_device_info(const MemoryDeviceState
*md
,
78 MemoryDeviceInfo
*info
)
80 VirtioMEMDeviceInfo
*vi
= g_new0(VirtioMEMDeviceInfo
, 1);
81 VirtIOMEMPCI
*pci_mem
= VIRTIO_MEM_PCI(md
);
82 VirtIOMEM
*vmem
= &pci_mem
->vdev
;
83 VirtIOMEMClass
*vpc
= VIRTIO_MEM_GET_CLASS(vmem
);
84 DeviceState
*dev
= DEVICE(md
);
87 vi
->id
= g_strdup(dev
->id
);
90 /* let the real device handle everything else */
91 vpc
->fill_device_info(vmem
, vi
);
93 info
->u
.virtio_mem
.data
= vi
;
94 info
->type
= MEMORY_DEVICE_INFO_KIND_VIRTIO_MEM
;
97 static uint64_t virtio_mem_pci_get_min_alignment(const MemoryDeviceState
*md
)
99 return object_property_get_uint(OBJECT(md
), VIRTIO_MEM_BLOCK_SIZE_PROP
,
103 static void virtio_mem_pci_size_change_notify(Notifier
*notifier
, void *data
)
105 VirtIOMEMPCI
*pci_mem
= container_of(notifier
, VirtIOMEMPCI
,
106 size_change_notifier
);
107 DeviceState
*dev
= DEVICE(pci_mem
);
108 char *qom_path
= object_get_canonical_path(OBJECT(dev
));
109 const uint64_t * const size_p
= data
;
111 qapi_event_send_memory_device_size_change(dev
->id
, *size_p
, qom_path
);
115 static void virtio_mem_pci_unplug_request_check(VirtIOMDPCI
*vmd
, Error
**errp
)
117 VirtIOMEMPCI
*pci_mem
= VIRTIO_MEM_PCI(vmd
);
118 VirtIOMEM
*vmem
= &pci_mem
->vdev
;
119 VirtIOMEMClass
*vpc
= VIRTIO_MEM_GET_CLASS(vmem
);
121 vpc
->unplug_request_check(vmem
, errp
);
124 static void virtio_mem_pci_get_requested_size(Object
*obj
, Visitor
*v
,
125 const char *name
, void *opaque
,
128 VirtIOMEMPCI
*pci_mem
= VIRTIO_MEM_PCI(obj
);
130 object_property_get(OBJECT(&pci_mem
->vdev
), name
, v
, errp
);
133 static void virtio_mem_pci_set_requested_size(Object
*obj
, Visitor
*v
,
134 const char *name
, void *opaque
,
137 VirtIOMEMPCI
*pci_mem
= VIRTIO_MEM_PCI(obj
);
138 DeviceState
*dev
= DEVICE(obj
);
141 * If we passed virtio_mem_pci_unplug_request_check(), making sure that
142 * the requested size is 0, don't allow modifying the requested size
143 * anymore, otherwise the VM might end up hotplugging memory before
144 * handling the unplug request.
146 if (dev
->pending_deleted_event
) {
147 error_setg(errp
, "'%s' cannot be changed if the device is in the"
148 " process of unplug", name
);
152 object_property_set(OBJECT(&pci_mem
->vdev
), name
, v
, errp
);
155 static void virtio_mem_pci_class_init(ObjectClass
*klass
, void *data
)
157 DeviceClass
*dc
= DEVICE_CLASS(klass
);
158 VirtioPCIClass
*k
= VIRTIO_PCI_CLASS(klass
);
159 PCIDeviceClass
*pcidev_k
= PCI_DEVICE_CLASS(klass
);
160 MemoryDeviceClass
*mdc
= MEMORY_DEVICE_CLASS(klass
);
161 VirtIOMDPCIClass
*vmdc
= VIRTIO_MD_PCI_CLASS(klass
);
163 k
->realize
= virtio_mem_pci_realize
;
164 set_bit(DEVICE_CATEGORY_MISC
, dc
->categories
);
165 pcidev_k
->revision
= VIRTIO_PCI_ABI_VERSION
;
166 pcidev_k
->class_id
= PCI_CLASS_OTHERS
;
168 mdc
->get_addr
= virtio_mem_pci_get_addr
;
169 mdc
->set_addr
= virtio_mem_pci_set_addr
;
170 mdc
->get_plugged_size
= virtio_mem_pci_get_plugged_size
;
171 mdc
->get_memory_region
= virtio_mem_pci_get_memory_region
;
172 mdc
->decide_memslots
= virtio_mem_pci_decide_memslots
;
173 mdc
->get_memslots
= virtio_mem_pci_get_memslots
;
174 mdc
->fill_device_info
= virtio_mem_pci_fill_device_info
;
175 mdc
->get_min_alignment
= virtio_mem_pci_get_min_alignment
;
177 vmdc
->unplug_request_check
= virtio_mem_pci_unplug_request_check
;
180 static void virtio_mem_pci_instance_init(Object
*obj
)
182 VirtIOMEMPCI
*dev
= VIRTIO_MEM_PCI(obj
);
186 virtio_instance_init_common(obj
, &dev
->vdev
, sizeof(dev
->vdev
),
189 dev
->size_change_notifier
.notify
= virtio_mem_pci_size_change_notify
;
191 vmc
= VIRTIO_MEM_GET_CLASS(vmem
);
193 * We never remove the notifier again, as we expect both devices to
194 * disappear at the same time.
196 vmc
->add_size_change_notifier(vmem
, &dev
->size_change_notifier
);
198 object_property_add_alias(obj
, VIRTIO_MEM_BLOCK_SIZE_PROP
,
199 OBJECT(&dev
->vdev
), VIRTIO_MEM_BLOCK_SIZE_PROP
);
200 object_property_add_alias(obj
, VIRTIO_MEM_SIZE_PROP
, OBJECT(&dev
->vdev
),
201 VIRTIO_MEM_SIZE_PROP
);
202 object_property_add(obj
, VIRTIO_MEM_REQUESTED_SIZE_PROP
, "size",
203 virtio_mem_pci_get_requested_size
,
204 virtio_mem_pci_set_requested_size
, NULL
, NULL
);
207 static const VirtioPCIDeviceTypeInfo virtio_mem_pci_info
= {
208 .base_name
= TYPE_VIRTIO_MEM_PCI
,
209 .parent
= TYPE_VIRTIO_MD_PCI
,
210 .generic_name
= "virtio-mem-pci",
211 .instance_size
= sizeof(VirtIOMEMPCI
),
212 .instance_init
= virtio_mem_pci_instance_init
,
213 .class_init
= virtio_mem_pci_class_init
,
216 static void virtio_mem_pci_register_types(void)
218 virtio_pci_types_register(&virtio_mem_pci_info
);
220 type_init(virtio_mem_pci_register_types
)