Skip to content

Commit 88d86f6

Browse files
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: <[email protected]> Acked-by: Michael S. Tsirkin <[email protected]> Signed-off-by: David Hildenbrand <[email protected]>
1 parent df2ac21 commit 88d86f6

File tree

7 files changed

+274
-1
lines changed

7 files changed

+274
-1
lines changed

MAINTAINERS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2376,6 +2376,9 @@ F: include/hw/virtio/virtio-crypto.h
23762376
virtio based memory device
23772377
M: David Hildenbrand <[email protected]>
23782378
S: Supported
2379+
F: hw/s390x/virtio-ccw-md.c
2380+
F: hw/s390x/virtio-ccw-md.h
2381+
F: hw/s390x/virtio-ccw-md-stubs.c
23792382
F: hw/virtio/virtio-md-pci.c
23802383
F: include/hw/virtio/virtio-md-pci.h
23812384
F: stubs/virtio-md-pci.c

hw/s390x/meson.build

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,11 @@ endif
5050
virtio_ss.add(when: 'CONFIG_VHOST_SCSI', if_true: files('vhost-scsi-ccw.c'))
5151
virtio_ss.add(when: 'CONFIG_VHOST_VSOCK', if_true: files('vhost-vsock-ccw.c'))
5252
virtio_ss.add(when: 'CONFIG_VHOST_USER_FS', if_true: files('vhost-user-fs-ccw.c'))
53+
virtio_ss.add(when: 'CONFIG_VIRTIO_MD', if_true: files('virtio-ccw-md.c'))
5354
s390x_ss.add_all(when: 'CONFIG_VIRTIO_CCW', if_true: virtio_ss)
5455

56+
s390x_ss.add(when: 'CONFIG_VIRTIO_MD', if_false: files('virtio-ccw-md-stubs.c'))
57+
5558
hw_arch += {'s390x': s390x_ss}
5659

5760
hw_s390x_modules = {}

hw/s390x/s390-virtio-ccw.c

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
#include "qapi/visitor.h"
4747
#include "hw/s390x/cpu-topology.h"
4848
#include "kvm/kvm_s390x.h"
49+
#include "hw/virtio/virtio-md-pci.h"
50+
#include "hw/s390x/virtio-ccw-md.h"
4951
#include CONFIG_DEVICES
5052

5153
static Error *pv_mig_blocker;
@@ -546,11 +548,39 @@ static void s390_machine_reset(MachineState *machine, ResetType type)
546548
s390_ipl_clear_reset_request();
547549
}
548550

551+
static void s390_machine_device_pre_plug(HotplugHandler *hotplug_dev,
552+
DeviceState *dev, Error **errp)
553+
{
554+
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
555+
virtio_ccw_md_pre_plug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp);
556+
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
557+
error_setg(errp,
558+
"PCI-attached virtio based memory devices not supported");
559+
}
560+
}
561+
549562
static void s390_machine_device_plug(HotplugHandler *hotplug_dev,
550563
DeviceState *dev, Error **errp)
551564
{
565+
S390CcwMachineState *s390ms = S390_CCW_MACHINE(hotplug_dev);
566+
552567
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
553568
s390_cpu_plug(hotplug_dev, dev, errp);
569+
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
570+
/*
571+
* At this point, the device is realized and set all memdevs mapped, so
572+
* qemu_maxrampagesize() will pick up the page sizes of these memdevs
573+
* as well. Before we plug the device and expose any RAM memory regions
574+
* to the system, make sure we don't exceed the previously set max page
575+
* size. While only relevant for KVM, there is not really any use case
576+
* for this with TCG, so we'll unconditionally reject it.
577+
*/
578+
if (qemu_maxrampagesize() != s390ms->max_pagesize) {
579+
error_setg(errp, "Memory device uses a bigger page size than"
580+
" initial memory");
581+
return;
582+
}
583+
virtio_ccw_md_plug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp);
554584
}
555585
}
556586

@@ -560,9 +590,20 @@ static void s390_machine_device_unplug_request(HotplugHandler *hotplug_dev,
560590
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
561591
error_setg(errp, "CPU hot unplug not supported on this machine");
562592
return;
593+
} else if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
594+
virtio_ccw_md_unplug_request(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev),
595+
errp);
563596
}
564597
}
565598

