xref: /qemu/hw/virtio/virtio-md-pci.c (revision aac44204)
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 
virtio_md_pci_pre_plug(VirtIOMDPCI * vmd,MachineState * ms,Error ** errp)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      */
40dbdf841bSDavid Hildenbrand     memory_device_pre_plug(md, ms, NULL, &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 
virtio_md_pci_plug(VirtIOMDPCI * vmd,MachineState * ms,Error ** errp)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 
virtio_md_pci_unplug_request(VirtIOMDPCI * vmd,MachineState * ms,Error ** errp)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 
virtio_md_pci_unplug(VirtIOMDPCI * vmd,MachineState * ms,Error ** errp)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,
14118129c15SDavid Hildenbrand     .interfaces = (InterfaceInfo[]) {
14218129c15SDavid Hildenbrand         { TYPE_MEMORY_DEVICE },
14318129c15SDavid Hildenbrand         { }
14418129c15SDavid Hildenbrand     },
14518129c15SDavid Hildenbrand };
14618129c15SDavid Hildenbrand 
virtio_md_pci_register(void)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