1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
/*
* Abstract virtio based memory device
*
* Copyright (C) 2023 Red Hat, Inc.
*
* Authors:
* David Hildenbrand <david@redhat.com>
*
* This work is licensed under the terms of the GNU GPL, version 2.
* See the COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "hw/virtio/virtio-md-pci.h"
#include "hw/mem/memory-device.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
void virtio_md_pci_pre_plug(VirtIOMDPCI *vmd, MachineState *ms, Error **errp)
{
DeviceState *dev = DEVICE(vmd);
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
MemoryDeviceState *md = MEMORY_DEVICE(vmd);
Error *local_err = NULL;
if (!bus_handler && dev->hotplugged) {
/*
* Without a bus hotplug handler, we cannot control the plug/unplug
* order. We should never reach this point when hotplugging on x86,
* however, better add a safety net.
*/
error_setg(errp, "hotplug of virtio based memory devices not supported"
" on this bus.");
return;
}
/*
* First, see if we can plug this memory device at all. If that
* succeeds, branch of to the actual hotplug handler.
*/
memory_device_pre_plug(md, ms, &local_err);
if (!local_err && bus_handler) {
hotplug_handler_pre_plug(bus_handler, dev, &local_err);
}
error_propagate(errp, local_err);
}
void virtio_md_pci_plug(VirtIOMDPCI *vmd, MachineState *ms, Error **errp)
{
DeviceState *dev = DEVICE(vmd);
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
MemoryDeviceState *md = MEMORY_DEVICE(vmd);
Error *local_err = NULL;
/*
* Plug the memory device first and then branch off to the actual
* hotplug handler. If that one fails, we can easily undo the memory
* device bits.
*/
memory_device_plug(md, ms);
if (bus_handler) {
hotplug_handler_plug(bus_handler, dev, &local_err);
if (local_err) {
memory_device_unplug(md, ms);
}
}
error_propagate(errp, local_err);
}
void virtio_md_pci_unplug_request(VirtIOMDPCI *vmd, MachineState *ms,
Error **errp)
{
VirtIOMDPCIClass *vmdc = VIRTIO_MD_PCI_GET_CLASS(vmd);
DeviceState *dev = DEVICE(vmd);
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
HotplugHandlerClass *hdc;
Error *local_err = NULL;
if (!vmdc->unplug_request_check) {
error_setg(errp, "this virtio based memory devices cannot be unplugged");
return;
}
if (!bus_handler) {
error_setg(errp, "hotunplug of virtio based memory devices not"
"supported on this bus");
return;
}
vmdc->unplug_request_check(vmd, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
/*
* Forward the async request or turn it into a sync request (handling it
* like qdev_unplug()).
*/
hdc = HOTPLUG_HANDLER_GET_CLASS(bus_handler);
if (hdc->unplug_request) {
hotplug_handler_unplug_request(bus_handler, dev, &local_err);
} else {
virtio_md_pci_unplug(vmd, ms, &local_err);
if (!local_err) {
object_unparent(OBJECT(dev));
}
}
}
void virtio_md_pci_unplug(VirtIOMDPCI *vmd, MachineState *ms, Error **errp)
{
DeviceState *dev = DEVICE(vmd);
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
MemoryDeviceState *md = MEMORY_DEVICE(vmd);
Error *local_err = NULL;
/* Unplug the memory device while it is still realized. */
memory_device_unplug(md, ms);
if (bus_handler) {
hotplug_handler_unplug(bus_handler, dev, &local_err);
if (local_err) {
/* Not expected to fail ... but still try to recover. */
memory_device_plug(md, ms);
error_propagate(errp, local_err);
return;
}
} else {
/* Very unexpected, but let's just try to do the right thing. */
warn_report("Unexpected unplug of virtio based memory device");
qdev_unrealize(dev);
}
}
static const TypeInfo virtio_md_pci_info = {
.name = TYPE_VIRTIO_MD_PCI,
.parent = TYPE_VIRTIO_PCI,
.instance_size = sizeof(VirtIOMDPCI),
.class_size = sizeof(VirtIOMDPCIClass),
.abstract = true,
.interfaces = (InterfaceInfo[]) {
{ TYPE_MEMORY_DEVICE },
{ }
},
};
static void virtio_md_pci_register(void)
{
type_register_static(&virtio_md_pci_info);
}
type_init(virtio_md_pci_register)
|