1 /* 2 * Virtio CCW support for abstract virtio based memory device 3 * 4 * Copyright (C) 2024 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/s390x/virtio-ccw-md.h" 15 #include "hw/mem/memory-device.h" 16 #include "qapi/error.h" 17 #include "qemu/error-report.h" 18 19 void virtio_ccw_md_pre_plug(VirtIOMDCcw *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, but 30 * 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 /* 38 * First, see if we can plug this memory device at all. If that 39 * succeeds, branch of to the actual hotplug handler. 40 */ 41 memory_device_pre_plug(md, ms, &local_err); 42 if (!local_err && bus_handler) { 43 hotplug_handler_pre_plug(bus_handler, dev, &local_err); 44 } 45 error_propagate(errp, local_err); 46 } 47 48 void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp) 49 { 50 DeviceState *dev = DEVICE(vmd); 51 HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev); 52 MemoryDeviceState *md = MEMORY_DEVICE(vmd); 53 Error *local_err = NULL; 54 55 /* 56 * Plug the memory device first and then branch off to the actual 57 * hotplug handler. If that one fails, we can easily undo the memory 58 * device bits. 59 */ 60 memory_device_plug(md, ms); 61 if (bus_handler) { 62 hotplug_handler_plug(bus_handler, dev, &local_err); 63 if (local_err) { 64 memory_device_unplug(md, ms); 65 } 66 } 67 error_propagate(errp, local_err); 68 } 69 70 void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms, 71 Error **errp) 72 { 73 VirtIOMDCcwClass *vmdc = VIRTIO_MD_CCW_GET_CLASS(vmd); 74 DeviceState *dev = DEVICE(vmd); 75 HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev); 76 HotplugHandlerClass *hdc; 77 Error *local_err = NULL; 78 79 if (!vmdc->unplug_request_check) { 80 error_setg(errp, 81 "this virtio based memory devices cannot be unplugged"); 82 return; 83 } 84 85 if (!bus_handler) { 86 error_setg(errp, "hotunplug of virtio based memory devices not" 87 "supported on this bus"); 88 return; 89 } 90 91 vmdc->unplug_request_check(vmd, &local_err); 92 if (local_err) { 93 error_propagate(errp, local_err); 94 return; 95 } 96 97 /* 98 * Forward the async request or turn it into a sync request (handling it 99 * like qdev_unplug()). 100 */ 101 hdc = HOTPLUG_HANDLER_GET_CLASS(bus_handler); 102 if (hdc->unplug_request) { 103 hotplug_handler_unplug_request(bus_handler, dev, &local_err); 104 } else { 105 virtio_ccw_md_unplug(vmd, ms, &local_err); 106 if (!local_err) { 107 object_unparent(OBJECT(dev)); 108 } 109 } 110 } 111 112 void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp) 113 { 114 DeviceState *dev = DEVICE(vmd); 115 HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev); 116 MemoryDeviceState *md = MEMORY_DEVICE(vmd); 117 Error *local_err = NULL; 118 119 /* Unplug the memory device while it is still realized. */ 120 memory_device_unplug(md, ms); 121 122 if (bus_handler) { 123 hotplug_handler_unplug(bus_handler, dev, &local_err); 124 if (local_err) { 125 /* Not expected to fail ... but still try to recover. */ 126 memory_device_plug(md, ms); 127 error_propagate(errp, local_err); 128 return; 129 } 130 } else { 131 /* Very unexpected, but let's just try to do the right thing. */ 132 warn_report("Unexpected unplug of virtio based memory device"); 133 qdev_unrealize(dev); 134 } 135 } 136 137 static const TypeInfo virtio_ccw_md_info = { 138 .name = TYPE_VIRTIO_MD_CCW, 139 .parent = TYPE_VIRTIO_CCW_DEVICE, 140 .instance_size = sizeof(VirtIOMDCcw), 141 .class_size = sizeof(VirtIOMDCcwClass), 142 .abstract = true, 143 .interfaces = (InterfaceInfo[]) { 144 { TYPE_MEMORY_DEVICE }, 145 { } 146 }, 147 }; 148 149 static void virtio_ccw_md_register(void) 150 { 151 type_register_static(&virtio_ccw_md_info); 152 } 153 type_init(virtio_ccw_md_register) 154