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