599+
static void s390_machine_device_unplug(HotplugHandler *hotplug_dev,
600+
DeviceState *dev, Error **errp)
601+
{
602+
if (object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW)) {
603+
virtio_ccw_md_unplug(VIRTIO_MD_CCW(dev), MACHINE(hotplug_dev), errp);
604+
}
605+
}
606+
566607
static CpuInstanceProperties s390_cpu_index_to_props(MachineState *ms,
567608
unsigned cpu_index)
568609
{
@@ -609,7 +650,9 @@ static const CPUArchIdList *s390_possible_cpu_arch_ids(MachineState *ms)
609650
static HotplugHandler *s390_get_hotplug_handler(MachineState *machine,
610651
DeviceState *dev)
611652
{
612-
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
653+
if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) ||
654+
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_CCW) ||
655+
object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_MD_PCI)) {
613656
return HOTPLUG_HANDLER(machine);
614657
}
615658
return NULL;
@@ -769,8 +812,10 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
769812
mc->possible_cpu_arch_ids = s390_possible_cpu_arch_ids;
770813
/* it is overridden with 'host' cpu *in kvm_arch_init* */
771814
mc->default_cpu_type = S390_CPU_TYPE_NAME("qemu");
815+
hc->pre_plug = s390_machine_device_pre_plug;
772816
hc->plug = s390_machine_device_plug;
773817
hc->unplug_request = s390_machine_device_unplug_request;
818+
hc->unplug = s390_machine_device_unplug;
774819
nc->nmi_monitor_handler = s390_nmi;
775820
mc->default_ram_id = "s390.ram";
776821
mc->default_nic = "virtio-net-ccw";

hw/s390x/virtio-ccw-md-stubs.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "qemu/osdep.h"
2+
#include "qapi/error.h"
3+
#include "hw/s390x/virtio-ccw-md.h"
4+
5+
void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
6+
{
7+
error_setg(errp, "virtio based memory devices not supported");
8+
}
9+
10+
void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
11+
{
12+
error_setg(errp, "virtio based memory devices not supported");
13+
}
14+
15+
void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
16+
Error **errp)
17+
{
18+
error_setg(errp, "virtio based memory devices not supported");
19+
}
20+
21+
void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
22+
{
23+
error_setg(errp, "virtio based memory devices not supported");
24+
}

hw/s390x/virtio-ccw-md.c

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
* Virtio CCW support for abstract virtio based memory device
3+
*
4+
* Copyright (C) 2024 Red Hat, Inc.
5+
*
6+
* Authors:
7+
* David Hildenbrand <[email protected]>
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/s390x/virtio-ccw-md.h"
15+
#include "hw/mem/memory-device.h"
16+
#include "qapi/error.h"
17+
#include "qemu/error-report.h"
18+
19+
void virtio_ccw_md_pre_plug(VirtIOMDCcw *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, but
30+
* 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+
/*
38+
* First, see if we can plug this memory device at all. If that
39+
* succeeds, branch of to the actual hotplug handler.
40+
*/
41+
memory_device_pre_plug(md, ms, &local_err);
42+
if (!local_err && bus_handler) {
43+
hotplug_handler_pre_plug(bus_handler, dev, &local_err);
44+
}
45+
error_propagate(errp, local_err);
46+
}
47+
48+
void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
49+
{
50+
DeviceState *dev = DEVICE(vmd);
51+
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
52+
MemoryDeviceState *md = MEMORY_DEVICE(vmd);
53+
Error *local_err = NULL;
54+
55+
/*
56+
* Plug the memory device first and then branch off to the actual
57+
* hotplug handler. If that one fails, we can easily undo the memory
58+
* device bits.
59+
*/
60+
memory_device_plug(md, ms);
61+
if (bus_handler) {
62+
hotplug_handler_plug(bus_handler, dev, &local_err);
63+
if (local_err) {
64+
memory_device_unplug(md, ms);
65+
}
66+
}
67+
error_propagate(errp, local_err);
68+
}
69+
70+
void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
71+
Error **errp)
72+
{
73+
VirtIOMDCcwClass *vmdc = VIRTIO_MD_CCW_GET_CLASS(vmd);
74+
DeviceState *dev = DEVICE(vmd);
75+
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
76+
HotplugHandlerClass *hdc;
77+
Error *local_err = NULL;
78+
79+
if (!vmdc->unplug_request_check) {
80+
error_setg(errp,
81+
"this virtio based memory devices cannot be unplugged");
82+
return;
83+
}
84+
85+
if (!bus_handler) {
86+
error_setg(errp, "hotunplug of virtio based memory devices not"
87+
"supported on this bus");
88+
return;
89+
}
90+
91+
vmdc->unplug_request_check(vmd, &local_err);
92+
if (local_err) {
93+
error_propagate(errp, local_err);
94+
return;
95+
}
96+
97+
/*
98+
* Forward the async request or turn it into a sync request (handling it
99+
* like qdev_unplug()).
100+
*/
101+
hdc = HOTPLUG_HANDLER_GET_CLASS(bus_handler);
102+
if (hdc->unplug_request) {
103+
hotplug_handler_unplug_request(bus_handler, dev, &local_err);
104+
} else {
105+
virtio_ccw_md_unplug(vmd, ms, &local_err);
106+
if (!local_err) {
107+
object_unparent(OBJECT(dev));
108+
}
109+
}
110+
}
111+
112+
void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp)
113+
{
114+
DeviceState *dev = DEVICE(vmd);
115+
HotplugHandler *bus_handler = qdev_get_bus_hotplug_handler(dev);
116+
MemoryDeviceState *md = MEMORY_DEVICE(vmd);
117+
Error *local_err = NULL;
118+
119+
/* Unplug the memory device while it is still realized. */
120+
memory_device_unplug(md, ms);
121+
122+
if (bus_handler) {
123+
hotplug_handler_unplug(bus_handler, dev, &local_err);
124+
if (local_err) {
125+
/* Not expected to fail ... but still try to recover. */
126+
memory_device_plug(md, ms);
127+
error_propagate(errp, local_err);
128+
return;
129+
}
130+
} else {
131+
/* Very unexpected, but let's just try to do the right thing. */
132+
warn_report("Unexpected unplug of virtio based memory device");
133+
qdev_unrealize(dev);
134+
}
135+
}
136+
137+
static const TypeInfo virtio_ccw_md_info = {
138+
.name = TYPE_VIRTIO_MD_CCW,
139+
.parent = TYPE_VIRTIO_CCW_DEVICE,
140+
.instance_size = sizeof(VirtIOMDCcw),
141+
.class_size = sizeof(VirtIOMDCcwClass),
142+
.abstract = true,
143+
.interfaces = (InterfaceInfo[]) {
144+
{ TYPE_MEMORY_DEVICE },
145+
{ }
146+
},
147+
};
148+
149+
static void virtio_ccw_md_register(void)
150+
{
151+
type_register_static(&virtio_ccw_md_info);
152+
}
153+
type_init(virtio_ccw_md_register)

hw/s390x/virtio-ccw-md.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Virtio CCW support for abstract virtio based memory device
3+
*
4+
* Copyright (C) 2024 Red Hat, Inc.
5+
*
6+
* Authors:
7+
* David Hildenbrand <[email protected]>
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+
#ifndef HW_S390X_VIRTIO_CCW_MD_H
14+
#define HW_S390X_VIRTIO_CCW_MD_H
15+
16+
#include "virtio-ccw.h"
17+
#include "qom/object.h"
18+
19+
/*
20+
* virtio-md-ccw: This extends VirtioCcwDevice.
21+
*/
22+
#define TYPE_VIRTIO_MD_CCW "virtio-md-ccw"
23+
24+
OBJECT_DECLARE_TYPE(VirtIOMDCcw, VirtIOMDCcwClass, VIRTIO_MD_CCW)
25+
26+
struct VirtIOMDCcwClass {
27+
/* private */
28+
VirtIOCCWDeviceClass parent;
29+
30+
/* public */
31+
void (*unplug_request_check)(VirtIOMDCcw *vmd, Error **errp);
32+
};
33+
34+
struct VirtIOMDCcw {
35+
VirtioCcwDevice parent_obj;
36+
};
37+
38+
void virtio_ccw_md_pre_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp);
39+
void virtio_ccw_md_plug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp);
40+
void virtio_ccw_md_unplug_request(VirtIOMDCcw *vmd, MachineState *ms,
41+
Error **errp);
42+
void virtio_ccw_md_unplug(VirtIOMDCcw *vmd, MachineState *ms, Error **errp);
43+
44+
#endif /* HW_S390X_VIRTIO_CCW_MD_H */

hw/virtio/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ config VIRTIO_MMIO
2929
config VIRTIO_CCW
3030
bool
3131
select VIRTIO
32+
select VIRTIO_MD_SUPPORTED
3233

3334
config VIRTIO_BALLOON
3435
bool

0 commit comments

Comments
 (0)