qemu/hw/virtio/virtio-md-pci.c
<<
>>
Prefs
   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
  19void 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
  47void 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
  69void virtio_md_pci_unplug_request(VirtIOMDPCI *vmd, MachineState *ms,
  70                                  Error **errp)
  71{
  72    VirtIOMDPCIClass *vmdc = VIRTIO_MD_PCI_GET_CLASS(vmd);
  73    DeviceState *dev = DEVICE(vmd);
  74    HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
  75    HotplugHandlerClass *hdc;
  76    Error *local_err = NULL;
  77
  78    if (!vmdc->unplug_request_check) {
  79        error_setg(errp, "this virtio based memory devices cannot be unplugged");
  80        return;
  81    }
  82
  83    if (!bus_handler) {
  84        error_setg(errp, "hotunplug of virtio based memory devices not"
  85                   "supported on this bus");
  86        return;
  87    }
  88
  89    vmdc->unplug_request_check(vmd, &local_err);
  90    if (local_err) {
  91        error_propagate(errp, local_err);
  92        return;
  93    }
  94
  95    /*
  96     * Forward the async request or turn it into a sync request (handling it
  97     * like qdev_unplug()).
  98     */
  99    hdc = HOTPLUG_HANDLER_GET_CLASS(bus_handler);
 100    if (hdc->unplug_request) {
 101        hotplug_handler_unplug_request(bus_handler, dev, &local_err);
 102    } else {
 103        virtio_md_pci_unplug(vmd, ms, &local_err);
 104        if (!local_err) {
 105            object_unparent(OBJECT(dev));
 106        }
 107    }
 108}
 109
 110void virtio_md_pci_unplug(VirtIOMDPCI *vmd, MachineState *ms, Error **errp)
 111{
 112    DeviceState *dev = DEVICE(vmd);
 113    HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
 114    MemoryDeviceState *md = MEMORY_DEVICE(vmd);
 115    Error *local_err = NULL;
 116
 117    /* Unplug the memory device while it is still realized. */
 118    memory_device_unplug(md, ms);
 119
 120    if (bus_handler) {
 121        hotplug_handler_unplug(bus_handler, dev, &local_err);
 122        if (local_err) {
 123            /* Not expected to fail ... but still try to recover. */
 124            memory_device_plug(md, ms);
 125            error_propagate(errp, local_err);
 126            return;
 127        }
 128    } else {
 129        /* Very unexpected, but let's just try to do the right thing. */
 130        warn_report("Unexpected unplug of virtio based memory device");
 131        qdev_unrealize(dev);
 132    }
 133}
 134
 135static const TypeInfo virtio_md_pci_info = {
 136    .name = TYPE_VIRTIO_MD_PCI,
 137    .parent = TYPE_VIRTIO_PCI,
 138    .instance_size = sizeof(VirtIOMDPCI),
 139    .class_size = sizeof(VirtIOMDPCIClass),
 140    .abstract = true,
 141    .interfaces = (InterfaceInfo[]) {
 142        { TYPE_MEMORY_DEVICE },
 143        { }
 144    },
 145};
 146
 147static void virtio_md_pci_register(void)
 148{
 149    type_register_static(&virtio_md_pci_info);
 150}
 151type_init(virtio_md_pci_register)
 152