mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 07:43:54 -06:00
s390x/virtio-ccw: add support for virtio based memory devices
Let's implement support for abstract virtio based memory devices, using the virtio-pci implementation as an orientation. Wire them up in the machine hotplug handler, taking care of s390x page size limitations. As we neither support virtio-mem or virtio-pmem yet, the code is effectively unused. We'll implement support for virtio-mem based on this next. Note that we won't wire up the virtio-pci variant (should currently be impossible due to lack of support for MSI-X), but we'll add a safety net to reject plugging them in the pre-plug handler. Message-ID: <20241219144115.2820241-14-david@redhat.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: David Hildenbrand <david@redhat.com>
This commit is contained in:
parent
df2ac211a6
commit
88d86f6f1e
7 changed files with 274 additions and 1 deletions
|
@ -2376,6 +2376,9 @@ F: include/hw/virtio/virtio-crypto.h
|
|||
virtio based memory device
|
||||
M: David Hildenbrand <david@redhat.com>
|
||||
S: Supported
|
||||
F: hw/s390x/virtio-ccw-md.c
|
||||
F: hw/s390x/virtio-ccw-md.h
|
||||
F: hw/s390x/virtio-ccw-md-stubs.c
|
||||
F: hw/virtio/virtio-md-pci.c
|
||||
F: include/hw/virtio/virtio-md-pci.h
|
||||
F: stubs/virtio-md-pci.c
|
||||
|
|
|
@ -50,8 +50,11 @@ endif
|
|||
virtio_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi-ccw.c'))
|
||||
virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-ccw.c'))
|
||||
virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs-ccw.c'))
|
||||
virtio_ss.add(when: 'CONFIG_VIRTIO_MD', if_true: files('virtio-ccw-md.c'))
|
||||
s390x_ss.add_all(when: 'CONFIG_VIRTIO_CCW', if_true: virtio_ss)
|
||||
|
||||
s390x_ss.add(when: 'CONFIG_VIRTIO_MD', if_false: files('virtio-ccw-md-stubs.c'))
|
||||
|
||||
hw_arch += {'s390x': s390x_ss}
|
||||
|
||||
hw_s390x_modules = {}
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#include "qapi/visitor.h"
|
||||
#include "hw/s390x/cpu-topology.h"
|
||||
#include "kvm/kvm_s390x.h"
|
||||
#include "hw/virtio/virtio-md-pci.h"
|
||||
#include "hw/s390x/virtio-ccw-md.h"
|
||||
#include CONFIG_DEVICES
|
||||
|
||||
static Error *pv_mig_blocker;
|
||||
|
@ -546,11 +548,39 @@ static void s390_machine_reset(MachineState *machine, ResetType type)
|
|||
s390_ipl_clear_reset_request();
|
||||
}
|
||||
|
||||
static void s390_machine_device_pre_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
|
||||
virtio_ccw_md_pre_plug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
|
||||
error_setg(errp,
|
||||
"PCI-attached virtio based memory devices not supported");
|
||||
}
|
||||
}
|
||||
|
||||
static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
S390CcwMachineState *s390ms = S390_CCW_MACHINE(hotplug_dev);
|
||||
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
s390_cpu_plug(hotplug_dev, dev, errp);
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
|
||||
/*
|
||||
* At this point, the device is realized and set all memdevs mapped, so
|
||||
* qemu_maxrampagesize() will pick up the page sizes of these memdevs
|
||||
* as well. Before we plug the device and expose any RAM memory regions
|
||||
* to the system, make sure we don't exceed the previously set max page
|
||||
* size. While only relevant for KVM, there is not really any use case
|
||||
* for this with TCG, so we'll unconditionally reject it.
|
||||
*/
|
||||
if (qemu_maxrampagesize() != s390ms->max_pagesize) {
|
||||
error_setg(errp, "Memory device uses a bigger page size than"
|
||||
" initial memory");
|
||||
return;
|
||||
}
|
||||
virtio_ccw_md_plug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -560,9 +590,20 @@ static void s390_machine_device_unplug_request(HotplugHandler *hotplug_dev,
|
|||
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
error_setg(errp, "CPU hot unplug not supported on this machine");
|
||||
return;
|
||||
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
|
||||
virtio_ccw_md_unplug_request(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev),
|
||||
errp);
|
||||
}
|
||||
}
|
||||
|
||||
static void s390_machine_device_unplug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
|
||||
virtio_ccw_md_unplug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp);
|
||||
}
|
||||
}
|
||||
|
||||
static CpuInstanceProperties s390_cpu_index_to_props(MachineState *ms,
|
||||
unsigned cpu_index)
|
||||
{
|
||||
|
@ -609,7 +650,9 @@ static const CPUArchIdList *s390_possible_cpu_arch_ids(MachineState *ms)
|
|||
static HotplugHandler *s390_get_hotplug_handler(MachineState *machine,
|
||||
DeviceState *dev)
|
||||
{
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) ||
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW) ||
|
||||
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
|
||||
return HOTPLUG_HANDLER(machine);
|
||||
}
|
||||
return NULL;
|
||||
|
@ -769,8 +812,10 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
|
|||
mc->possible_cpu_arch_ids = s390_possible_cpu_arch_ids;
|
||||
/* it is overridden with 'host' cpu *in kvm_arch_init* */
|
||||
mc->default_cpu_type = S390_CPU_TYPE_NAME("qemu");
|
||||
hc->pre_plug = s390_machine_device_pre_plug;
|
||||
hc->plug = s390_machine_device_plug;
|
||||
hc->unplug_request = s390_machine_device_unplug_request;
|
||||
hc->unplug = s390_machine_device_unplug;
|
||||
nc->nmi_monitor_handler = s390_nmi;
|
||||
mc->default_ram_id = "s390.ram";
|
||||
mc->default_nic = "virtio-net-ccw";
|
||||
|
|
24
hw/s390x/virtio-ccw-md-stubs.c
Normal file
24
hw/s390x/virtio-ccw-md-stubs.c
Normal file
|
@ -0,0 +1,24 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/s390x/virtio-ccw-md.h"
|
||||
|
||||
void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
|
||||
{
|
||||
error_setg(errp, "virtio based memory devices not supported");
|
||||
}
|
||||
|
||||
void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
|
||||
{
|
||||
error_setg(errp, "virtio based memory devices not supported");
|
||||
}
|
||||
|
||||
void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg(errp, "virtio based memory devices not supported");
|
||||
}
|
||||
|
||||
void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
|
||||
{
|
||||
error_setg(errp, "virtio based memory devices not supported");
|
||||
}
|
153
hw/s390x/virtio-ccw-md.c
Normal file
153
hw/s390x/virtio-ccw-md.c
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Virtio CCW support for abstract virtio based memory device
|
||||
*
|
||||
* Copyright (C) 2024 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* David Hildenbrand <david@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/s390x/virtio-ccw-md.h"
|
||||
#include "hw/mem/memory-device.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(vmd);
|
||||
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
|
||||
MemoryDeviceState *md = MEMORY_DEVICE(vmd);
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!bus_handler && dev->hotplugged) {
|
||||
/*
|
||||
* Without a bus hotplug handler, we cannot control the plug/unplug
|
||||
* order. We should never reach this point when hotplugging, but
|
||||
* better add a safety net.
|
||||
*/
|
||||
error_setg(errp, "hotplug of virtio based memory devices not supported"
|
||||
" on this bus.");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* First, see if we can plug this memory device at all. If that
|
||||
* succeeds, branch of to the actual hotplug handler.
|
||||
*/
|
||||
memory_device_pre_plug(md, ms, &local_err);
|
||||
if (!local_err && bus_handler) {
|
||||
hotplug_handler_pre_plug(bus_handler, dev, &local_err);
|
||||
}
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(vmd);
|
||||
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
|
||||
MemoryDeviceState *md = MEMORY_DEVICE(vmd);
|
||||
Error *local_err = NULL;
|
||||
|
||||
/*
|
||||
* Plug the memory device first and then branch off to the actual
|
||||
* hotplug handler. If that one fails, we can easily undo the memory
|
||||
* device bits.
|
||||
*/
|
||||
memory_device_plug(md, ms);
|
||||
if (bus_handler) {
|
||||
hotplug_handler_plug(bus_handler, dev, &local_err);
|
||||
if (local_err) {
|
||||
memory_device_unplug(md, ms);
|
||||
}
|
||||
}
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
||||
void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
|
||||
Error **errp)
|
||||
{
|
||||
VirtIOMDCcwClass *vmdc = VIRTIO_MD_CCW_GET_CLASS(vmd);
|
||||
DeviceState *dev = DEVICE(vmd);
|
||||
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
|
||||
HotplugHandlerClass *hdc;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (!vmdc->unplug_request_check) {
|
||||
error_setg(errp,
|
||||
"this virtio based memory devices cannot be unplugged");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bus_handler) {
|
||||
error_setg(errp, "hotunplug of virtio based memory devices not"
|
||||
"supported on this bus");
|
||||
return;
|
||||
}
|
||||
|
||||
vmdc->unplug_request_check(vmd, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Forward the async request or turn it into a sync request (handling it
|
||||
* like qdev_unplug()).
|
||||
*/
|
||||
hdc = HOTPLUG_HANDLER_GET_CLASS(bus_handler);
|
||||
if (hdc->unplug_request) {
|
||||
hotplug_handler_unplug_request(bus_handler, dev, &local_err);
|
||||
} else {
|
||||
virtio_ccw_md_unplug(vmd, ms, &local_err);
|
||||
if (!local_err) {
|
||||
object_unparent(OBJECT(dev));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
|
||||
{
|
||||
DeviceState *dev = DEVICE(vmd);
|
||||
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
|
||||
MemoryDeviceState *md = MEMORY_DEVICE(vmd);
|
||||
Error *local_err = NULL;
|
||||
|
||||
/* Unplug the memory device while it is still realized. */
|
||||
memory_device_unplug(md, ms);
|
||||
|
||||
if (bus_handler) {
|
||||
hotplug_handler_unplug(bus_handler, dev, &local_err);
|
||||
if (local_err) {
|
||||
/* Not expected to fail ... but still try to recover. */
|
||||
memory_device_plug(md, ms);
|
||||
error_propagate(errp, local_err);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* Very unexpected, but let's just try to do the right thing. */
|
||||
warn_report("Unexpected unplug of virtio based memory device");
|
||||
qdev_unrealize(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static const TypeInfo virtio_ccw_md_info = {
|
||||
.name = TYPE_VIRTIO_MD_CCW,
|
||||
.parent = TYPE_VIRTIO_CCW_DEVICE,
|
||||
.instance_size = sizeof(VirtIOMDCcw),
|
||||
.class_size = sizeof(VirtIOMDCcwClass),
|
||||
.abstract = true,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ TYPE_MEMORY_DEVICE },
|
||||
{ }
|
||||
},
|
||||
};
|
||||
|
||||
static void virtio_ccw_md_register(void)
|
||||
{
|
||||
type_register_static(&virtio_ccw_md_info);
|
||||
}
|
||||
type_init(virtio_ccw_md_register)
|
44
hw/s390x/virtio-ccw-md.h
Normal file
44
hw/s390x/virtio-ccw-md.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Virtio CCW support for abstract virtio based memory device
|
||||
*
|
||||
* Copyright (C) 2024 Red Hat, Inc.
|
||||
*
|
||||
* Authors:
|
||||
* David Hildenbrand <david@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef HW_S390X_VIRTIO_CCW_MD_H
|
||||
#define HW_S390X_VIRTIO_CCW_MD_H
|
||||
|
||||
#include "virtio-ccw.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
/*
|
||||
* virtio-md-ccw: This extends VirtioCcwDevice.
|
||||
*/
|
||||
#define TYPE_VIRTIO_MD_CCW "virtio-md-ccw"
|
||||
|
||||
OBJECT_DECLARE_TYPE(VirtIOMDCcw, VirtIOMDCcwClass, VIRTIO_MD_CCW)
|
||||
|
||||
struct VirtIOMDCcwClass {
|
||||
/* private */
|
||||
VirtIOCCWDeviceClass parent;
|
||||
|
||||
/* public */
|
||||
void (*unplug_request_check)(VirtIOMDCcw *vmd, Error **errp);
|
||||
};
|
||||
|
||||
struct VirtIOMDCcw {
|
||||
VirtioCcwDevice parent_obj;
|
||||
};
|
||||
|
||||
void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp);
|
||||
void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp);
|
||||
void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
|
||||
Error **errp);
|
||||
void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp);
|
||||
|
||||
#endif /* HW_S390X_VIRTIO_CCW_MD_H */
|
|
@ -29,6 +29,7 @@ config VIRTIO_MMIO
|
|||
config VIRTIO_CCW
|
||||
bool
|
||||
select VIRTIO
|
||||
select VIRTIO_MD_SUPPORTED
|
||||
|
||||
config VIRTIO_BALLOON
|
||||
bool
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue