mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-11 03:24:58 -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
|
virtio based memory device
|
||||||
M: David Hildenbrand <david@redhat.com>
|
M: David Hildenbrand <david@redhat.com>
|
||||||
S: Supported
|
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: hw/virtio/virtio-md-pci.c
|
||||||
F: include/hw/virtio/virtio-md-pci.h
|
F: include/hw/virtio/virtio-md-pci.h
|
||||||
F: stubs/virtio-md-pci.c
|
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_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_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_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_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_arch += {'s390x': s390x_ss}
|
||||||
|
|
||||||
hw_s390x_modules = {}
|
hw_s390x_modules = {}
|
||||||
|
|
|
@ -46,6 +46,8 @@
|
||||||
#include "qapi/visitor.h"
|
#include "qapi/visitor.h"
|
||||||
#include "hw/s390x/cpu-topology.h"
|
#include "hw/s390x/cpu-topology.h"
|
||||||
#include "kvm/kvm_s390x.h"
|
#include "kvm/kvm_s390x.h"
|
||||||
|
#include "hw/virtio/virtio-md-pci.h"
|
||||||
|
#include "hw/s390x/virtio-ccw-md.h"
|
||||||
#include CONFIG_DEVICES
|
#include CONFIG_DEVICES
|
||||||
|
|
||||||
static Error *pv_mig_blocker;
|
static Error *pv_mig_blocker;
|
||||||
|
@ -546,11 +548,39 @@ static void s390_machine_reset(MachineState *machine, ResetType type)
|
||||||
s390_ipl_clear_reset_request();
|
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,
|
static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
|
||||||
DeviceState *dev, Error **errp)
|
DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
|
S390CcwMachineState *s390ms = S390_CCW_MACHINE(hotplug_dev);
|
||||||
|
|
||||||
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||||
s390_cpu_plug(hotplug_dev, dev, errp);
|
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)) {
|
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
|
||||||
error_setg(errp, "CPU hot unplug not supported on this machine");
|
error_setg(errp, "CPU hot unplug not supported on this machine");
|
||||||
return;
|
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,
|
static CpuInstanceProperties s390_cpu_index_to_props(MachineState *ms,
|
||||||
unsigned cpu_index)
|
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,
|
static HotplugHandler *s390_get_hotplug_handler(MachineState *machine,
|
||||||
DeviceState *dev)
|
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 HOTPLUG_HANDLER(machine);
|
||||||
}
|
}
|
||||||
return NULL;
|
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;
|
mc->possible_cpu_arch_ids = s390_possible_cpu_arch_ids;
|
||||||
/* it is overridden with 'host' cpu *in kvm_arch_init* */
|
/* it is overridden with 'host' cpu *in kvm_arch_init* */
|
||||||
mc->default_cpu_type = S390_CPU_TYPE_NAME("qemu");
|
mc->default_cpu_type = S390_CPU_TYPE_NAME("qemu");
|
||||||
|
hc->pre_plug = s390_machine_device_pre_plug;
|
||||||
hc->plug = s390_machine_device_plug;
|
hc->plug = s390_machine_device_plug;
|
||||||
hc->unplug_request = s390_machine_device_unplug_request;
|
hc->unplug_request = s390_machine_device_unplug_request;
|
||||||
|
hc->unplug = s390_machine_device_unplug;
|
||||||
nc->nmi_monitor_handler = s390_nmi;
|
nc->nmi_monitor_handler = s390_nmi;
|
||||||
mc->default_ram_id = "s390.ram";
|
mc->default_ram_id = "s390.ram";
|
||||||
mc->default_nic = "virtio-net-ccw";
|
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
|
config VIRTIO_CCW
|
||||||
bool
|
bool
|
||||||
select VIRTIO
|
select VIRTIO
|
||||||
|
select VIRTIO_MD_SUPPORTED
|
||||||
|
|
||||||
config VIRTIO_BALLOON
|
config VIRTIO_BALLOON
|
||||||
bool
|
bool
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue