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