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