aboutsummaryrefslogtreecommitdiff
path: root/hw/s390x
diff options
context:
space:
mode:
Diffstat (limited to 'hw/s390x')
-rw-r--r--hw/s390x/Kconfig5
-rw-r--r--hw/s390x/ap-bridge.c2
-rw-r--r--hw/s390x/ccw-device.c2
-rw-r--r--hw/s390x/cpu-topology.c469
-rw-r--r--hw/s390x/css-bridge.c14
-rw-r--r--hw/s390x/css.c90
-rw-r--r--hw/s390x/event-facility.c17
-rw-r--r--hw/s390x/ipl.c91
-rw-r--r--hw/s390x/ipl.h4
-rw-r--r--hw/s390x/meson.build4
-rw-r--r--hw/s390x/pv.c174
-rw-r--r--hw/s390x/s390-ccw.c9
-rw-r--r--hw/s390x/s390-pci-bus.c188
-rw-r--r--hw/s390x/s390-pci-inst.c200
-rw-r--r--hw/s390x/s390-pci-kvm.c82
-rw-r--r--hw/s390x/s390-pci-vfio.c140
-rw-r--r--hw/s390x/s390-skeys.c38
-rw-r--r--hw/s390x/s390-stattrib-kvm.c12
-rw-r--r--hw/s390x/s390-stattrib.c80
-rw-r--r--hw/s390x/s390-virtio-ccw.c358
-rw-r--r--hw/s390x/sclp.c14
-rw-r--r--hw/s390x/sclpcpu.c4
-rw-r--r--hw/s390x/sclpquiesce.c10
-rw-r--r--hw/s390x/tod-kvm.c11
-rw-r--r--hw/s390x/tod-tcg.c4
-rw-r--r--hw/s390x/tod.c2
-rw-r--r--hw/s390x/trace-events17
-rw-r--r--hw/s390x/vhost-scsi-ccw.c73
-rw-r--r--hw/s390x/vhost-vsock-ccw.c9
-rw-r--r--hw/s390x/virtio-ccw-9p.c9
-rw-r--r--hw/s390x/virtio-ccw-balloon.c9
-rw-r--r--hw/s390x/virtio-ccw-blk.c9
-rw-r--r--hw/s390x/virtio-ccw-crypto.c9
-rw-r--r--hw/s390x/virtio-ccw-gpu.c10
-rw-r--r--hw/s390x/virtio-ccw-input.c20
-rw-r--r--hw/s390x/virtio-ccw-net.c9
-rw-r--r--hw/s390x/virtio-ccw-rng.c9
-rw-r--r--hw/s390x/virtio-ccw-scsi.c56
-rw-r--r--hw/s390x/virtio-ccw-serial.c8
-rw-r--r--hw/s390x/virtio-ccw.c27
-rw-r--r--hw/s390x/virtio-ccw.h149
41 files changed, 1702 insertions, 745 deletions
diff --git a/hw/s390x/Kconfig b/hw/s390x/Kconfig
index 5e7d8a2bae..26ad104485 100644
--- a/hw/s390x/Kconfig
+++ b/hw/s390x/Kconfig
@@ -5,8 +5,11 @@ config S390_CCW_VIRTIO
imply VFIO_AP
imply VFIO_CCW
imply WDT_DIAG288
- select PCI
+ imply PCIE_DEVICES
+ imply IOMMUFD
+ select PCI_EXPRESS
select S390_FLIC
+ select S390_FLIC_KVM if KVM
select SCLPCONSOLE
select VIRTIO_CCW
select MSI_NONBROKEN
diff --git a/hw/s390x/ap-bridge.c b/hw/s390x/ap-bridge.c
index 8bcf8ece9d..ef8fa2b15b 100644
--- a/hw/s390x/ap-bridge.c
+++ b/hw/s390x/ap-bridge.c
@@ -55,7 +55,7 @@ void s390_init_ap(void)
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
/* Create bus on bridge device */
- bus = qbus_create(TYPE_AP_BUS, dev, TYPE_AP_BUS);
+ bus = qbus_new(TYPE_AP_BUS, dev, TYPE_AP_BUS);
/* Enable hotplugging */
qbus_set_hotplug_handler(bus, OBJECT(dev));
diff --git a/hw/s390x/ccw-device.c b/hw/s390x/ccw-device.c
index 95f269ab44..fb8c1acc64 100644
--- a/hw/s390x/ccw-device.c
+++ b/hw/s390x/ccw-device.c
@@ -66,7 +66,7 @@ const VMStateDescription vmstate_ccw_dev = {
.name = "s390_ccw_dev",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_STRUCT_POINTER(sch, CcwDevice, vmstate_subch_dev, SubchDev),
VMSTATE_END_OF_LIST()
}
diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c
new file mode 100644
index 0000000000..f16bdf65fa
--- /dev/null
+++ b/hw/s390x/cpu-topology.c
@@ -0,0 +1,469 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * CPU Topology
+ *
+ * Copyright IBM Corp. 2022, 2023
+ * Author(s): Pierre Morel <pmorel@linux.ibm.com>
+ *
+ * S390 topology handling can be divided in two parts:
+ *
+ * - The first part in this file is taking care of all common functions
+ * used by KVM and TCG to create and modify the topology.
+ *
+ * - The second part, building the topology information data for the
+ * guest with CPU and KVM specificity will be implemented inside
+ * the target/s390/kvm sub tree.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/error-report.h"
+#include "hw/qdev-properties.h"
+#include "hw/boards.h"
+#include "target/s390x/cpu.h"
+#include "hw/s390x/s390-virtio-ccw.h"
+#include "hw/s390x/cpu-topology.h"
+#include "qapi/qapi-commands-machine-target.h"
+#include "qapi/qapi-events-machine-target.h"
+
+/*
+ * s390_topology is used to keep the topology information.
+ * .cores_per_socket: tracks information on the count of cores
+ * per socket.
+ * .polarization: tracks machine polarization.
+ */
+S390Topology s390_topology = {
+ /* will be initialized after the CPU model is realized */
+ .cores_per_socket = NULL,
+ .polarization = S390_CPU_POLARIZATION_HORIZONTAL,
+};
+
+/**
+ * s390_socket_nb:
+ * @cpu: s390x CPU
+ *
+ * Returns the socket number used inside the cores_per_socket array
+ * for a topology tree entry
+ */
+static int s390_socket_nb_from_ids(int drawer_id, int book_id, int socket_id)
+{
+ return (drawer_id * current_machine->smp.books + book_id) *
+ current_machine->smp.sockets + socket_id;
+}
+
+/**
+ * s390_socket_nb:
+ * @cpu: s390x CPU
+ *
+ * Returns the socket number used inside the cores_per_socket array
+ * for a cpu.
+ */
+static int s390_socket_nb(S390CPU *cpu)
+{
+ return s390_socket_nb_from_ids(cpu->env.drawer_id, cpu->env.book_id,
+ cpu->env.socket_id);
+}
+
+/**
+ * s390_has_topology:
+ *
+ * Return: true if the topology is supported by the machine.
+ */
+bool s390_has_topology(void)
+{
+ return s390_has_feat(S390_FEAT_CONFIGURATION_TOPOLOGY);
+}
+
+/**
+ * s390_topology_init:
+ * @ms: the machine state where the machine topology is defined
+ *
+ * Keep track of the machine topology.
+ *
+ * Allocate an array to keep the count of cores per socket.
+ * The index of the array starts at socket 0 from book 0 and
+ * drawer 0 up to the maximum allowed by the machine topology.
+ */
+static void s390_topology_init(MachineState *ms)
+{
+ CpuTopology *smp = &ms->smp;
+
+ s390_topology.cores_per_socket = g_new0(uint8_t, smp->sockets *
+ smp->books * smp->drawers);
+}
+
+/*
+ * s390_handle_ptf:
+ *
+ * @register 1: contains the function code
+ *
+ * Function codes 0 (horizontal) and 1 (vertical) define the CPU
+ * polarization requested by the guest.
+ *
+ * Function code 2 is handling topology changes and is interpreted
+ * by the SIE.
+ */
+void s390_handle_ptf(S390CPU *cpu, uint8_t r1, uintptr_t ra)
+{
+ CpuS390Polarization polarization;
+ CPUS390XState *env = &cpu->env;
+ uint64_t reg = env->regs[r1];
+ int fc = reg & S390_TOPO_FC_MASK;
+
+ if (!s390_has_feat(S390_FEAT_CONFIGURATION_TOPOLOGY)) {
+ s390_program_interrupt(env, PGM_OPERATION, ra);
+ return;
+ }
+
+ if (env->psw.mask & PSW_MASK_PSTATE) {
+ s390_program_interrupt(env, PGM_PRIVILEGED, ra);
+ return;
+ }
+
+ if (reg & ~S390_TOPO_FC_MASK) {
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ return;
+ }
+
+ polarization = S390_CPU_POLARIZATION_VERTICAL;
+ switch (fc) {
+ case 0:
+ polarization = S390_CPU_POLARIZATION_HORIZONTAL;
+ /* fallthrough */
+ case 1:
+ if (s390_topology.polarization == polarization) {
+ env->regs[r1] |= S390_PTF_REASON_DONE;
+ setcc(cpu, 2);
+ } else {
+ s390_topology.polarization = polarization;
+ s390_cpu_topology_set_changed(true);
+ qapi_event_send_cpu_polarization_change(polarization);
+ setcc(cpu, 0);
+ }
+ break;
+ default:
+ /* Note that fc == 2 is interpreted by the SIE */
+ s390_program_interrupt(env, PGM_SPECIFICATION, ra);
+ }
+}
+
+/**
+ * s390_topology_reset:
+ *
+ * Generic reset for CPU topology, calls s390_topology_reset()
+ * to reset the kernel Modified Topology Change Record.
+ */
+void s390_topology_reset(void)
+{
+ s390_cpu_topology_set_changed(false);
+ s390_topology.polarization = S390_CPU_POLARIZATION_HORIZONTAL;
+}
+
+/**
+ * s390_topology_cpu_default:
+ * @cpu: pointer to a S390CPU
+ * @errp: Error pointer
+ *
+ * Setup the default topology if no attributes are already set.
+ * Passing a CPU with some, but not all, attributes set is considered
+ * an error.
+ *
+ * The function calculates the (drawer_id, book_id, socket_id)
+ * topology by filling the cores starting from the first socket
+ * (0, 0, 0) up to the last (smp->drawers, smp->books, smp->sockets).
+ *
+ * CPU type and dedication have defaults values set in the
+ * s390x_cpu_properties, entitlement must be adjust depending on the
+ * dedication.
+ *
+ * Returns false if it is impossible to setup a default topology
+ * true otherwise.
+ */
+static bool s390_topology_cpu_default(S390CPU *cpu, Error **errp)
+{
+ CpuTopology *smp = &current_machine->smp;
+ CPUS390XState *env = &cpu->env;
+
+ /* All geometry topology attributes must be set or all unset */
+ if ((env->socket_id < 0 || env->book_id < 0 || env->drawer_id < 0) &&
+ (env->socket_id >= 0 || env->book_id >= 0 || env->drawer_id >= 0)) {
+ error_setg(errp,
+ "Please define all or none of the topology geometry attributes");
+ return false;
+ }
+
+ /* If one value is unset all are unset -> calculate defaults */
+ if (env->socket_id < 0) {
+ env->socket_id = s390_std_socket(env->core_id, smp);
+ env->book_id = s390_std_book(env->core_id, smp);
+ env->drawer_id = s390_std_drawer(env->core_id, smp);
+ }
+
+ /*
+ * When the user specifies the entitlement as 'auto' on the command line,
+ * QEMU will set the entitlement as:
+ * Medium when the CPU is not dedicated.
+ * High when dedicated is true.
+ */
+ if (env->entitlement == S390_CPU_ENTITLEMENT_AUTO) {
+ if (env->dedicated) {
+ env->entitlement = S390_CPU_ENTITLEMENT_HIGH;
+ } else {
+ env->entitlement = S390_CPU_ENTITLEMENT_MEDIUM;
+ }
+ }
+ return true;
+}
+
+/**
+ * s390_topology_check:
+ * @socket_id: socket to check
+ * @book_id: book to check
+ * @drawer_id: drawer to check
+ * @entitlement: entitlement to check
+ * @dedicated: dedication to check
+ * @errp: Error pointer
+ *
+ * The function checks if the topology
+ * attributes fits inside the system topology.
+ *
+ * Returns false if the specified topology does not match with
+ * the machine topology.
+ */
+static bool s390_topology_check(uint16_t socket_id, uint16_t book_id,
+ uint16_t drawer_id, uint16_t entitlement,
+ bool dedicated, Error **errp)
+{
+ CpuTopology *smp = &current_machine->smp;
+
+ if (socket_id >= smp->sockets) {
+ error_setg(errp, "Unavailable socket: %d", socket_id);
+ return false;
+ }
+ if (book_id >= smp->books) {
+ error_setg(errp, "Unavailable book: %d", book_id);
+ return false;
+ }
+ if (drawer_id >= smp->drawers) {
+ error_setg(errp, "Unavailable drawer: %d", drawer_id);
+ return false;
+ }
+ if (entitlement >= S390_CPU_ENTITLEMENT__MAX) {
+ error_setg(errp, "Unknown entitlement: %d", entitlement);
+ return false;
+ }
+ if (dedicated && (entitlement == S390_CPU_ENTITLEMENT_LOW ||
+ entitlement == S390_CPU_ENTITLEMENT_MEDIUM)) {
+ error_setg(errp, "A dedicated CPU implies high entitlement");
+ return false;
+ }
+ return true;
+}
+
+/**
+ * s390_topology_need_report
+ * @cpu: Current cpu
+ * @drawer_id: future drawer ID
+ * @book_id: future book ID
+ * @socket_id: future socket ID
+ * @entitlement: future entitlement
+ * @dedicated: future dedicated
+ *
+ * A modified topology change report is needed if the topology
+ * tree or the topology attributes change.
+ */
+static bool s390_topology_need_report(S390CPU *cpu, int drawer_id,
+ int book_id, int socket_id,
+ uint16_t entitlement, bool dedicated)
+{
+ return cpu->env.drawer_id != drawer_id ||
+ cpu->env.book_id != book_id ||
+ cpu->env.socket_id != socket_id ||
+ cpu->env.entitlement != entitlement ||
+ cpu->env.dedicated != dedicated;
+}
+
+/**
+ * s390_update_cpu_props:
+ * @ms: the machine state
+ * @cpu: the CPU for which to update the properties from the environment.
+ *
+ */
+static void s390_update_cpu_props(MachineState *ms, S390CPU *cpu)
+{
+ CpuInstanceProperties *props;
+
+ props = &ms->possible_cpus->cpus[cpu->env.core_id].props;
+
+ props->socket_id = cpu->env.socket_id;
+ props->book_id = cpu->env.book_id;
+ props->drawer_id = cpu->env.drawer_id;
+}
+
+/**
+ * s390_topology_setup_cpu:
+ * @ms: MachineState used to initialize the topology structure on
+ * first call.
+ * @cpu: the new S390CPU to insert in the topology structure
+ * @errp: the error pointer
+ *
+ * Called from CPU hotplug to check and setup the CPU attributes
+ * before the CPU is inserted in the topology.
+ * There is no need to update the MTCR explicitly here because it
+ * will be updated by KVM on creation of the new CPU.
+ */
+void s390_topology_setup_cpu(MachineState *ms, S390CPU *cpu, Error **errp)
+{
+ int entry;
+
+ /*
+ * We do not want to initialize the topology if the CPU model
+ * does not support topology, consequently, we have to wait for
+ * the first CPU to be realized, which realizes the CPU model
+ * to initialize the topology structures.
+ *
+ * s390_topology_setup_cpu() is called from the CPU hotplug.
+ */
+ if (!s390_topology.cores_per_socket) {
+ s390_topology_init(ms);
+ }
+
+ if (!s390_topology_cpu_default(cpu, errp)) {
+ return;
+ }
+
+ if (!s390_topology_check(cpu->env.socket_id, cpu->env.book_id,
+ cpu->env.drawer_id, cpu->env.entitlement,
+ cpu->env.dedicated, errp)) {
+ return;
+ }
+
+ /* Do we still have space in the socket */
+ entry = s390_socket_nb(cpu);
+ if (s390_topology.cores_per_socket[entry] >= ms->smp.cores) {
+ error_setg(errp, "No more space on this socket");
+ return;
+ }
+
+ /* Update the count of cores in sockets */
+ s390_topology.cores_per_socket[entry] += 1;
+
+ /* topology tree is reflected in props */
+ s390_update_cpu_props(ms, cpu);
+}
+
+static void s390_change_topology(uint16_t core_id,
+ bool has_socket_id, uint16_t socket_id,
+ bool has_book_id, uint16_t book_id,
+ bool has_drawer_id, uint16_t drawer_id,
+ bool has_entitlement,
+ CpuS390Entitlement entitlement,
+ bool has_dedicated, bool dedicated,
+ Error **errp)
+{
+ MachineState *ms = current_machine;
+ int old_socket_entry;
+ int new_socket_entry;
+ bool report_needed;
+ S390CPU *cpu;
+
+ cpu = s390_cpu_addr2state(core_id);
+ if (!cpu) {
+ error_setg(errp, "Core-id %d does not exist!", core_id);
+ return;
+ }
+
+ /* Get attributes not provided from cpu and verify the new topology */
+ if (!has_socket_id) {
+ socket_id = cpu->env.socket_id;
+ }
+ if (!has_book_id) {
+ book_id = cpu->env.book_id;
+ }
+ if (!has_drawer_id) {
+ drawer_id = cpu->env.drawer_id;
+ }
+ if (!has_dedicated) {
+ dedicated = cpu->env.dedicated;
+ }
+
+ /*
+ * When the user specifies the entitlement as 'auto' on the command line,
+ * QEMU will set the entitlement as:
+ * Medium when the CPU is not dedicated.
+ * High when dedicated is true.
+ */
+ if (!has_entitlement || entitlement == S390_CPU_ENTITLEMENT_AUTO) {
+ if (dedicated) {
+ entitlement = S390_CPU_ENTITLEMENT_HIGH;
+ } else {
+ entitlement = S390_CPU_ENTITLEMENT_MEDIUM;
+ }
+ }
+
+ if (!s390_topology_check(socket_id, book_id, drawer_id,
+ entitlement, dedicated, errp)) {
+ return;
+ }
+
+ /* Check for space on new socket */
+ old_socket_entry = s390_socket_nb(cpu);
+ new_socket_entry = s390_socket_nb_from_ids(drawer_id, book_id, socket_id);
+
+ if (new_socket_entry != old_socket_entry) {
+ if (s390_topology.cores_per_socket[new_socket_entry] >=
+ ms->smp.cores) {
+ error_setg(errp, "No more space on this socket");
+ return;
+ }
+ /* Update the count of cores in sockets */
+ s390_topology.cores_per_socket[new_socket_entry] += 1;
+ s390_topology.cores_per_socket[old_socket_entry] -= 1;
+ }
+
+ /* Check if we will need to report the modified topology */
+ report_needed = s390_topology_need_report(cpu, drawer_id, book_id,
+ socket_id, entitlement,
+ dedicated);
+
+ /* All checks done, report new topology into the vCPU */
+ cpu->env.drawer_id = drawer_id;
+ cpu->env.book_id = book_id;
+ cpu->env.socket_id = socket_id;
+ cpu->env.dedicated = dedicated;
+ cpu->env.entitlement = entitlement;
+
+ /* topology tree is reflected in props */
+ s390_update_cpu_props(ms, cpu);
+
+ /* Advertise the topology change */
+ if (report_needed) {
+ s390_cpu_topology_set_changed(true);
+ }
+}
+
+void qmp_set_cpu_topology(uint16_t core,
+ bool has_socket, uint16_t socket,
+ bool has_book, uint16_t book,
+ bool has_drawer, uint16_t drawer,
+ bool has_entitlement, CpuS390Entitlement entitlement,
+ bool has_dedicated, bool dedicated,
+ Error **errp)
+{
+ if (!s390_has_topology()) {
+ error_setg(errp, "This machine doesn't support topology");
+ return;
+ }
+
+ s390_change_topology(core, has_socket, socket, has_book, book,
+ has_drawer, drawer, has_entitlement, entitlement,
+ has_dedicated, dedicated, errp);
+}
+
+CpuPolarizationInfo *qmp_query_s390x_cpu_polarization(Error **errp)
+{
+ CpuPolarizationInfo *info = g_new0(CpuPolarizationInfo, 1);
+
+ info->polarization = s390_topology.polarization;
+ return info;
+}
diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c
index 191b29f077..34639f2143 100644
--- a/hw/s390x/css-bridge.c
+++ b/hw/s390x/css-bridge.c
@@ -56,7 +56,7 @@ static void ccw_device_unplug(HotplugHandler *hotplug_dev,
qdev_unrealize(dev);
}
-static void virtual_css_bus_reset(BusState *qbus)
+static void virtual_css_bus_reset_hold(Object *obj)
{
/* This should actually be modelled via the generic css */
css_reset();
@@ -81,8 +81,9 @@ static char *virtual_css_bus_get_dev_path(DeviceState *dev)
static void virtual_css_bus_class_init(ObjectClass *klass, void *data)
{
BusClass *k = BUS_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
- k->reset = virtual_css_bus_reset;
+ rc->phases.hold = virtual_css_bus_reset_hold;
k->get_dev_path = virtual_css_bus_get_dev_path;
}
@@ -95,7 +96,6 @@ static const TypeInfo virtual_css_bus_info = {
VirtualCssBus *virtual_css_bus_init(void)
{
- VirtualCssBus *cbus;
BusState *bus;
DeviceState *dev;
@@ -103,19 +103,19 @@ VirtualCssBus *virtual_css_bus_init(void)
dev = qdev_new(TYPE_VIRTUAL_CSS_BRIDGE);
object_property_add_child(qdev_get_machine(), TYPE_VIRTUAL_CSS_BRIDGE,
OBJECT(dev));
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
/* Create bus on bridge device */
- bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
- cbus = VIRTUAL_CSS_BUS(bus);
+ bus = qbus_new(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css");
/* Enable hotplugging */
qbus_set_hotplug_handler(bus, OBJECT(dev));
+ sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
css_register_io_adapters(CSS_IO_ADAPTER_VIRTIO, true, false,
0, &error_abort);
- return cbus;
+ return VIRTUAL_CSS_BUS(bus);
}
/***************** Virtual-css Bus Bridge Device ********************/
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 7d9523f811..295530963a 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -32,7 +32,7 @@ static const VMStateDescription vmstate_crw = {
.name = "s390_crw",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT16(flags, CRW),
VMSTATE_UINT16(rsid, CRW),
VMSTATE_END_OF_LIST()
@@ -43,7 +43,7 @@ static const VMStateDescription vmstate_crw_container = {
.name = "s390_crw_container",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_STRUCT(crw, CrwContainer, 0, vmstate_crw, CRW),
VMSTATE_END_OF_LIST()
},
@@ -59,7 +59,7 @@ static const VMStateDescription vmstate_chp_info = {
.name = "s390_chp_info",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT8(in_use, ChpInfo),
VMSTATE_UINT8(type, ChpInfo),
VMSTATE_UINT8(is_virtual, ChpInfo),
@@ -77,7 +77,7 @@ static const VMStateDescription vmstate_scsw = {
.name = "s390_scsw",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT16(flags, SCSW),
VMSTATE_UINT16(ctrl, SCSW),
VMSTATE_UINT32(cpa, SCSW),
@@ -92,7 +92,7 @@ static const VMStateDescription vmstate_pmcw = {
.name = "s390_pmcw",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32(intparm, PMCW),
VMSTATE_UINT16(flags, PMCW),
VMSTATE_UINT16(devno, PMCW),
@@ -113,7 +113,7 @@ static const VMStateDescription vmstate_schib = {
.name = "s390_schib",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_STRUCT(pmcw, SCHIB, 0, vmstate_pmcw, PMCW),
VMSTATE_STRUCT(scsw, SCHIB, 0, vmstate_scsw, SCSW),
VMSTATE_UINT64(mba, SCHIB),
@@ -127,7 +127,7 @@ static const VMStateDescription vmstate_ccw1 = {
.name = "s390_ccw1",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT8(cmd_code, CCW1),
VMSTATE_UINT8(flags, CCW1),
VMSTATE_UINT16(count, CCW1),
@@ -140,7 +140,7 @@ static const VMStateDescription vmstate_ciw = {
.name = "s390_ciw",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT8(type, CIW),
VMSTATE_UINT8(command, CIW),
VMSTATE_UINT16(count, CIW),
@@ -152,7 +152,7 @@ static const VMStateDescription vmstate_sense_id = {
.name = "s390_sense_id",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT8(reserved, SenseId),
VMSTATE_UINT16(cu_type, SenseId),
VMSTATE_UINT8(cu_model, SenseId),
@@ -168,7 +168,7 @@ static const VMStateDescription vmstate_orb = {
.name = "s390_orb",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32(intparm, ORB),
VMSTATE_UINT16(ctrl0, ORB),
VMSTATE_UINT8(lpm, ORB),
@@ -188,7 +188,7 @@ static const VMStateDescription vmstate_schdev_orb = {
.version_id = 1,
.minimum_version_id = 1,
.needed = vmstate_schdev_orb_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_STRUCT(orb, SubchDev, 1, vmstate_orb, ORB),
VMSTATE_END_OF_LIST()
}
@@ -207,7 +207,7 @@ const VMStateDescription vmstate_subch_dev = {
.minimum_version_id = 1,
.post_load = subch_dev_post_load,
.pre_save = subch_dev_pre_save,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT8_EQUAL(cssid, SubchDev, "Bug!"),
VMSTATE_UINT8_EQUAL(ssid, SubchDev, "Bug!"),
VMSTATE_UINT16(migrated_schid, SubchDev),
@@ -223,7 +223,7 @@ const VMStateDescription vmstate_subch_dev = {
VMSTATE_UINT8(ccw_no_data_cnt, SubchDev),
VMSTATE_END_OF_LIST()
},
- .subsections = (const VMStateDescription * []) {
+ .subsections = (const VMStateDescription * const []) {
&vmstate_schdev_orb,
NULL
}
@@ -264,12 +264,12 @@ static int pre_save_ind_addr(void *opaque)
return 0;
}
-const VMStateDescription vmstate_ind_addr_tmp = {
+static const VMStateDescription vmstate_ind_addr_tmp = {
.name = "s390_ind_addr_tmp",
.pre_save = pre_save_ind_addr,
.post_load = post_load_ind_addr,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_INT32(len, IndAddrPtrTmp),
VMSTATE_UINT64(addr, IndAddrPtrTmp),
VMSTATE_END_OF_LIST()
@@ -278,7 +278,7 @@ const VMStateDescription vmstate_ind_addr_tmp = {
const VMStateDescription vmstate_ind_addr = {
.name = "s390_ind_addr_tmp",
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_WITH_TMP(IndAddr*, IndAddrPtrTmp, vmstate_ind_addr_tmp),
VMSTATE_END_OF_LIST()
}
@@ -293,7 +293,7 @@ static const VMStateDescription vmstate_css_img = {
.name = "s390_css_img",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
/* Subchannel sets have no relevant state. */
VMSTATE_STRUCT_ARRAY(chpids, CssImage, MAX_CHPID + 1, 0,
vmstate_chp_info, ChpInfo),
@@ -330,7 +330,7 @@ static const VMStateDescription vmstate_css = {
.name = "s390_css",
.version_id = 1,
.minimum_version_id = 1,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_QTAILQ_V(pending_crws, ChannelSubSys, 1, vmstate_crw_container,
CrwContainer, sibling),
VMSTATE_BOOL(sei_pending, ChannelSubSys),
@@ -644,8 +644,9 @@ void css_conditional_io_interrupt(SubchDev *sch)
}
}
-int css_do_sic(CPUS390XState *env, uint8_t isc, uint16_t mode)
+int css_do_sic(S390CPU *cpu, uint8_t isc, uint16_t mode)
{
+ CPUS390XState *env = &cpu->env;
S390FLICState *fs = s390_get_flic();
S390FLICStateClass *fsc = s390_get_flic_class(fs);
int r;
@@ -1522,21 +1523,37 @@ IOInstEnding css_do_xsch(SubchDev *sch)
IOInstEnding css_do_csch(SubchDev *sch)
{
SCHIB *schib = &sch->curr_status;
+ uint16_t old_scsw_ctrl;
+ IOInstEnding ccode;
if (~(schib->pmcw.flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
return IOINST_CC_NOT_OPERATIONAL;
}
+ /*
+ * Save the current scsw.ctrl in case CSCH fails and we need
+ * to revert the scsw to the status quo ante.
+ */
+ old_scsw_ctrl = schib->scsw.ctrl;
+
/* Trigger the clear function. */
schib->scsw.ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL);
schib->scsw.ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_ACTL_CLEAR_PEND;
- return do_subchannel_work(sch);
+ ccode = do_subchannel_work(sch);
+
+ if (ccode != IOINST_CC_EXPECTED) {
+ schib->scsw.ctrl = old_scsw_ctrl;
+ }
+
+ return ccode;
}
IOInstEnding css_do_hsch(SubchDev *sch)
{
SCHIB *schib = &sch->curr_status;
+ uint16_t old_scsw_ctrl;
+ IOInstEnding ccode;
if (~(schib->pmcw.flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
return IOINST_CC_NOT_OPERATIONAL;
@@ -1553,6 +1570,12 @@ IOInstEnding css_do_hsch(SubchDev *sch)
return IOINST_CC_BUSY;
}
+ /*
+ * Save the current scsw.ctrl in case HSCH fails and we need
+ * to revert the scsw to the status quo ante.
+ */
+ old_scsw_ctrl = schib->scsw.ctrl;
+
/* Trigger the halt function. */
schib->scsw.ctrl |= SCSW_FCTL_HALT_FUNC;
schib->scsw.ctrl &= ~SCSW_FCTL_START_FUNC;
@@ -1564,7 +1587,13 @@ IOInstEnding css_do_hsch(SubchDev *sch)
}
schib->scsw.ctrl |= SCSW_ACTL_HALT_PEND;
- return do_subchannel_work(sch);
+ ccode = do_subchannel_work(sch);
+
+ if (ccode != IOINST_CC_EXPECTED) {
+ schib->scsw.ctrl = old_scsw_ctrl;
+ }
+
+ return ccode;
}
static void css_update_chnmon(SubchDev *sch)
@@ -1605,6 +1634,8 @@ static void css_update_chnmon(SubchDev *sch)
IOInstEnding css_do_ssch(SubchDev *sch, ORB *orb)
{
SCHIB *schib = &sch->curr_status;
+ uint16_t old_scsw_ctrl, old_scsw_flags;
+ IOInstEnding ccode;
if (~(schib->pmcw.flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) {
return IOINST_CC_NOT_OPERATIONAL;
@@ -1626,11 +1657,26 @@ IOInstEnding css_do_ssch(SubchDev *sch, ORB *orb)
}
sch->orb = *orb;
sch->channel_prog = orb->cpa;
+
+ /*
+ * Save the current scsw.ctrl and scsw.flags in case SSCH fails and we need
+ * to revert the scsw to the status quo ante.
+ */
+ old_scsw_ctrl = schib->scsw.ctrl;
+ old_scsw_flags = schib->scsw.flags;
+
/* Trigger the start function. */
schib->scsw.ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND);
schib->scsw.flags &= ~SCSW_FLAGS_MASK_PNO;
- return do_subchannel_work(sch);
+ ccode = do_subchannel_work(sch);
+
+ if (ccode != IOINST_CC_EXPECTED) {
+ schib->scsw.ctrl = old_scsw_ctrl;
+ schib->scsw.flags = old_scsw_flags;
+ }
+
+ return ccode;
}
static void copy_irb_to_guest(IRB *dest, const IRB *src, const PMCW *pmcw,
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index ed92ce510d..f9829de953 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -28,7 +28,7 @@ typedef struct SCLPEventsBus {
} SCLPEventsBus;
/* we need to save 32 bit chunks for compatibility */
-#ifdef HOST_WORDS_BIGENDIAN
+#if HOST_BIG_ENDIAN
#define RECV_MASK_LOWER 1
#define RECV_MASK_UPPER 0
#else /* little endian host */
@@ -64,8 +64,7 @@ static bool event_pending(SCLPEventFacility *ef)
SCLPEventClass *event_class;
QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
- DeviceState *qdev = kid->child;
- event = DO_UPCAST(SCLPEvent, qdev, qdev);
+ event = SCLP_EVENT(kid->child);
event_class = SCLP_EVENT_GET_CLASS(event);
if (event->event_pending &&
event_class->get_send_mask() & ef->receive_mask) {
@@ -368,7 +367,7 @@ static const VMStateDescription vmstate_event_facility_mask64 = {
.version_id = 0,
.minimum_version_id = 0,
.needed = vmstate_event_facility_mask64_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32(receive_mask_pieces[RECV_MASK_LOWER], SCLPEventFacility),
VMSTATE_END_OF_LIST()
}
@@ -379,7 +378,7 @@ static const VMStateDescription vmstate_event_facility_mask_length = {
.version_id = 0,
.minimum_version_id = 0,
.needed = vmstate_event_facility_mask_length_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT16(mask_length, SCLPEventFacility),
VMSTATE_END_OF_LIST()
}
@@ -389,11 +388,11 @@ static const VMStateDescription vmstate_event_facility = {
.name = "vmstate-event-facility",
.version_id = 0,
.minimum_version_id = 0,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT32(receive_mask_pieces[RECV_MASK_UPPER], SCLPEventFacility),
VMSTATE_END_OF_LIST()
},
- .subsections = (const VMStateDescription * []) {
+ .subsections = (const VMStateDescription * const []) {
&vmstate_event_facility_mask64,
&vmstate_event_facility_mask_length,
NULL
@@ -427,8 +426,8 @@ static void init_event_facility(Object *obj)
sclp_event_set_allow_all_mask_sizes);
/* Spawn a new bus for SCLP events */
- qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
- TYPE_SCLP_EVENTS_BUS, sdev, NULL);
+ qbus_init(&event_facility->sbus, sizeof(event_facility->sbus),
+ TYPE_SCLP_EVENTS_BUS, sdev, NULL);
object_initialize_child(obj, TYPE_SCLP_QUIESCE,
&event_facility->quiesce,
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 1821c6faee..e934bf89d1 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -13,7 +13,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qemu/datadir.h"
#include "qapi/error.h"
#include "sysemu/reset.h"
@@ -27,17 +26,21 @@
#include "hw/s390x/vfio-ccw.h"
#include "hw/s390x/css.h"
#include "hw/s390x/ebcdic.h"
-#include "hw/s390x/pv.h"
+#include "target/s390x/kvm/pv.h"
+#include "hw/scsi/scsi.h"
+#include "hw/virtio/virtio-net.h"
#include "ipl.h"
#include "qemu/error-report.h"
#include "qemu/config-file.h"
#include "qemu/cutils.h"
#include "qemu/option.h"
-#include "exec/exec-all.h"
+#include "standard-headers/linux/virtio_ids.h"
#define KERN_IMAGE_START 0x010000UL
#define LINUX_MAGIC_ADDR 0x010008UL
+#define KERN_PARM_AREA_SIZE_ADDR 0x010430UL
#define KERN_PARM_AREA 0x010480UL
+#define LEGACY_KERN_PARM_AREA_SIZE 0x000380UL
#define INITRD_START 0x800000UL
#define INITRD_PARM_START 0x010408UL
#define PARMFILE_START 0x001000UL
@@ -56,7 +59,7 @@ static const VMStateDescription vmstate_iplb_extended = {
.version_id = 0,
.minimum_version_id = 0,
.needed = iplb_extended_needed,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT8_ARRAY(reserved_ext, IplParameterBlock, 4096 - 200),
VMSTATE_END_OF_LIST()
}
@@ -66,13 +69,13 @@ static const VMStateDescription vmstate_iplb = {
.name = "ipl/iplb",
.version_id = 0,
.minimum_version_id = 0,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT8_ARRAY(reserved1, IplParameterBlock, 110),
VMSTATE_UINT16(devno, IplParameterBlock),
VMSTATE_UINT8_ARRAY(reserved2, IplParameterBlock, 88),
VMSTATE_END_OF_LIST()
},
- .subsections = (const VMStateDescription*[]) {
+ .subsections = (const VMStateDescription * const []) {
&vmstate_iplb_extended,
NULL
}
@@ -82,7 +85,7 @@ static const VMStateDescription vmstate_ipl = {
.name = "ipl",
.version_id = 0,
.minimum_version_id = 0,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT64(compat_start_addr, S390IPLState),
VMSTATE_UINT64(compat_bios_start_addr, S390IPLState),
VMSTATE_STRUCT(iplb, S390IPLState, 0, vmstate_iplb, IplParameterBlock),
@@ -109,6 +112,21 @@ static uint64_t bios_translate_addr(void *opaque, uint64_t srcaddr)
return srcaddr + dstaddr;
}
+static uint64_t get_max_kernel_cmdline_size(void)
+{
+ uint64_t *size_ptr = rom_ptr(KERN_PARM_AREA_SIZE_ADDR, sizeof(*size_ptr));
+
+ if (size_ptr) {
+ uint64_t size;
+
+ size = be64_to_cpu(*size_ptr);
+ if (size) {
+ return size;
+ }
+ }
+ return LEGACY_KERN_PARM_AREA_SIZE;
+}
+
static void s390_ipl_realize(DeviceState *dev, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
@@ -190,10 +208,22 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
* loader) and it won't work. For this case we force it to 0x10000, too.
*/
if (pentry == KERN_IMAGE_START || pentry == 0x800) {
- char *parm_area = rom_ptr(KERN_PARM_AREA, strlen(ipl->cmdline) + 1);
+ size_t cmdline_size = strlen(ipl->cmdline) + 1;
+ char *parm_area = rom_ptr(KERN_PARM_AREA, cmdline_size);
+
ipl->start_addr = KERN_IMAGE_START;
/* Overwrite parameters in the kernel image, which are "rom" */
if (parm_area) {
+ uint64_t max_cmdline_size = get_max_kernel_cmdline_size();
+
+ if (cmdline_size > max_cmdline_size) {
+ error_setg(errp,
+ "kernel command line exceeds maximum size:"
+ " %zu > %" PRIu64,
+ cmdline_size, max_cmdline_size);
+ return;
+ }
+
strcpy(parm_area, ipl->cmdline);
}
} else {
@@ -259,13 +289,10 @@ static Property s390_ipl_properties[] = {
static void s390_ipl_set_boot_menu(S390IPLState *ipl)
{
- QemuOptsList *plist = qemu_find_opts("boot-opts");
- QemuOpts *opts = QTAILQ_FIRST(&plist->head);
- const char *tmp;
unsigned long splash_time = 0;
if (!get_boot_device(0)) {
- if (boot_menu) {
+ if (current_machine->boot_config.has_menu && current_machine->boot_config.menu) {
error_report("boot menu requires a bootindex to be specified for "
"the IPL device");
}
@@ -275,7 +302,7 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
switch (ipl->iplb.pbt) {
case S390_IPL_TYPE_CCW:
/* In the absence of -boot menu, use zipl parameters */
- if (!qemu_opt_get(opts, "menu")) {
+ if (!current_machine->boot_config.has_menu) {
ipl->qipl.qipl_flags |= QIPL_FLAG_BM_OPTS_ZIPL;
return;
}
@@ -283,26 +310,21 @@ static void s390_ipl_set_boot_menu(S390IPLState *ipl)
case S390_IPL_TYPE_QEMU_SCSI:
break;
default:
- if (boot_menu) {
+ if (current_machine->boot_config.has_menu && current_machine->boot_config.menu) {
error_report("boot menu is not supported for this device type");
}
return;
}
- if (!boot_menu) {
+ if (!current_machine->boot_config.has_menu || !current_machine->boot_config.menu) {
return;
}
ipl->qipl.qipl_flags |= QIPL_FLAG_BM_OPTS_CMD;
- tmp = qemu_opt_get(opts, "splash-time");
-
- if (tmp && qemu_strtoul(tmp, NULL, 10, &splash_time)) {
- error_report("splash-time is invalid, forcing it to 0");
- ipl->qipl.boot_menu_timeout = 0;
- return;
+ if (current_machine->boot_config.has_splash_time) {
+ splash_time = current_machine->boot_config.splash_time;
}
-
if (splash_time > 0xffffffff) {
error_report("splash-time is too large, forcing it to max value");
ipl->qipl.boot_menu_timeout = 0xffffffff;
@@ -347,14 +369,18 @@ static CcwDevice *s390_get_ccw_device(DeviceState *dev_st, int *devtype)
object_dynamic_cast(OBJECT(dev_st),
TYPE_SCSI_DEVICE);
if (sd) {
- SCSIBus *bus = scsi_bus_from_device(sd);
- VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus);
- VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw,
- vdev);
-
- ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw),
- TYPE_CCW_DEVICE);
- tmp_dt = CCW_DEVTYPE_SCSI;
+ SCSIBus *sbus = scsi_bus_from_device(sd);
+ VirtIODevice *vdev = (VirtIODevice *)
+ object_dynamic_cast(OBJECT(sbus->qbus.parent),
+ TYPE_VIRTIO_DEVICE);
+ if (vdev) {
+ ccw_dev = (CcwDevice *)
+ object_dynamic_cast(OBJECT(qdev_get_parent_bus(DEVICE(vdev))->parent),
+ TYPE_CCW_DEVICE);
+ if (ccw_dev) {
+ tmp_dt = CCW_DEVTYPE_SCSI;
+ }
+ }
}
}
}
@@ -676,7 +702,7 @@ static void s390_ipl_prepare_qipl(S390CPU *cpu)
cpu_physical_memory_unmap(addr, len, 1, len);
}
-int s390_ipl_prepare_pv_header(void)
+int s390_ipl_prepare_pv_header(Error **errp)
{
IplParameterBlock *ipib = s390_ipl_get_iplb_pv();
IPLBlockPV *ipib_pv = &ipib->pv;
@@ -685,8 +711,7 @@ int s390_ipl_prepare_pv_header(void)
cpu_physical_memory_read(ipib_pv->pv_header_addr, hdr,
ipib_pv->pv_header_len);
- rc = s390_pv_set_sec_parms((uintptr_t)hdr,
- ipib_pv->pv_header_len);
+ rc = s390_pv_set_sec_parms((uintptr_t)hdr, ipib_pv->pv_header_len, errp);
g_free(hdr);
return rc;
}
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index dfc6dfd89c..57cd125769 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -107,7 +107,7 @@ typedef union IplParameterBlock IplParameterBlock;
int s390_ipl_set_loadparm(uint8_t *loadparm);
void s390_ipl_update_diag308(IplParameterBlock *iplb);
-int s390_ipl_prepare_pv_header(void);
+int s390_ipl_prepare_pv_header(Error **errp);
int s390_ipl_pv_unpack(void);
void s390_ipl_prepare_cpu(S390CPU *cpu);
IplParameterBlock *s390_ipl_get_iplb(void);
@@ -140,7 +140,7 @@ void s390_ipl_clear_reset_request(void);
* have an offset of 4 + n * 8 bytes within the struct in order
* to keep it double-word aligned.
* The total size of the struct must never exceed 28 bytes.
- * This definition must be kept in sync with the defininition
+ * This definition must be kept in sync with the definition
* in pc-bios/s390-ccw/iplb.h.
*/
struct QemuIplParameters {
diff --git a/hw/s390x/meson.build b/hw/s390x/meson.build
index 28484256ec..482fd13420 100644
--- a/hw/s390x/meson.build
+++ b/hw/s390x/meson.build
@@ -22,7 +22,8 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files(
'tod-kvm.c',
's390-skeys-kvm.c',
's390-stattrib-kvm.c',
- 'pv.c',
+ 's390-pci-kvm.c',
+ 'cpu-topology.c',
))
s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
'tod-tcg.c',
@@ -44,6 +45,7 @@ virtio_ss.add(when: 'CONFIG_VIRTIO_SERIAL', if_true: files('virtio-ccw-serial.c'
if have_virtfs
virtio_ss.add(when: 'CONFIG_VIRTIO_9P', if_true: files('virtio-ccw-9p.c'))
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'))
s390x_ss.add_all(when: 'CONFIG_VIRTIO_CCW', if_true: virtio_ss)
diff --git a/hw/s390x/pv.c b/hw/s390x/pv.c
deleted file mode 100644
index 401b63d6cb..0000000000
--- a/hw/s390x/pv.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Protected Virtualization functions
- *
- * Copyright IBM Corp. 2020
- * Author(s):
- * Janosch Frank <frankja@linux.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or (at
- * your option) any later version. See the COPYING file in the top-level
- * directory.
- */
-#include "qemu/osdep.h"
-
-#include <linux/kvm.h>
-
-#include "qapi/error.h"
-#include "qemu/error-report.h"
-#include "sysemu/kvm.h"
-#include "qom/object_interfaces.h"
-#include "exec/confidential-guest-support.h"
-#include "hw/s390x/ipl.h"
-#include "hw/s390x/pv.h"
-
-static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data)
-{
- struct kvm_pv_cmd pv_cmd = {
- .cmd = cmd,
- .data = (uint64_t)data,
- };
- int rc;
-
- do {
- rc = kvm_vm_ioctl(kvm_state, KVM_S390_PV_COMMAND, &pv_cmd);
- } while (rc == -EINTR);
-
- if (rc) {
- error_report("KVM PV command %d (%s) failed: header rc %x rrc %x "
- "IOCTL rc: %d", cmd, cmdname, pv_cmd.rc, pv_cmd.rrc,
- rc);
- }
- return rc;
-}
-
-/*
- * This macro lets us pass the command as a string to the function so
- * we can print it on an error.
- */
-#define s390_pv_cmd(cmd, data) __s390_pv_cmd(cmd, #cmd, data);
-#define s390_pv_cmd_exit(cmd, data) \
-{ \
- int rc; \
- \
- rc = __s390_pv_cmd(cmd, #cmd, data);\
- if (rc) { \
- exit(1); \
- } \
-}
-
-int s390_pv_vm_enable(void)
-{
- return s390_pv_cmd(KVM_PV_ENABLE, NULL);
-}
-
-void s390_pv_vm_disable(void)
-{
- s390_pv_cmd_exit(KVM_PV_DISABLE, NULL);
-}
-
-int s390_pv_set_sec_parms(uint64_t origin, uint64_t length)
-{
- struct kvm_s390_pv_sec_parm args = {
- .origin = origin,
- .length = length,
- };
-
- return s390_pv_cmd(KVM_PV_SET_SEC_PARMS, &args);
-}
-
-/*
- * Called for each component in the SE type IPL parameter block 0.
- */
-int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak)
-{
- struct kvm_s390_pv_unp args = {
- .addr = addr,
- .size = size,
- .tweak = tweak,
- };
-
- return s390_pv_cmd(KVM_PV_UNPACK, &args);
-}
-
-void s390_pv_prep_reset(void)
-{
- s390_pv_cmd_exit(KVM_PV_PREP_RESET, NULL);
-}
-
-int s390_pv_verify(void)
-{
- return s390_pv_cmd(KVM_PV_VERIFY, NULL);
-}
-
-void s390_pv_unshare(void)
-{
- s390_pv_cmd_exit(KVM_PV_UNSHARE_ALL, NULL);
-}
-
-void s390_pv_inject_reset_error(CPUState *cs)
-{
- int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4;
- CPUS390XState *env = &S390_CPU(cs)->env;
-
- /* Report that we are unable to enter protected mode */
- env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
-}
-
-#define TYPE_S390_PV_GUEST "s390-pv-guest"
-OBJECT_DECLARE_SIMPLE_TYPE(S390PVGuest, S390_PV_GUEST)
-
-/**
- * S390PVGuest:
- *
- * The S390PVGuest object is basically a dummy used to tell the
- * confidential guest support system to use s390's PV mechanism.
- *
- * # $QEMU \
- * -object s390-pv-guest,id=pv0 \
- * -machine ...,confidential-guest-support=pv0
- */
-struct S390PVGuest {
- ConfidentialGuestSupport parent_obj;
-};
-
-typedef struct S390PVGuestClass S390PVGuestClass;
-
-struct S390PVGuestClass {
- ConfidentialGuestSupportClass parent_class;
-};
-
-int s390_pv_kvm_init(ConfidentialGuestSupport *cgs, Error **errp)
-{
- if (!object_dynamic_cast(OBJECT(cgs), TYPE_S390_PV_GUEST)) {
- return 0;
- }
-
- if (!s390_has_feat(S390_FEAT_UNPACK)) {
- error_setg(errp,
- "CPU model does not support Protected Virtualization");
- return -1;
- }
-
- cgs->ready = true;
-
- return 0;
-}
-
-OBJECT_DEFINE_TYPE_WITH_INTERFACES(S390PVGuest,
- s390_pv_guest,
- S390_PV_GUEST,
- CONFIDENTIAL_GUEST_SUPPORT,
- { TYPE_USER_CREATABLE },
- { NULL })
-
-static void s390_pv_guest_class_init(ObjectClass *oc, void *data)
-{
-}
-
-static void s390_pv_guest_init(Object *obj)
-{
-}
-
-static void s390_pv_guest_finalize(Object *obj)
-{
-}
diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c
index 2fc8bb9c23..5261e66724 100644
--- a/hw/s390x/s390-ccw.c
+++ b/hw/s390x/s390-ccw.c
@@ -57,7 +57,7 @@ IOInstEnding s390_ccw_store(SubchDev *sch)
/*
* This code is called for both virtual and passthrough devices,
- * but only applies to to the latter. This ugly check makes that
+ * but only applies to the latter. This ugly check makes that
* distinction for us.
*/
if (object_dynamic_cast(OBJECT(sch->driver_data), TYPE_S390_CCW)) {
@@ -76,7 +76,9 @@ static void s390_ccw_get_dev_info(S390CCWDevice *cdev,
Error **errp)
{
unsigned int cssid, ssid, devid;
- char dev_path[PATH_MAX] = {0}, *tmp;
+ char dev_path[PATH_MAX] = {0};
+ g_autofree char *tmp_dir = NULL;
+ g_autofree char *tmp = NULL;
if (!sysfsdev) {
error_setg(errp, "No host device provided");
@@ -92,7 +94,8 @@ static void s390_ccw_get_dev_info(S390CCWDevice *cdev,
cdev->mdevid = g_path_get_basename(dev_path);
- tmp = basename(dirname(dev_path));
+ tmp_dir = g_path_get_dirname(dev_path);
+ tmp = g_path_get_basename(tmp_dir);
if (sscanf(tmp, "%2x.%1x.%4x", &cssid, &ssid, &devid) != 3) {
error_setg_errno(errp, errno, "Failed to read %s", tmp);
return;
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 6c0225c3a0..3e57d5faca 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -16,6 +16,7 @@
#include "qapi/visitor.h"
#include "hw/s390x/s390-pci-bus.h"
#include "hw/s390x/s390-pci-inst.h"
+#include "hw/s390x/s390-pci-kvm.h"
#include "hw/s390x/s390-pci-vfio.h"
#include "hw/pci/pci_bus.h"
#include "hw/qdev-properties.h"
@@ -23,17 +24,10 @@
#include "hw/pci/msi.h"
#include "qemu/error-report.h"
#include "qemu/module.h"
+#include "sysemu/reset.h"
+#include "sysemu/runstate.h"
-#ifndef DEBUG_S390PCI_BUS
-#define DEBUG_S390PCI_BUS 0
-#endif
-
-#define DPRINTF(fmt, ...) \
- do { \
- if (DEBUG_S390PCI_BUS) { \
- fprintf(stderr, "S390pci-bus: " fmt, ## __VA_ARGS__); \
- } \
- } while (0)
+#include "trace.h"
S390pciState *s390_get_phb(void)
{
@@ -129,7 +123,7 @@ void s390_pci_sclp_configure(SCCB *sccb)
uint16_t rc;
if (!pbdev) {
- DPRINTF("sclp config no dev found\n");
+ trace_s390_pci_sclp_nodev("configure", be32_to_cpu(psccb->aid));
rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED;
goto out;
}
@@ -149,10 +143,22 @@ out:
psccb->header.response_code = cpu_to_be16(rc);
}
+static void s390_pci_shutdown_notifier(Notifier *n, void *opaque)
+{
+ S390PCIBusDevice *pbdev = container_of(n, S390PCIBusDevice,
+ shutdown_notifier);
+
+ pci_device_reset(pbdev->pdev);
+}
+
static void s390_pci_perform_unplug(S390PCIBusDevice *pbdev)
{
HotplugHandler *hotplug_ctrl;
+ if (pbdev->pft == ZPCI_PFT_ISM) {
+ notifier_remove(&pbdev->shutdown_notifier);
+ }
+
/* Unplug the PCI device */
if (pbdev->pdev) {
DeviceState *pdev = DEVICE(pbdev->pdev);
@@ -176,7 +182,7 @@ void s390_pci_sclp_deconfigure(SCCB *sccb)
uint16_t rc;
if (!pbdev) {
- DPRINTF("sclp deconfig no dev found\n");
+ trace_s390_pci_sclp_nodev("deconfigure", be32_to_cpu(psccb->aid));
rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED;
goto out;
}
@@ -189,7 +195,10 @@ void s390_pci_sclp_deconfigure(SCCB *sccb)
rc = SCLP_RC_NO_ACTION_REQUIRED;
break;
default:
- if (pbdev->summary_ind) {
+ if (pbdev->interp && (pbdev->fh & FH_MASK_ENABLE)) {
+ /* Interpreted devices were using interrupt forwarding */
+ s390_pci_kvm_aif_disable(pbdev);
+ } else if (pbdev->summary_ind) {
pci_dereg_irqs(pbdev);
}
if (pbdev->iommu->enabled) {
@@ -547,7 +556,7 @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr,
return ret;
}
- DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr);
+ trace_s390_pci_iommu_xlate(addr);
if (addr < iommu->pba || addr > iommu->pal) {
error = ERR_EVENT_OORANGE;
@@ -635,6 +644,10 @@ static AddressSpace *s390_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
return &iommu->as;
}
+static const PCIIOMMUOps s390_iommu_ops = {
+ .get_address_space = s390_pci_dma_iommu,
+};
+
static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set)
{
uint8_t expected, actual;
@@ -666,8 +679,8 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data,
uint32_t sum_bit;
assert(pbdev);
- DPRINTF("write_msix data 0x%" PRIx64 " idx %d vec 0x%x\n", data,
- pbdev->idx, vec);
+
+ trace_s390_pci_msi_ctrl_write(data, pbdev->idx, vec);
if (pbdev->state != ZPCI_FS_ENABLED) {
return;
@@ -744,13 +757,14 @@ static void s390_pci_iommu_free(S390pciState *s, PCIBus *bus, int32_t devfn)
object_unref(OBJECT(iommu));
}
-S390PCIGroup *s390_group_create(int id)
+S390PCIGroup *s390_group_create(int id, int host_id)
{
S390PCIGroup *group;
S390pciState *s = s390_get_phb();
group = g_new0(S390PCIGroup, 1);
group->id = id;
+ group->host_id = host_id;
QTAILQ_INSERT_TAIL(&s->zpci_groups, group, link);
return group;
}
@@ -768,12 +782,25 @@ S390PCIGroup *s390_group_find(int id)
return NULL;
}
+S390PCIGroup *s390_group_find_host_sim(int host_id)
+{
+ S390PCIGroup *group;
+ S390pciState *s = s390_get_phb();
+
+ QTAILQ_FOREACH(group, &s->zpci_groups, link) {
+ if (group->id >= ZPCI_SIM_GRP_START && group->host_id == host_id) {
+ return group;
+ }
+ }
+ return NULL;
+}
+
static void s390_pci_init_default_group(void)
{
S390PCIGroup *group;
ClpRspQueryPciGrp *resgrp;
- group = s390_group_create(ZPCI_DEFAULT_FN_GRP);
+ group = s390_group_create(ZPCI_DEFAULT_FN_GRP, ZPCI_DEFAULT_FN_GRP);
resgrp = &group->zpci_group;
resgrp->fr = 1;
resgrp->dasm = 0;
@@ -782,6 +809,7 @@ static void s390_pci_init_default_group(void)
resgrp->i = 128;
resgrp->maxstbl = 128;
resgrp->version = 0;
+ resgrp->dtsm = ZPCI_DTSM;
}
static void set_pbdev_info(S390PCIBusDevice *pbdev)
@@ -802,24 +830,25 @@ static void s390_pcihost_realize(DeviceState *dev, Error **errp)
PCIHostState *phb = PCI_HOST_BRIDGE(dev);
S390pciState *s = S390_PCI_HOST_BRIDGE(dev);
- DPRINTF("host_init\n");
+ trace_s390_pcihost("realize");
b = pci_register_root_bus(dev, NULL, s390_pci_set_irq, s390_pci_map_irq,
NULL, get_system_memory(), get_system_io(), 0,
64, TYPE_PCI_BUS);
- pci_setup_iommu(b, s390_pci_dma_iommu, s);
+ pci_setup_iommu(b, &s390_iommu_ops, s);
bus = BUS(b);
qbus_set_hotplug_handler(bus, OBJECT(dev));
phb->bus = b;
- s->bus = S390_PCI_BUS(qbus_create(TYPE_S390_PCI_BUS, dev, NULL));
+ s->bus = S390_PCI_BUS(qbus_new(TYPE_S390_PCI_BUS, dev, NULL));
qbus_set_hotplug_handler(BUS(s->bus), OBJECT(dev));
s->iommu_table = g_hash_table_new_full(g_int64_hash, g_int64_equal,
NULL, g_free);
s->zpci_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, NULL);
s->bus_no = 0;
+ s->next_sim_grp = ZPCI_SIM_GRP_START;
QTAILQ_INIT(&s->pending_sei);
QTAILQ_INIT(&s->zpci_devs);
QTAILQ_INIT(&s->zpci_dma_limit);
@@ -879,6 +908,10 @@ static int s390_pci_msix_init(S390PCIBusDevice *pbdev)
static void s390_pci_msix_free(S390PCIBusDevice *pbdev)
{
+ if (pbdev->msix.entries == 0) {
+ return;
+ }
+
memory_region_del_subregion(&pbdev->iommu->mr, &pbdev->msix_notify_mr);
object_unparent(OBJECT(&pbdev->msix_notify_mr));
}
@@ -970,19 +1003,58 @@ static void s390_pci_update_subordinate(PCIDevice *dev, uint32_t nr)
}
}
+static int s390_pci_interp_plug(S390pciState *s, S390PCIBusDevice *pbdev)
+{
+ uint32_t idx, fh;
+
+ if (!s390_pci_get_host_fh(pbdev, &fh)) {
+ return -EPERM;
+ }
+
+ /*
+ * The host device is already in an enabled state, but we always present
+ * the initial device state to the guest as disabled (ZPCI_FS_DISABLED).
+ * Therefore, mask off the enable bit from the passthrough handle until
+ * the guest issues a CLP SET PCI FN later to enable the device.
+ */
+ pbdev->fh = fh & ~FH_MASK_ENABLE;
+
+ /* Next, see if the idx is already in-use */
+ idx = pbdev->fh & FH_MASK_INDEX;
+ if (pbdev->idx != idx) {
+ if (s390_pci_find_dev_by_idx(s, idx)) {
+ return -EINVAL;
+ }
+ /*
+ * Update the idx entry with the passed through idx
+ * If the relinquished idx is lower than next_idx, use it
+ * to replace next_idx
+ */
+ g_hash_table_remove(s->zpci_table, &pbdev->idx);
+ if (idx < s->next_idx) {
+ s->next_idx = idx;
+ }
+ pbdev->idx = idx;
+ g_hash_table_insert(s->zpci_table, &pbdev->idx, pbdev);
+ }
+
+ return 0;
+}
+
static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
Error **errp)
{
S390pciState *s = S390_PCI_HOST_BRIDGE(hotplug_dev);
PCIDevice *pdev = NULL;
S390PCIBusDevice *pbdev = NULL;
+ int rc;
if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_BRIDGE)) {
PCIBridge *pb = PCI_BRIDGE(dev);
pdev = PCI_DEVICE(dev);
pci_bridge_map_irq(pb, dev->id, s390_pci_map_irq);
- pci_setup_iommu(&pb->sec_bus, s390_pci_dma_iommu, s);
+ pci_setup_iommu(&pb->sec_bus, &s390_iommu_ops, s);
qbus_set_hotplug_handler(BUS(&pb->sec_bus), OBJECT(s));
@@ -1021,15 +1093,46 @@ static void s390_pcihost_plug(HotplugHandler *hotplug_dev, DeviceState *dev,
set_pbdev_info(pbdev);
if (object_dynamic_cast(OBJECT(dev), "vfio-pci")) {
- pbdev->fh |= FH_SHM_VFIO;
+ /*
+ * By default, interpretation is always requested; if the available
+ * facilities indicate it is not available, fallback to the
+ * interception model.
+ */
+ if (pbdev->interp) {
+ if (s390_pci_kvm_interp_allowed()) {
+ rc = s390_pci_interp_plug(s, pbdev);
+ if (rc) {
+ error_setg(errp, "Plug failed for zPCI device in "
+ "interpretation mode: %d", rc);
+ return;
+ }
+ } else {
+ trace_s390_pcihost("zPCI interpretation missing");
+ pbdev->interp = false;
+ pbdev->forwarding_assist = false;
+ }
+ }
pbdev->iommu->dma_limit = s390_pci_start_dma_count(s, pbdev);
/* Fill in CLP information passed via the vfio region */
s390_pci_get_clp_info(pbdev);
+ if (!pbdev->interp) {
+ /* Do vfio passthrough but intercept for I/O */
+ pbdev->fh |= FH_SHM_VFIO;
+ pbdev->forwarding_assist = false;
+ }
+ /* Register shutdown notifier and reset callback for ISM devices */
+ if (pbdev->pft == ZPCI_PFT_ISM) {
+ pbdev->shutdown_notifier.notify = s390_pci_shutdown_notifier;
+ qemu_register_shutdown_notifier(&pbdev->shutdown_notifier);
+ }
} else {
pbdev->fh |= FH_SHM_EMUL;
+ /* Always intercept emulated devices */
+ pbdev->interp = false;
+ pbdev->forwarding_assist = false;
}
- if (s390_pci_msix_init(pbdev)) {
+ if (s390_pci_msix_init(pbdev) && !pbdev->interp) {
error_setg(errp, "MSI-X support is mandatory "
"in the S390 architecture");
return;
@@ -1163,11 +1266,27 @@ static void s390_pci_enumerate_bridge(PCIBus *bus, PCIDevice *pdev,
}
/* Assign numbers to all child bridges. The last is the highest number. */
- pci_for_each_device(sec_bus, pci_bus_num(sec_bus),
- s390_pci_enumerate_bridge, s);
+ pci_for_each_device_under_bus(sec_bus, s390_pci_enumerate_bridge, s);
pci_default_write_config(pdev, PCI_SUBORDINATE_BUS, s->bus_no, 1);
}
+void s390_pci_ism_reset(void)
+{
+ S390pciState *s = s390_get_phb();
+
+ S390PCIBusDevice *pbdev, *next;
+
+ /* Trigger reset event for each passthrough ISM device currently in-use */
+ QTAILQ_FOREACH_SAFE(pbdev, &s->zpci_devs, link, next) {
+ if (pbdev->interp && pbdev->pft == ZPCI_PFT_ISM &&
+ pbdev->fh & FH_MASK_ENABLE) {
+ s390_pci_kvm_aif_disable(pbdev);
+
+ pci_device_reset(pbdev->pdev);
+ }
+ }
+}
+
static void s390_pcihost_reset(DeviceState *dev)
{
S390pciState *s = S390_PCI_HOST_BRIDGE(dev);
@@ -1177,7 +1296,10 @@ static void s390_pcihost_reset(DeviceState *dev)
/* Process all pending unplug requests */
QTAILQ_FOREACH_SAFE(pbdev, &s->zpci_devs, link, next) {
if (pbdev->unplug_requested) {
- if (pbdev->summary_ind) {
+ if (pbdev->interp && (pbdev->fh & FH_MASK_ENABLE)) {
+ /* Interpreted devices were using interrupt forwarding */
+ s390_pci_kvm_aif_disable(pbdev);
+ } else if (pbdev->summary_ind) {
pci_dereg_irqs(pbdev);
}
if (pbdev->iommu->enabled) {
@@ -1193,7 +1315,7 @@ static void s390_pcihost_reset(DeviceState *dev)
* on every system reset, we also have to reassign numbers.
*/
s->bus_no = 0;
- pci_for_each_device(bus, pci_bus_num(bus), s390_pci_enumerate_bridge, s);
+ pci_for_each_device_under_bus(bus, s390_pci_enumerate_bridge, s);
}
static void s390_pcihost_class_init(ObjectClass *klass, void *data)
@@ -1315,7 +1437,10 @@ static void s390_pci_device_reset(DeviceState *dev)
break;
}
- if (pbdev->summary_ind) {
+ if (pbdev->interp && (pbdev->fh & FH_MASK_ENABLE)) {
+ /* Interpreted devices were using interrupt forwarding */
+ s390_pci_kvm_aif_disable(pbdev);
+ } else if (pbdev->summary_ind) {
pci_dereg_irqs(pbdev);
}
if (pbdev->iommu->enabled) {
@@ -1360,6 +1485,9 @@ static Property s390_pci_device_properties[] = {
DEFINE_PROP_UINT16("uid", S390PCIBusDevice, uid, UID_UNDEFINED),
DEFINE_PROP_S390_PCI_FID("fid", S390PCIBusDevice, fid),
DEFINE_PROP_STRING("target", S390PCIBusDevice, target),
+ DEFINE_PROP_BOOL("interpret", S390PCIBusDevice, interp, true),
+ DEFINE_PROP_BOOL("forwarding-assist", S390PCIBusDevice, forwarding_assist,
+ true),
DEFINE_PROP_END_OF_LIST(),
};
@@ -1392,7 +1520,7 @@ static const TypeInfo s390_pci_device_info = {
.class_init = s390_pci_device_class_init,
};
-static TypeInfo s390_pci_iommu_info = {
+static const TypeInfo s390_pci_iommu_info = {
.name = TYPE_S390_PCI_IOMMU,
.parent = TYPE_OBJECT,
.instance_size = sizeof(S390PCIIOMMU),
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 1c8ad91175..30149546c0 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -13,23 +13,17 @@
#include "qemu/osdep.h"
#include "exec/memop.h"
-#include "exec/memory-internal.h"
+#include "exec/memory.h"
#include "qemu/error-report.h"
#include "sysemu/hw_accel.h"
+#include "hw/pci/pci_device.h"
#include "hw/s390x/s390-pci-inst.h"
#include "hw/s390x/s390-pci-bus.h"
+#include "hw/s390x/s390-pci-kvm.h"
+#include "hw/s390x/s390-pci-vfio.h"
#include "hw/s390x/tod.h"
-#ifndef DEBUG_S390PCI_INST
-#define DEBUG_S390PCI_INST 0
-#endif
-
-#define DPRINTF(fmt, ...) \
- do { \
- if (DEBUG_S390PCI_INST) { \
- fprintf(stderr, "s390pci-inst: " fmt, ## __VA_ARGS__); \
- } \
- } while (0)
+#include "trace.h"
static inline void inc_dma_avail(S390PCIIOMMU *iommu)
{
@@ -130,8 +124,7 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
g_l2 += sizeof(ClpFhListEntry);
/* Add endian check for DPRINTF? */
- DPRINTF("g_l2 %d vendor id 0x%x device id 0x%x fid 0x%x fh 0x%x\n",
- g_l2,
+ trace_s390_pci_list_entry(g_l2,
lduw_p(&rrb->response.fh_list[i].vendor_id),
lduw_p(&rrb->response.fh_list[i].device_id),
ldl_p(&rrb->response.fh_list[i].fid),
@@ -150,7 +143,7 @@ static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc)
stw_p(&rrb->response.hdr.rsp, CLP_RC_OK);
out:
if (rc) {
- DPRINTF("list pci failed rc 0x%x\n", rc);
+ trace_s390_pci_list(rc);
stw_p(&rrb->response.hdr.rsp, res_code);
}
return rc;
@@ -246,6 +239,20 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
goto out;
}
+ /*
+ * Take this opportunity to make sure we still have an accurate
+ * host fh. It's possible part of the handle changed while the
+ * device was disabled to the guest (e.g. vfio hot reset for
+ * ISM during plug)
+ */
+ if (pbdev->interp) {
+ /* Take this opportunity to make sure we are sync'd with host */
+ if (!s390_pci_get_host_fh(pbdev, &pbdev->fh) ||
+ !(pbdev->fh & FH_MASK_ENABLE)) {
+ stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH);
+ goto out;
+ }
+ }
pbdev->fh |= FH_MASK_ENABLE;
pbdev->state = ZPCI_FS_ENABLED;
stl_p(&ressetpci->fh, pbdev->fh);
@@ -256,14 +263,14 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
goto out;
}
- device_legacy_reset(DEVICE(pbdev));
+ device_cold_reset(DEVICE(pbdev));
pbdev->fh &= ~FH_MASK_ENABLE;
pbdev->state = ZPCI_FS_DISABLED;
stl_p(&ressetpci->fh, pbdev->fh);
stw_p(&ressetpci->hdr.rsp, CLP_RC_OK);
break;
default:
- DPRINTF("unknown set pci command\n");
+ trace_s390_pci_unknown("set-pci", reqsetpci->oc);
stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP);
break;
}
@@ -275,7 +282,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
pbdev = s390_pci_find_dev_by_fh(s, ldl_p(&reqquery->fh));
if (!pbdev) {
- DPRINTF("query pci no pci dev\n");
+ trace_s390_pci_nodev("query", ldl_p(&reqquery->fh));
stw_p(&resquery->hdr.rsp, CLP_RC_SETPCIFN_FH);
goto out;
}
@@ -300,7 +307,7 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
stl_p(&resquery->bar[i], data);
resquery->bar_size[i] = pbdev->pdev->io_regions[i].size ?
ctz64(pbdev->pdev->io_regions[i].size) : 0;
- DPRINTF("bar %d addr 0x%x size 0x%" PRIx64 "barsize 0x%x\n", i,
+ trace_s390_pci_bar(i,
ldl_p(&resquery->bar[i]),
pbdev->pdev->io_regions[i].size,
resquery->bar_size[i]);
@@ -329,11 +336,12 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
stw_p(&resgrp->i, group->zpci_group.i);
stw_p(&resgrp->maxstbl, group->zpci_group.maxstbl);
resgrp->version = group->zpci_group.version;
+ resgrp->dtsm = group->zpci_group.dtsm;
stw_p(&resgrp->hdr.rsp, CLP_RC_OK);
break;
}
default:
- DPRINTF("unknown clp command\n");
+ trace_s390_pci_unknown("clp", lduw_p(&reqh->cmd));
stw_p(&resh->rsp, CLP_RC_CMD);
break;
}
@@ -441,7 +449,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh);
if (!pbdev) {
- DPRINTF("pcilg no pci dev\n");
+ trace_s390_pci_nodev("pcilg", fh);
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
}
@@ -482,7 +490,7 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
}
break;
default:
- DPRINTF("pcilg invalid space\n");
+ trace_s390_pci_invalid("pcilg", fh);
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS);
return 0;
@@ -541,7 +549,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh);
if (!pbdev) {
- DPRINTF("pcistg no pci dev\n");
+ trace_s390_pci_nodev("pcistg", fh);
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
}
@@ -590,7 +598,7 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
data, len);
break;
default:
- DPRINTF("pcistg invalid space\n");
+ trace_s390_pci_invalid("pcistg", fh);
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS);
return 0;
@@ -623,6 +631,8 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu,
}
g_hash_table_remove(iommu->iotlb, &entry->iova);
inc_dma_avail(iommu);
+ /* Don't notify the iommu yet, maybe we can bundle contiguous unmaps */
+ goto out;
} else {
if (cache) {
if (cache->perm == entry->perm &&
@@ -646,22 +656,52 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu,
dec_dma_avail(iommu);
}
+ /*
+ * All associated iotlb entries have already been cleared, trigger the
+ * unmaps.
+ */
memory_region_notify_iommu(&iommu->iommu_mr, 0, event);
out:
return iommu->dma_limit ? iommu->dma_limit->avail : 1;
}
+static void s390_pci_batch_unmap(S390PCIIOMMU *iommu, uint64_t iova,
+ uint64_t len)
+{
+ uint64_t remain = len, start = iova, end = start + len - 1, mask, size;
+ IOMMUTLBEvent event = {
+ .type = IOMMU_NOTIFIER_UNMAP,
+ .entry = {
+ .target_as = &address_space_memory,
+ .translated_addr = 0,
+ .perm = IOMMU_NONE,
+ },
+ };
+
+ while (remain >= TARGET_PAGE_SIZE) {
+ mask = dma_aligned_pow2_mask(start, end, 64);
+ size = mask + 1;
+ event.entry.iova = start;
+ event.entry.addr_mask = mask;
+ memory_region_notify_iommu(&iommu->iommu_mr, 0, event);
+ start += size;
+ remain -= size;
+ }
+}
+
int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
{
CPUS390XState *env = &cpu->env;
+ uint64_t iova, coalesce = 0;
uint32_t fh;
uint16_t error = 0;
S390PCIBusDevice *pbdev;
S390PCIIOMMU *iommu;
S390IOTLBEntry entry;
- hwaddr start, end;
+ hwaddr start, end, sstart;
uint32_t dma_avail;
+ bool again;
if (env->psw.mask & PSW_MASK_PSTATE) {
s390_program_interrupt(env, PGM_PRIVILEGED, ra);
@@ -674,12 +714,12 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
}
fh = env->regs[r1] >> 32;
- start = env->regs[r2];
+ sstart = start = env->regs[r2];
end = start + env->regs[r2 + 1];
pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh);
if (!pbdev) {
- DPRINTF("rpcit no pci dev\n");
+ trace_s390_pci_nodev("rpcit", fh);
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
}
@@ -715,20 +755,54 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
goto err;
}
+ retry:
+ start = sstart;
+ again = false;
while (start < end) {
error = s390_guest_io_table_walk(iommu->g_iota, start, &entry);
if (error) {
break;
}
+ /*
+ * If this is an unmap of a PTE, let's try to coalesce multiple unmaps
+ * into as few notifier events as possible.
+ */
+ if (entry.perm == IOMMU_NONE && entry.len == TARGET_PAGE_SIZE) {
+ if (coalesce == 0) {
+ iova = entry.iova;
+ }
+ coalesce += entry.len;
+ } else if (coalesce > 0) {
+ /* Unleash the coalesced unmap before processing a new map */
+ s390_pci_batch_unmap(iommu, iova, coalesce);
+ coalesce = 0;
+ }
+
start += entry.len;
- while (entry.iova < start && entry.iova < end &&
- (dma_avail > 0 || entry.perm == IOMMU_NONE)) {
- dma_avail = s390_pci_update_iotlb(iommu, &entry);
- entry.iova += TARGET_PAGE_SIZE;
- entry.translated_addr += TARGET_PAGE_SIZE;
+ while (entry.iova < start && entry.iova < end) {
+ if (dma_avail > 0 || entry.perm == IOMMU_NONE) {
+ dma_avail = s390_pci_update_iotlb(iommu, &entry);
+ entry.iova += TARGET_PAGE_SIZE;
+ entry.translated_addr += TARGET_PAGE_SIZE;
+ } else {
+ /*
+ * We are unable to make a new mapping at this time, continue
+ * on and hopefully free up more space. Then attempt another
+ * pass.
+ */
+ again = true;
+ break;
+ }
}
}
+ if (coalesce) {
+ /* Unleash the coalesced unmap before finishing rpcit */
+ s390_pci_batch_unmap(iommu, iova, coalesce);
+ coalesce = 0;
+ }
+ if (again && dma_avail > 0)
+ goto retry;
err:
if (error) {
pbdev->state = ZPCI_FS_ERROR;
@@ -779,7 +853,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh);
if (!pbdev) {
- DPRINTF("pcistb no pci dev fh 0x%x\n", fh);
+ trace_s390_pci_nodev("pcistb", fh);
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
}
@@ -795,7 +869,7 @@ int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr,
}
if (pcias > ZPCI_IO_BAR_MAX) {
- DPRINTF("pcistb invalid space\n");
+ trace_s390_pci_invalid("pcistb", fh);
setcc(cpu, ZPCI_PCI_LS_ERR);
s390_set_status_code(env, r1, ZPCI_PCI_ST_INVAL_AS);
return 0;
@@ -887,7 +961,7 @@ static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
pbdev->noi = FIB_DATA_NOI(ldl_p(&fib.data));
pbdev->sum = FIB_DATA_SUM(ldl_p(&fib.data));
- DPRINTF("reg_irqs adapter id %d\n", pbdev->routes.adapter.adapter_id);
+ trace_s390_pci_irqs("register", pbdev->routes.adapter.adapter_id);
return 0;
out:
release_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
@@ -912,13 +986,14 @@ int pci_dereg_irqs(S390PCIBusDevice *pbdev)
pbdev->noi = 0;
pbdev->sum = 0;
- DPRINTF("dereg_irqs adapter id %d\n", pbdev->routes.adapter.adapter_id);
+ trace_s390_pci_irqs("unregister", pbdev->routes.adapter.adapter_id);
return 0;
}
-static int reg_ioat(CPUS390XState *env, S390PCIIOMMU *iommu, ZpciFib fib,
+static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib,
uintptr_t ra)
{
+ S390PCIIOMMU *iommu = pbdev->iommu;
uint64_t pba = ldq_p(&fib.pba);
uint64_t pal = ldq_p(&fib.pal);
uint64_t g_iota = ldq_p(&fib.iota);
@@ -927,7 +1002,7 @@ static int reg_ioat(CPUS390XState *env, S390PCIIOMMU *iommu, ZpciFib fib,
pba &= ~0xfff;
pal |= 0xfff;
- if (pba > pal || pba < ZPCI_SDMA_ADDR || pal > ZPCI_EDMA_ADDR) {
+ if (pba > pal || pba < pbdev->zpci_fn.sdma || pal > pbdev->zpci_fn.edma) {
s390_program_interrupt(env, PGM_OPERAND, ra);
return -EINVAL;
}
@@ -1045,7 +1120,33 @@ static void fmb_update(void *opaque)
sizeof(pbdev->fmb.last_update))) {
return;
}
- timer_mod(pbdev->fmb_timer, t + DEFAULT_MUI);
+ timer_mod(pbdev->fmb_timer, t + pbdev->pci_group->zpci_group.mui);
+}
+
+static int mpcifc_reg_int_interp(S390PCIBusDevice *pbdev, ZpciFib *fib)
+{
+ int rc;
+
+ rc = s390_pci_kvm_aif_enable(pbdev, fib, pbdev->forwarding_assist);
+ if (rc) {
+ trace_s390_pci_kvm_aif("enable");
+ return rc;
+ }
+
+ return 0;
+}
+
+static int mpcifc_dereg_int_interp(S390PCIBusDevice *pbdev, ZpciFib *fib)
+{
+ int rc;
+
+ rc = s390_pci_kvm_aif_disable(pbdev);
+ if (rc) {
+ trace_s390_pci_kvm_aif("disable");
+ return rc;
+ }
+
+ return 0;
}
int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
@@ -1074,7 +1175,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh);
if (!pbdev) {
- DPRINTF("mpcifc no pci dev fh 0x%x\n", fh);
+ trace_s390_pci_nodev("mpcifc", fh);
setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE);
return 0;
}
@@ -1102,7 +1203,12 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
switch (oc) {
case ZPCI_MOD_FC_REG_INT:
- if (pbdev->summary_ind) {
+ if (pbdev->interp) {
+ if (mpcifc_reg_int_interp(pbdev, &fib)) {
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
+ }
+ } else if (pbdev->summary_ind) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else if (reg_irqs(env, pbdev, fib)) {
@@ -1111,7 +1217,12 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
}
break;
case ZPCI_MOD_FC_DEREG_INT:
- if (!pbdev->summary_ind) {
+ if (pbdev->interp) {
+ if (mpcifc_dereg_int_interp(pbdev, &fib)) {
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
+ }
+ } else if (!pbdev->summary_ind) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else {
@@ -1125,7 +1236,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
} else if (pbdev->iommu->enabled) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
- } else if (reg_ioat(env, pbdev->iommu, fib, ra)) {
+ } else if (reg_ioat(env, pbdev, fib, ra)) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
}
@@ -1150,7 +1261,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
} else {
pci_dereg_ioat(pbdev->iommu);
- if (reg_ioat(env, pbdev->iommu, fib, ra)) {
+ if (reg_ioat(env, pbdev, fib, ra)) {
cc = ZPCI_PCI_LS_ERR;
s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
}
@@ -1203,7 +1314,8 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar,
}
pbdev->fmb_addr = fmb_addr;
timer_mod(pbdev->fmb_timer,
- qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + DEFAULT_MUI);
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+ pbdev->pci_group->zpci_group.mui);
break;
}
default:
diff --git a/hw/s390x/s390-pci-kvm.c b/hw/s390x/s390-pci-kvm.c
new file mode 100644
index 0000000000..9eef4fc3ec
--- /dev/null
+++ b/hw/s390x/s390-pci-kvm.c
@@ -0,0 +1,82 @@
+/*
+ * s390 zPCI KVM interfaces
+ *
+ * Copyright 2022 IBM Corp.
+ * Author(s): Matthew Rosato <mjrosato@linux.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include <linux/kvm.h>
+
+#include "kvm/kvm_s390x.h"
+#include "target/s390x/kvm/pv.h"
+#include "hw/s390x/s390-pci-bus.h"
+#include "hw/s390x/s390-pci-kvm.h"
+#include "hw/s390x/s390-pci-inst.h"
+#include "hw/s390x/s390-pci-vfio.h"
+#include "cpu_models.h"
+
+bool s390_pci_kvm_interp_allowed(void)
+{
+ return kvm_s390_get_zpci_op() && !s390_is_pv();
+}
+
+int s390_pci_kvm_aif_enable(S390PCIBusDevice *pbdev, ZpciFib *fib, bool assist)
+{
+ int rc;
+ struct kvm_s390_zpci_op args = {
+ .fh = pbdev->fh,
+ .op = KVM_S390_ZPCIOP_REG_AEN,
+ .u.reg_aen.ibv = fib->aibv,
+ .u.reg_aen.sb = fib->aisb,
+ .u.reg_aen.noi = FIB_DATA_NOI(fib->data),
+ .u.reg_aen.isc = FIB_DATA_ISC(fib->data),
+ .u.reg_aen.sbo = FIB_DATA_AISBO(fib->data),
+ .u.reg_aen.flags = (assist) ? 0 : KVM_S390_ZPCIOP_REGAEN_HOST
+ };
+
+ if (pbdev->aif) {
+ return -EINVAL;
+ }
+
+ rc = kvm_vm_ioctl(kvm_state, KVM_S390_ZPCI_OP, &args);
+ if (rc == 0) {
+ pbdev->aif = true;
+ }
+
+ return rc;
+}
+
+int s390_pci_kvm_aif_disable(S390PCIBusDevice *pbdev)
+{
+ int rc;
+
+ struct kvm_s390_zpci_op args = {
+ .fh = pbdev->fh,
+ .op = KVM_S390_ZPCIOP_DEREG_AEN
+ };
+
+ if (!pbdev->aif) {
+ return -EINVAL;
+ }
+
+ /*
+ * The device may have already been reset but we still want to relinquish
+ * the guest ISC, so always be sure to use an up-to-date host fh.
+ */
+ if (!s390_pci_get_host_fh(pbdev, &args.fh)) {
+ return -EPERM;
+ }
+
+ rc = kvm_vm_ioctl(kvm_state, KVM_S390_ZPCI_OP, &args);
+ if (rc == 0) {
+ pbdev->aif = false;
+ }
+
+ return rc;
+}
diff --git a/hw/s390x/s390-pci-vfio.c b/hw/s390x/s390-pci-vfio.c
index 2a153fa8c9..7dbbc76823 100644
--- a/hw/s390x/s390-pci-vfio.c
+++ b/hw/s390x/s390-pci-vfio.c
@@ -66,6 +66,10 @@ S390PCIDMACount *s390_pci_start_dma_count(S390pciState *s,
assert(vpdev);
+ if (!vpdev->vbasedev.group) {
+ return NULL;
+ }
+
id = vpdev->vbasedev.group->container->fd;
if (!s390_pci_update_dma_avail(id, &avail)) {
@@ -84,6 +88,7 @@ S390PCIDMACount *s390_pci_start_dma_count(S390pciState *s,
cnt->users = 1;
cnt->avail = avail;
QTAILQ_INSERT_TAIL(&s->zpci_dma_limit, cnt, link);
+ pbdev->iommu->max_dma_limit = avail;
return cnt;
}
@@ -103,6 +108,7 @@ static void s390_pci_read_base(S390PCIBusDevice *pbdev,
struct vfio_info_cap_header *hdr;
struct vfio_device_info_cap_zpci_base *cap;
VFIOPCIDevice *vpci = container_of(pbdev->pdev, VFIOPCIDevice, pdev);
+ uint64_t vfio_size;
hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_BASE);
@@ -122,6 +128,38 @@ static void s390_pci_read_base(S390PCIBusDevice *pbdev,
/* The following values remain 0 until we support other FMB formats */
pbdev->zpci_fn.fmbl = 0;
pbdev->zpci_fn.pft = 0;
+ /* Store function type separately for type-specific behavior */
+ pbdev->pft = cap->pft;
+
+ /*
+ * If appropriate, reduce the size of the supported DMA aperture reported
+ * to the guest based upon the vfio DMA limit.
+ */
+ vfio_size = pbdev->iommu->max_dma_limit << TARGET_PAGE_BITS;
+ if (vfio_size > 0 && vfio_size < cap->end_dma - cap->start_dma + 1) {
+ pbdev->zpci_fn.edma = cap->start_dma + vfio_size - 1;
+ }
+}
+
+static bool get_host_fh(S390PCIBusDevice *pbdev, struct vfio_device_info *info,
+ uint32_t *fh)
+{
+ struct vfio_info_cap_header *hdr;
+ struct vfio_device_info_cap_zpci_base *cap;
+ VFIOPCIDevice *vpci = container_of(pbdev->pdev, VFIOPCIDevice, pdev);
+
+ hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_BASE);
+
+ /* Can only get the host fh with version 2 or greater */
+ if (hdr == NULL || hdr->version < 2) {
+ trace_s390_pci_clp_cap(vpci->vbasedev.name,
+ VFIO_DEVICE_INFO_CAP_ZPCI_BASE);
+ return false;
+ }
+ cap = (void *) hdr;
+
+ *fh = cap->fh;
+ return true;
}
static void s390_pci_read_group(S390PCIBusDevice *pbdev,
@@ -129,13 +167,18 @@ static void s390_pci_read_group(S390PCIBusDevice *pbdev,
{
struct vfio_info_cap_header *hdr;
struct vfio_device_info_cap_zpci_group *cap;
+ S390pciState *s = s390_get_phb();
ClpRspQueryPciGrp *resgrp;
VFIOPCIDevice *vpci = container_of(pbdev->pdev, VFIOPCIDevice, pdev);
+ uint8_t start_gid = pbdev->zpci_fn.pfgid;
hdr = vfio_get_device_info_cap(info, VFIO_DEVICE_INFO_CAP_ZPCI_GROUP);
- /* If capability not provided, just use the default group */
- if (hdr == NULL) {
+ /*
+ * If capability not provided or the underlying hostdev is simulated, just
+ * use the default group.
+ */
+ if (hdr == NULL || pbdev->zpci_fn.pfgid >= ZPCI_SIM_GRP_START) {
trace_s390_pci_clp_cap(vpci->vbasedev.name,
VFIO_DEVICE_INFO_CAP_ZPCI_GROUP);
pbdev->zpci_fn.pfgid = ZPCI_DEFAULT_FN_GRP;
@@ -144,11 +187,40 @@ static void s390_pci_read_group(S390PCIBusDevice *pbdev,
}
cap = (void *) hdr;
+ /*
+ * For an intercept device, let's use an existing simulated group if one
+ * one was already created for other intercept devices in this group.
+ * If not, create a new simulated group if any are still available.
+ * If all else fails, just fall back on the default group.
+ */
+ if (!pbdev->interp) {
+ pbdev->pci_group = s390_group_find_host_sim(pbdev->zpci_fn.pfgid);
+ if (pbdev->pci_group) {
+ /* Use existing simulated group */
+ pbdev->zpci_fn.pfgid = pbdev->pci_group->id;
+ return;
+ } else {
+ if (s->next_sim_grp == ZPCI_DEFAULT_FN_GRP) {
+ /* All out of simulated groups, use default */
+ trace_s390_pci_clp_cap(vpci->vbasedev.name,
+ VFIO_DEVICE_INFO_CAP_ZPCI_GROUP);
+ pbdev->zpci_fn.pfgid = ZPCI_DEFAULT_FN_GRP;
+ pbdev->pci_group = s390_group_find(ZPCI_DEFAULT_FN_GRP);
+ return;
+ } else {
+ /* We can assign a new simulated group */
+ pbdev->zpci_fn.pfgid = s->next_sim_grp;
+ s->next_sim_grp++;
+ /* Fall through to create the new sim group using CLP info */
+ }
+ }
+ }
+
/* See if the PCI group is already defined, create if not */
pbdev->pci_group = s390_group_find(pbdev->zpci_fn.pfgid);
if (!pbdev->pci_group) {
- pbdev->pci_group = s390_group_create(pbdev->zpci_fn.pfgid);
+ pbdev->pci_group = s390_group_create(pbdev->zpci_fn.pfgid, start_gid);
resgrp = &pbdev->pci_group->zpci_group;
if (cap->flags & VFIO_DEVICE_INFO_ZPCI_FLAG_REFRESH) {
@@ -158,8 +230,13 @@ static void s390_pci_read_group(S390PCIBusDevice *pbdev,
resgrp->msia = cap->msi_addr;
resgrp->mui = cap->mui;
resgrp->i = cap->noi;
- resgrp->maxstbl = cap->maxstbl;
+ if (pbdev->interp && hdr->version >= 2) {
+ resgrp->maxstbl = cap->imaxstbl;
+ } else {
+ resgrp->maxstbl = cap->maxstbl;
+ }
resgrp->version = cap->version;
+ resgrp->dtsm = ZPCI_DTSM;
}
}
@@ -216,6 +293,33 @@ static void s390_pci_read_pfip(S390PCIBusDevice *pbdev,
memcpy(pbdev->zpci_fn.pfip, cap->pfip, CLP_PFIP_NR_SEGMENTS);
}
+static struct vfio_device_info *get_device_info(S390PCIBusDevice *pbdev)
+{
+ VFIOPCIDevice *vfio_pci = container_of(pbdev->pdev, VFIOPCIDevice, pdev);
+
+ return vfio_get_device_info(vfio_pci->vbasedev.fd);
+}
+
+/*
+ * Get the host function handle from the vfio CLP capabilities chain. Returns
+ * true if a fh value was placed into the provided buffer. Returns false
+ * if a fh could not be obtained (ioctl failed or capability version does
+ * not include the fh)
+ */
+bool s390_pci_get_host_fh(S390PCIBusDevice *pbdev, uint32_t *fh)
+{
+ g_autofree struct vfio_device_info *info = NULL;
+
+ assert(fh);
+
+ info = get_device_info(pbdev);
+ if (!info) {
+ return false;
+ }
+
+ return get_host_fh(pbdev, info, fh);
+}
+
/*
* This function will issue the VFIO_DEVICE_GET_INFO ioctl and look for
* capabilities that contain information about CLP features provided by the
@@ -228,36 +332,12 @@ static void s390_pci_read_pfip(S390PCIBusDevice *pbdev,
void s390_pci_get_clp_info(S390PCIBusDevice *pbdev)
{
g_autofree struct vfio_device_info *info = NULL;
- VFIOPCIDevice *vfio_pci;
- uint32_t argsz;
- int fd;
- argsz = sizeof(*info);
- info = g_malloc0(argsz);
-
- vfio_pci = container_of(pbdev->pdev, VFIOPCIDevice, pdev);
- fd = vfio_pci->vbasedev.fd;
-
- /*
- * If the specified argsz is not large enough to contain all capabilities
- * it will be updated upon return from the ioctl. Retry until we have
- * a big enough buffer to hold the entire capability chain. On error,
- * just exit and rely on CLP defaults.
- */
-retry:
- info->argsz = argsz;
-
- if (ioctl(fd, VFIO_DEVICE_GET_INFO, info)) {
- trace_s390_pci_clp_dev_info(vfio_pci->vbasedev.name);
+ info = get_device_info(pbdev);
+ if (!info) {
return;
}
- if (info->argsz > argsz) {
- argsz = info->argsz;
- info = g_realloc(info, argsz);
- goto retry;
- }
-
/*
* Find the CLP features provided and fill in the guest CLP responses.
* Always call s390_pci_read_base first as information from this could
diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c
index 5024faf411..5c535d483e 100644
--- a/hw/s390x/s390-skeys.c
+++ b/hw/s390x/s390-skeys.c
@@ -12,6 +12,7 @@
#include "qemu/osdep.h"
#include "qemu/units.h"
#include "hw/boards.h"
+#include "hw/qdev-properties.h"
#include "hw/s390x/storage-keys.h"
#include "qapi/error.h"
#include "qapi/qapi-commands-misc-target.h"
@@ -152,7 +153,7 @@ void qmp_dump_skeys(const char *filename, Error **errp)
goto out;
}
- assert(qemu_mutex_iothread_locked());
+ assert(bql_locked());
guest_phys_blocks_init(&guest_phys_blocks);
guest_phys_blocks_append(&guest_phys_blocks);
@@ -432,58 +433,39 @@ static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id)
return ret;
}
-static inline bool s390_skeys_get_migration_enabled(Object *obj, Error **errp)
-{
- S390SKeysState *ss = S390_SKEYS(obj);
-
- return ss->migration_enabled;
-}
-
static SaveVMHandlers savevm_s390_storage_keys = {
.save_state = s390_storage_keys_save,
.load_state = s390_storage_keys_load,
};
-static inline void s390_skeys_set_migration_enabled(Object *obj, bool value,
- Error **errp)
+static void s390_skeys_realize(DeviceState *dev, Error **errp)
{
- S390SKeysState *ss = S390_SKEYS(obj);
-
- /* Prevent double registration of savevm handler */
- if (ss->migration_enabled == value) {
- return;
- }
-
- ss->migration_enabled = value;
+ S390SKeysState *ss = S390_SKEYS(dev);
if (ss->migration_enabled) {
register_savevm_live(TYPE_S390_SKEYS, 0, 1,
&savevm_s390_storage_keys, ss);
- } else {
- unregister_savevm(VMSTATE_IF(ss), TYPE_S390_SKEYS, ss);
}
}
-static void s390_skeys_instance_init(Object *obj)
-{
- object_property_add_bool(obj, "migration-enabled",
- s390_skeys_get_migration_enabled,
- s390_skeys_set_migration_enabled);
- object_property_set_bool(obj, "migration-enabled", true, NULL);
-}
+static Property s390_skeys_props[] = {
+ DEFINE_PROP_BOOL("migration-enabled", S390SKeysState, migration_enabled, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
static void s390_skeys_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->hotpluggable = false;
+ dc->realize = s390_skeys_realize;
+ device_class_set_props(dc, s390_skeys_props);
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
}
static const TypeInfo s390_skeys_info = {
.name = TYPE_S390_SKEYS,
.parent = TYPE_DEVICE,
- .instance_init = s390_skeys_instance_init,
.instance_size = sizeof(S390SKeysState),
.class_init = s390_skeys_class_init,
.class_size = sizeof(S390SKeysClass),
diff --git a/hw/s390x/s390-stattrib-kvm.c b/hw/s390x/s390-stattrib-kvm.c
index 24cd01382e..eeaa811098 100644
--- a/hw/s390x/s390-stattrib-kvm.c
+++ b/hw/s390x/s390-stattrib-kvm.c
@@ -17,6 +17,7 @@
#include "sysemu/kvm.h"
#include "exec/ram_addr.h"
#include "kvm/kvm_s390x.h"
+#include "qapi/error.h"
Object *kvm_s390_stattrib_create(void)
{
@@ -137,14 +138,21 @@ static void kvm_s390_stattrib_synchronize(S390StAttribState *sa)
}
}
-static int kvm_s390_stattrib_set_migrationmode(S390StAttribState *sa, bool val)
+static int kvm_s390_stattrib_set_migrationmode(S390StAttribState *sa, bool val,
+ Error **errp)
{
struct kvm_device_attr attr = {
.group = KVM_S390_VM_MIGRATION,
.attr = val,
.addr = 0,
};
- return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+ int r;
+
+ r = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+ if (r) {
+ error_setg_errno(errp, -r, "setting KVM_S390_VM_MIGRATION failed");
+ }
+ return r;
}
static long long kvm_s390_stattrib_get_dirtycount(S390StAttribState *sa)
diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c
index 9eda1c3b2a..bc04187b2b 100644
--- a/hw/s390x/s390-stattrib.c
+++ b/hw/s390x/s390-stattrib.c
@@ -13,6 +13,7 @@
#include "qemu/units.h"
#include "migration/qemu-file.h"
#include "migration/register.h"
+#include "hw/qdev-properties.h"
#include "hw/s390x/storage-attributes.h"
#include "qemu/error-report.h"
#include "exec/ram_addr.h"
@@ -59,11 +60,13 @@ void hmp_migrationmode(Monitor *mon, const QDict *qdict)
S390StAttribState *sas = s390_get_stattrib_device();
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
uint64_t what = qdict_get_int(qdict, "mode");
+ Error *local_err = NULL;
int r;
- r = sac->set_migrationmode(sas, what);
+ r = sac->set_migrationmode(sas, what, &local_err);
if (r < 0) {
- monitor_printf(mon, "Error: %s", strerror(-r));
+ monitor_printf(mon, "Error: %s", error_get_pretty(local_err));
+ error_free(local_err);
}
}
@@ -165,7 +168,7 @@ static int cmma_load(QEMUFile *f, void *opaque, int version_id)
return ret;
}
-static int cmma_save_setup(QEMUFile *f, void *opaque)
+static int cmma_save_setup(QEMUFile *f, void *opaque, Error **errp)
{
S390StAttribState *sas = S390_STATTRIB(opaque);
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
@@ -174,7 +177,7 @@ static int cmma_save_setup(QEMUFile *f, void *opaque)
* Signal that we want to start a migration, thus needing PGSTE dirty
* tracking.
*/
- res = sac->set_migrationmode(sas, 1);
+ res = sac->set_migrationmode(sas, true, errp);
if (res) {
return res;
}
@@ -182,17 +185,15 @@ static int cmma_save_setup(QEMUFile *f, void *opaque)
return 0;
}
-static void cmma_save_pending(QEMUFile *f, void *opaque, uint64_t max_size,
- uint64_t *res_precopy_only,
- uint64_t *res_compatible,
- uint64_t *res_postcopy_only)
+static void cmma_state_pending(void *opaque, uint64_t *must_precopy,
+ uint64_t *can_postcopy)
{
S390StAttribState *sas = S390_STATTRIB(opaque);
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
long long res = sac->get_dirtycount(sas);
if (res >= 0) {
- *res_precopy_only += res;
+ *must_precopy += res;
}
}
@@ -211,7 +212,7 @@ static int cmma_save(QEMUFile *f, void *opaque, int final)
return -ENOMEM;
}
- while (final ? 1 : qemu_file_rate_limit(f) == 0) {
+ while (final ? 1 : migration_rate_exceeded(f) == 0) {
reallen = sac->get_stattr(sas, &start_gfn, buflen, buf);
if (reallen < 0) {
g_free(buf);
@@ -261,7 +262,7 @@ static void cmma_save_cleanup(void *opaque)
{
S390StAttribState *sas = S390_STATTRIB(opaque);
S390StAttribClass *sac = S390_STATTRIB_GET_CLASS(sas);
- sac->set_migrationmode(sas, 0);
+ sac->set_migrationmode(sas, false, NULL);
}
static bool cmma_active(void *opaque)
@@ -294,7 +295,8 @@ static long long qemu_s390_get_dirtycount_stub(S390StAttribState *sa)
{
return 0;
}
-static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value)
+static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value,
+ Error **errp)
{
return 0;
}
@@ -332,6 +334,17 @@ static const TypeInfo qemu_s390_stattrib_info = {
/* Generic abstract object: */
+static SaveVMHandlers savevm_s390_stattrib_handlers = {
+ .save_setup = cmma_save_setup,
+ .save_live_iterate = cmma_save_iterate,
+ .save_live_complete_precopy = cmma_save_complete,
+ .state_pending_exact = cmma_state_pending,
+ .state_pending_estimate = cmma_state_pending,
+ .save_cleanup = cmma_save_cleanup,
+ .load_state = cmma_load,
+ .is_active = cmma_active,
+};
+
static void s390_stattrib_realize(DeviceState *dev, Error **errp)
{
bool ambiguous = false;
@@ -339,9 +352,18 @@ static void s390_stattrib_realize(DeviceState *dev, Error **errp)
object_resolve_path_type("", TYPE_S390_STATTRIB, &ambiguous);
if (ambiguous) {
error_setg(errp, "storage_attributes device already exists");
+ return;
}
+
+ register_savevm_live(TYPE_S390_STATTRIB, 0, 0,
+ &savevm_s390_stattrib_handlers, dev);
}
+static Property s390_stattrib_props[] = {
+ DEFINE_PROP_BOOL("migration-enabled", S390StAttribState, migration_enabled, true),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void s390_stattrib_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -349,45 +371,13 @@ static void s390_stattrib_class_init(ObjectClass *oc, void *data)
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
dc->realize = s390_stattrib_realize;
+ device_class_set_props(dc, s390_stattrib_props);
}
-static inline bool s390_stattrib_get_migration_enabled(Object *obj,
- Error **errp)
-{
- S390StAttribState *s = S390_STATTRIB(obj);
-
- return s->migration_enabled;
-}
-
-static inline void s390_stattrib_set_migration_enabled(Object *obj, bool value,
- Error **errp)
-{
- S390StAttribState *s = S390_STATTRIB(obj);
-
- s->migration_enabled = value;
-}
-
-static SaveVMHandlers savevm_s390_stattrib_handlers = {
- .save_setup = cmma_save_setup,
- .save_live_iterate = cmma_save_iterate,
- .save_live_complete_precopy = cmma_save_complete,
- .save_live_pending = cmma_save_pending,
- .save_cleanup = cmma_save_cleanup,
- .load_state = cmma_load,
- .is_active = cmma_active,
-};
-
static void s390_stattrib_instance_init(Object *obj)
{
S390StAttribState *sas = S390_STATTRIB(obj);
- register_savevm_live(TYPE_S390_STATTRIB, 0, 0,
- &savevm_s390_stattrib_handlers, sas);
-
- object_property_add_bool(obj, "migration-enabled",
- s390_stattrib_get_migration_enabled,
- s390_stattrib_set_migration_enabled);
- object_property_set_bool(obj, "migration-enabled", true, NULL);
sas->migration_cur_gfn = 0;
}
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 61aeccb163..4dcc213820 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -14,6 +14,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "exec/ram_addr.h"
+#include "exec/confidential-guest-support.h"
#include "hw/s390x/s390-virtio-hcall.h"
#include "hw/s390x/sclp.h"
#include "hw/s390x/s390_flic.h"
@@ -25,6 +26,7 @@
#include "qemu/error-report.h"
#include "qemu/option.h"
#include "qemu/qemu-print.h"
+#include "qemu/units.h"
#include "hw/s390x/s390-pci-bus.h"
#include "sysemu/reset.h"
#include "hw/s390x/storage-keys.h"
@@ -40,8 +42,11 @@
#include "hw/qdev-properties.h"
#include "hw/s390x/tod.h"
#include "sysemu/sysemu.h"
-#include "hw/s390x/pv.h"
+#include "sysemu/cpus.h"
+#include "target/s390x/kvm/pv.h"
#include "migration/blocker.h"
+#include "qapi/visitor.h"
+#include "hw/s390x/cpu-topology.h"
static Error *pv_mig_blocker;
@@ -83,8 +88,15 @@ out:
static void s390_init_cpus(MachineState *machine)
{
MachineClass *mc = MACHINE_GET_CLASS(machine);
+ S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc);
int i;
+ if (machine->smp.threads > s390mc->max_threads) {
+ error_report("S390 does not support more than %d threads.",
+ s390mc->max_threads);
+ exit(1);
+ }
+
/* initialize possible_cpus */
mc->possible_cpu_arch_ids(machine);
@@ -99,6 +111,7 @@ static const char *const reset_dev_types[] = {
"s390-flic",
"diag288",
TYPE_S390_PCI_HOST_BRIDGE,
+ TYPE_AP_BRIDGE,
};
static void subsystem_reset(void)
@@ -106,12 +119,23 @@ static void subsystem_reset(void)
DeviceState *dev;
int i;
+ /*
+ * ISM firmware is sensitive to unexpected changes to the IOMMU, which can
+ * occur during reset of the vfio-pci device (unmap of entire aperture).
+ * Ensure any passthrough ISM devices are reset now, while CPUs are paused
+ * but before vfio-pci cleanup occurs.
+ */
+ s390_pci_ism_reset();
+
for (i = 0; i < ARRAY_SIZE(reset_dev_types); i++) {
dev = DEVICE(object_resolve_path_type("", reset_dev_types[i], NULL));
if (dev) {
- qdev_reset_all(dev);
+ device_cold_reset(dev);
}
}
+ if (s390_has_topology()) {
+ s390_topology_reset();
+ }
}
static int virtio_ccw_hcall_notify(const uint64_t *args)
@@ -206,20 +230,9 @@ static void s390_init_ipl_dev(const char *kernel_filename,
static void s390_create_virtio_net(BusState *bus, const char *name)
{
- int i;
-
- for (i = 0; i < nb_nics; i++) {
- NICInfo *nd = &nd_table[i];
- DeviceState *dev;
-
- if (!nd->model) {
- nd->model = g_strdup("virtio");
- }
-
- qemu_check_nic_model(nd, "virtio");
+ DeviceState *dev;
- dev = qdev_new(name);
- qdev_set_nic_properties(dev, nd);
+ while ((dev = qemu_create_nic_device(name, true, "virtio"))) {
qdev_realize_and_unref(dev, bus, &error_fatal);
}
}
@@ -235,6 +248,7 @@ static void s390_create_sclpconsole(const char *type, Chardev *chardev)
static void ccw_init(MachineState *machine)
{
+ MachineClass *mc = MACHINE_GET_CLASS(machine);
int ret;
VirtualCssBus *css_bus;
DeviceState *dev;
@@ -247,7 +261,9 @@ static void ccw_init(MachineState *machine)
s390_init_cpus(machine);
/* Need CPU model to be determined before we can set up PV */
- s390_pv_init(machine->cgs, &error_fatal);
+ if (machine->cgs) {
+ confidential_guest_kvm_init(machine->cgs, &error_fatal);
+ }
s390_flic_init();
@@ -282,7 +298,7 @@ static void ccw_init(MachineState *machine)
}
/* Create VirtIO network adapters */
- s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw");
+ s390_create_virtio_net(BUS(css_bus), mc->default_nic);
/* init consoles */
if (serial_hd(0)) {
@@ -299,11 +315,19 @@ static void ccw_init(MachineState *machine)
static void s390_cpu_plug(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
+ ERRP_GUARD();
MachineState *ms = MACHINE(hotplug_dev);
S390CPU *cpu = S390_CPU(dev);
g_assert(!ms->possible_cpus->cpus[cpu->env.core_id].cpu);
- ms->possible_cpus->cpus[cpu->env.core_id].cpu = OBJECT(dev);
+ ms->possible_cpus->cpus[cpu->env.core_id].cpu = CPU(dev);
+
+ if (s390_has_topology()) {
+ s390_topology_setup_cpu(ms, cpu, errp);
+ if (*errp) {
+ return;
+ }
+ }
if (dev->hotplugged) {
raise_irq_cpu_hotplug();
@@ -320,10 +344,11 @@ static inline void s390_do_cpu_ipl(CPUState *cs, run_on_cpu_data arg)
static void s390_machine_unprotect(S390CcwMachineState *ms)
{
- s390_pv_vm_disable();
+ if (!s390_pv_vm_try_disable_async(ms)) {
+ s390_pv_vm_disable();
+ }
ms->pv = false;
- migrate_del_blocker(pv_mig_blocker);
- error_free_or_abort(&pv_mig_blocker);
+ migrate_del_blocker(&pv_mig_blocker);
ram_block_discard_disable(false);
}
@@ -345,12 +370,11 @@ static int s390_machine_protect(S390CcwMachineState *ms)
}
error_setg(&pv_mig_blocker,
- "protected VMs are currently not migrateable.");
- rc = migrate_add_blocker(pv_mig_blocker, &local_err);
+ "protected VMs are currently not migratable.");
+ rc = migrate_add_blocker(&pv_mig_blocker, &local_err);
if (rc) {
ram_block_discard_disable(false);
error_report_err(local_err);
- error_free_or_abort(&pv_mig_blocker);
return rc;
}
@@ -358,15 +382,20 @@ static int s390_machine_protect(S390CcwMachineState *ms)
rc = s390_pv_vm_enable();
if (rc) {
ram_block_discard_disable(false);
- migrate_del_blocker(pv_mig_blocker);
- error_free_or_abort(&pv_mig_blocker);
+ migrate_del_blocker(&pv_mig_blocker);
return rc;
}
ms->pv = true;
+ /* Will return 0 if API is not available since it's not vital */
+ rc = s390_pv_query_info();
+ if (rc) {
+ goto out_err;
+ }
+
/* Set SE header and unpack */
- rc = s390_ipl_prepare_pv_header();
+ rc = s390_ipl_prepare_pv_header(&local_err);
if (rc) {
goto out_err;
}
@@ -385,6 +414,9 @@ static int s390_machine_protect(S390CcwMachineState *ms)
return rc;
out_err:
+ if (local_err) {
+ error_report_err(local_err);
+ }
s390_machine_unprotect(ms);
return rc;
}
@@ -404,7 +436,7 @@ static void s390_pv_prepare_reset(S390CcwMachineState *ms)
s390_pv_prep_reset();
}
-static void s390_machine_reset(MachineState *machine)
+static void s390_machine_reset(MachineState *machine, ShutdownCause reason)
{
S390CcwMachineState *ms = S390_CCW_MACHINE(machine);
enum s390_reset reset_type;
@@ -422,11 +454,21 @@ static void s390_machine_reset(MachineState *machine)
switch (reset_type) {
case S390_RESET_EXTERNAL:
case S390_RESET_REIPL:
+ /*
+ * Reset the subsystem which includes a AP reset. If a PV
+ * guest had APQNs attached the AP reset is a prerequisite to
+ * unprotecting since the UV checks if all APQNs are reset.
+ */
+ subsystem_reset();
if (s390_is_pv()) {
s390_machine_unprotect(ms);
}
- qemu_devices_reset();
+ /*
+ * Device reset includes CPU clear resets so this has to be
+ * done AFTER the unprotect call above.
+ */
+ qemu_devices_reset(reason);
s390_crypto_reset();
/* configure and start the ipl CPU only */
@@ -434,7 +476,7 @@ static void s390_machine_reset(MachineState *machine)
break;
case S390_RESET_MODIFIED_CLEAR:
/*
- * Susbsystem reset needs to be done before we unshare memory
+ * Subsystem reset needs to be done before we unshare memory
* and lose access to VIRTIO structures in guest memory.
*/
subsystem_reset();
@@ -447,7 +489,7 @@ static void s390_machine_reset(MachineState *machine)
break;
case S390_RESET_LOAD_NORMAL:
/*
- * Susbsystem reset needs to be done before we unshare memory
+ * Subsystem reset needs to be done before we unshare memory
* and lose access to VIRTIO structures in guest memory.
*/
subsystem_reset();
@@ -536,11 +578,20 @@ static const CPUArchIdList *s390_possible_cpu_arch_ids(MachineState *ms)
sizeof(CPUArchId) * max_cpus);
ms->possible_cpus->len = max_cpus;
for (i = 0; i < ms->possible_cpus->len; i++) {
+ CpuInstanceProperties *props = &ms->possible_cpus->cpus[i].props;
+
ms->possible_cpus->cpus[i].type = ms->cpu_type;
ms->possible_cpus->cpus[i].vcpus_count = 1;
ms->possible_cpus->cpus[i].arch_id = i;
- ms->possible_cpus->cpus[i].props.has_core_id = true;
- ms->possible_cpus->cpus[i].props.core_id = i;
+
+ props->has_core_id = true;
+ props->core_id = i;
+ props->has_socket_id = true;
+ props->socket_id = s390_std_socket(i, &ms->smp);
+ props->has_book_id = true;
+ props->book_id = s390_std_book(i, &ms->smp);
+ props->has_drawer_id = true;
+ props->drawer_id = s390_std_drawer(i, &ms->smp);
}
return ms->possible_cpus;
@@ -582,38 +633,6 @@ static ram_addr_t s390_fixup_ram_size(ram_addr_t sz)
return newsz;
}
-static void ccw_machine_class_init(ObjectClass *oc, void *data)
-{
- MachineClass *mc = MACHINE_CLASS(oc);
- NMIClass *nc = NMI_CLASS(oc);
- HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
- S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc);
-
- s390mc->ri_allowed = true;
- s390mc->cpu_model_allowed = true;
- s390mc->css_migration_enabled = true;
- s390mc->hpage_1m_allowed = true;
- mc->init = ccw_init;
- mc->reset = s390_machine_reset;
- mc->block_default_type = IF_VIRTIO;
- mc->no_cdrom = 1;
- mc->no_floppy = 1;
- mc->no_parallel = 1;
- mc->no_sdcard = 1;
- mc->max_cpus = S390_MAX_CPUS;
- mc->has_hotpluggable_cpus = true;
- assert(!mc->get_hotplug_handler);
- mc->get_hotplug_handler = s390_get_hotplug_handler;
- mc->cpu_index_to_instance_props = s390_cpu_index_to_props;
- 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->plug = s390_machine_device_plug;
- hc->unplug_request = s390_machine_device_unplug_request;
- nc->nmi_monitor_handler = s390_nmi;
- mc->default_ram_id = "s390.ram";
-}
-
static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp)
{
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
@@ -688,19 +707,29 @@ bool hpage_1m_allowed(void)
return get_machine_class()->hpage_1m_allowed;
}
-static char *machine_get_loadparm(Object *obj, Error **errp)
+static void machine_get_loadparm(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
{
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+ char *str = g_strndup((char *) ms->loadparm, sizeof(ms->loadparm));
- /* make a NUL-terminated string */
- return g_strndup((char *) ms->loadparm, sizeof(ms->loadparm));
+ visit_type_str(v, name, &str, errp);
+ g_free(str);
}
-static void machine_set_loadparm(Object *obj, const char *val, Error **errp)
+static void machine_set_loadparm(Object *obj, Visitor *v,
+ const char *name, void *opaque,
+ Error **errp)
{
S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+ char *val;
int i;
+ if (!visit_type_str(v, name, &val, errp)) {
+ return;
+ }
+
for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) {
uint8_t c = qemu_toupper(val[i]); /* mimic HMC */
@@ -718,29 +747,71 @@ static void machine_set_loadparm(Object *obj, const char *val, Error **errp)
ms->loadparm[i] = ' '; /* pad right with spaces */
}
}
-static inline void s390_machine_initfn(Object *obj)
+
+static void ccw_machine_class_init(ObjectClass *oc, void *data)
{
- object_property_add_bool(obj, "aes-key-wrap",
- machine_get_aes_key_wrap,
- machine_set_aes_key_wrap);
- object_property_set_description(obj, "aes-key-wrap",
+ MachineClass *mc = MACHINE_CLASS(oc);
+ NMIClass *nc = NMI_CLASS(oc);
+ HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc);
+ S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc);
+
+ s390mc->ri_allowed = true;
+ s390mc->cpu_model_allowed = true;
+ s390mc->css_migration_enabled = true;
+ s390mc->hpage_1m_allowed = true;
+ s390mc->max_threads = 1;
+ mc->init = ccw_init;
+ mc->reset = s390_machine_reset;
+ mc->block_default_type = IF_VIRTIO;
+ mc->no_cdrom = 1;
+ mc->no_floppy = 1;
+ mc->no_parallel = 1;
+ mc->no_sdcard = 1;
+ mc->max_cpus = S390_MAX_CPUS;
+ mc->has_hotpluggable_cpus = true;
+ mc->smp_props.books_supported = true;
+ mc->smp_props.drawers_supported = true;
+ assert(!mc->get_hotplug_handler);
+ mc->get_hotplug_handler = s390_get_hotplug_handler;
+ mc->cpu_index_to_instance_props = s390_cpu_index_to_props;
+ 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->plug = s390_machine_device_plug;
+ hc->unplug_request = s390_machine_device_unplug_request;
+ nc->nmi_monitor_handler = s390_nmi;
+ mc->default_ram_id = "s390.ram";
+ mc->default_nic = "virtio-net-ccw";
+
+ object_class_property_add_bool(oc, "aes-key-wrap",
+ machine_get_aes_key_wrap,
+ machine_set_aes_key_wrap);
+ object_class_property_set_description(oc, "aes-key-wrap",
"enable/disable AES key wrapping using the CPACF wrapping key");
- object_property_set_bool(obj, "aes-key-wrap", true, NULL);
- object_property_add_bool(obj, "dea-key-wrap",
- machine_get_dea_key_wrap,
- machine_set_dea_key_wrap);
- object_property_set_description(obj, "dea-key-wrap",
+ object_class_property_add_bool(oc, "dea-key-wrap",
+ machine_get_dea_key_wrap,
+ machine_set_dea_key_wrap);
+ object_class_property_set_description(oc, "dea-key-wrap",
"enable/disable DEA key wrapping using the CPACF wrapping key");
- object_property_set_bool(obj, "dea-key-wrap", true, NULL);
- object_property_add_str(obj, "loadparm",
- machine_get_loadparm, machine_set_loadparm);
- object_property_set_description(obj, "loadparm",
+
+ object_class_property_add(oc, "loadparm", "loadparm",
+ machine_get_loadparm, machine_set_loadparm,
+ NULL, NULL);
+ object_class_property_set_description(oc, "loadparm",
"Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted"
" to upper case) to pass to machine loader, boot manager,"
" and guest kernel");
}
+static inline void s390_machine_initfn(Object *obj)
+{
+ S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+
+ ms->aes_key_wrap = true;
+ ms->dea_key_wrap = true;
+}
+
static const TypeInfo ccw_machine_info = {
.name = TYPE_S390_CCW_MACHINE,
.parent = TYPE_MACHINE,
@@ -767,7 +838,7 @@ bool css_migration_enabled(void)
{ \
MachineClass *mc = MACHINE_CLASS(oc); \
ccw_machine_##suffix##_class_options(mc); \
- mc->desc = "VirtIO-ccw based S390 machine v" verstr; \
+ mc->desc = "Virtual s390x machine (version " verstr ")"; \
if (latest) { \
mc->alias = "s390-ccw-virtio"; \
mc->is_default = true; \
@@ -791,14 +862,130 @@ bool css_migration_enabled(void)
} \
type_init(ccw_machine_register_##suffix)
+static void ccw_machine_9_1_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_machine_9_1_class_options(MachineClass *mc)
+{
+}
+DEFINE_CCW_MACHINE(9_1, "9.1", true);
+
+static void ccw_machine_9_0_instance_options(MachineState *machine)
+{
+ ccw_machine_9_1_instance_options(machine);
+}
+
+static void ccw_machine_9_0_class_options(MachineClass *mc)
+{
+ ccw_machine_9_1_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_9_0, hw_compat_9_0_len);
+}
+DEFINE_CCW_MACHINE(9_0, "9.0", false);
+
+static void ccw_machine_8_2_instance_options(MachineState *machine)
+{
+ ccw_machine_9_0_instance_options(machine);
+}
+
+static void ccw_machine_8_2_class_options(MachineClass *mc)
+{
+ ccw_machine_9_0_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_8_2, hw_compat_8_2_len);
+}
+DEFINE_CCW_MACHINE(8_2, "8.2", false);
+
+static void ccw_machine_8_1_instance_options(MachineState *machine)
+{
+ ccw_machine_8_2_instance_options(machine);
+}
+
+static void ccw_machine_8_1_class_options(MachineClass *mc)
+{
+ ccw_machine_8_2_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_8_1, hw_compat_8_1_len);
+ mc->smp_props.drawers_supported = false;
+ mc->smp_props.books_supported = false;
+}
+DEFINE_CCW_MACHINE(8_1, "8.1", false);
+
+static void ccw_machine_8_0_instance_options(MachineState *machine)
+{
+ ccw_machine_8_1_instance_options(machine);
+}
+
+static void ccw_machine_8_0_class_options(MachineClass *mc)
+{
+ ccw_machine_8_1_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_8_0, hw_compat_8_0_len);
+}
+DEFINE_CCW_MACHINE(8_0, "8.0", false);
+
+static void ccw_machine_7_2_instance_options(MachineState *machine)
+{
+ ccw_machine_8_0_instance_options(machine);
+}
+
+static void ccw_machine_7_2_class_options(MachineClass *mc)
+{
+ ccw_machine_8_0_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_7_2, hw_compat_7_2_len);
+}
+DEFINE_CCW_MACHINE(7_2, "7.2", false);
+
+static void ccw_machine_7_1_instance_options(MachineState *machine)
+{
+ static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V7_1 };
+
+ ccw_machine_7_2_instance_options(machine);
+ s390_cpudef_featoff_greater(16, 1, S390_FEAT_PAIE);
+ s390_set_qemu_cpu_model(0x8561, 15, 1, qemu_cpu_feat);
+}
+
+static void ccw_machine_7_1_class_options(MachineClass *mc)
+{
+ S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc);
+ static GlobalProperty compat[] = {
+ { TYPE_S390_PCI_DEVICE, "interpret", "off", },
+ { TYPE_S390_PCI_DEVICE, "forwarding-assist", "off", },
+ };
+
+ ccw_machine_7_2_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_7_1, hw_compat_7_1_len);
+ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat));
+ s390mc->max_threads = S390_MAX_CPUS;
+}
+DEFINE_CCW_MACHINE(7_1, "7.1", false);
+
+static void ccw_machine_7_0_instance_options(MachineState *machine)
+{
+ static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V7_0 };
+
+ ccw_machine_7_1_instance_options(machine);
+ s390_set_qemu_cpu_model(0x8561, 15, 1, qemu_cpu_feat);
+}
+
+static void ccw_machine_7_0_class_options(MachineClass *mc)
+{
+ ccw_machine_7_1_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_7_0, hw_compat_7_0_len);
+}
+DEFINE_CCW_MACHINE(7_0, "7.0", false);
+
static void ccw_machine_6_2_instance_options(MachineState *machine)
{
+ static const S390FeatInit qemu_cpu_feat = { S390_FEAT_LIST_QEMU_V6_2 };
+
+ ccw_machine_7_0_instance_options(machine);
+ s390_set_qemu_cpu_model(0x3906, 14, 2, qemu_cpu_feat);
}
static void ccw_machine_6_2_class_options(MachineClass *mc)
{
+ ccw_machine_7_0_class_options(mc);
+ compat_props_add(mc->compat_props, hw_compat_6_2, hw_compat_6_2_len);
}
-DEFINE_CCW_MACHINE(6_2, "6.2", true);
+DEFINE_CCW_MACHINE(6_2, "6.2", false);
static void ccw_machine_6_1_instance_options(MachineState *machine)
{
@@ -814,6 +1001,7 @@ static void ccw_machine_6_1_class_options(MachineClass *mc)
{
ccw_machine_6_2_class_options(mc);
compat_props_add(mc->compat_props, hw_compat_6_1, hw_compat_6_1_len);
+ mc->smp_props.prefer_sockets = true;
}
DEFINE_CCW_MACHINE(6_1, "6.1", false);
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index 89c30a8a91..893e71a41b 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -20,6 +20,7 @@
#include "hw/s390x/event-facility.h"
#include "hw/s390x/s390-pci-bus.h"
#include "hw/s390x/ipl.h"
+#include "hw/s390x/cpu-topology.h"
static inline SCLPDevice *get_sclp_device(void)
{
@@ -123,6 +124,10 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
return;
}
+ if (s390_has_topology()) {
+ read_info->stsi_parm = SCLP_READ_SCP_INFO_MNEST;
+ }
+
/* CPU information */
prepare_cpu_entries(machine, entries_start, &cpu_count);
read_info->entries_cpu = cpu_to_be16(cpu_count);
@@ -264,9 +269,9 @@ static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code)
* service_interrupt call.
*/
#define SCLP_PV_DUMMY_ADDR 0x4000
-int sclp_service_call_protected(CPUS390XState *env, uint64_t sccb,
- uint32_t code)
+int sclp_service_call_protected(S390CPU *cpu, uint64_t sccb, uint32_t code)
{
+ CPUS390XState *env = &cpu->env;
SCLPDevice *sclp = get_sclp_device();
SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
SCCBHeader header;
@@ -291,8 +296,9 @@ out_write:
return 0;
}
-int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
+int sclp_service_call(S390CPU *cpu, uint64_t sccb, uint32_t code)
{
+ CPUS390XState *env = &cpu->env;
SCLPDevice *sclp = get_sclp_device();
SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
SCCBHeader header;
@@ -460,7 +466,7 @@ static void sclp_class_init(ObjectClass *oc, void *data)
sc->service_interrupt = service_interrupt;
}
-static TypeInfo sclp_info = {
+static const TypeInfo sclp_info = {
.name = TYPE_SCLP,
.parent = TYPE_DEVICE,
.instance_init = sclp_init,
diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c
index f2b1a4b037..fa79891f5a 100644
--- a/hw/s390x/sclpcpu.c
+++ b/hw/s390x/sclpcpu.c
@@ -73,7 +73,7 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
return 1;
}
-static void cpu_class_init(ObjectClass *oc, void *data)
+static void sclp_cpu_class_init(ObjectClass *oc, void *data)
{
SCLPEventClass *k = SCLP_EVENT_CLASS(oc);
DeviceClass *dc = DEVICE_CLASS(oc);
@@ -94,7 +94,7 @@ static const TypeInfo sclp_cpu_info = {
.name = TYPE_SCLP_CPU_HOTPLUG,
.parent = TYPE_SCLP_EVENT,
.instance_size = sizeof(SCLPEvent),
- .class_init = cpu_class_init,
+ .class_init = sclp_cpu_class_init,
.class_size = sizeof(SCLPEventClass),
};
diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c
index ce07b16884..14936aa94b 100644
--- a/hw/s390x/sclpquiesce.c
+++ b/hw/s390x/sclpquiesce.c
@@ -72,18 +72,16 @@ static const VMStateDescription vmstate_sclpquiesce = {
.name = TYPE_SCLP_QUIESCE,
.version_id = 0,
.minimum_version_id = 0,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_BOOL(event_pending, SCLPEvent),
VMSTATE_END_OF_LIST()
}
};
-typedef struct QuiesceNotifier QuiesceNotifier;
-
-static struct QuiesceNotifier {
+typedef struct QuiesceNotifier {
Notifier notifier;
SCLPEvent *event;
-} qn;
+} QuiesceNotifier;
static void quiesce_powerdown_req(Notifier *n, void *opaque)
{
@@ -97,6 +95,8 @@ static void quiesce_powerdown_req(Notifier *n, void *opaque)
static int quiesce_init(SCLPEvent *event)
{
+ static QuiesceNotifier qn;
+
qn.notifier.notify = quiesce_powerdown_req;
qn.event = event;
diff --git a/hw/s390x/tod-kvm.c b/hw/s390x/tod-kvm.c
index ec855811ae..9588b90f2b 100644
--- a/hw/s390x/tod-kvm.c
+++ b/hw/s390x/tod-kvm.c
@@ -13,6 +13,7 @@
#include "qemu/module.h"
#include "sysemu/runstate.h"
#include "hw/s390x/tod.h"
+#include "target/s390x/kvm/pv.h"
#include "kvm/kvm_s390x.h"
static void kvm_s390_get_tod_raw(S390TOD *tod, Error **errp)
@@ -84,6 +85,14 @@ static void kvm_s390_tod_vm_state_change(void *opaque, bool running,
S390TODState *td = opaque;
Error *local_err = NULL;
+ /*
+ * Under PV, the clock is under ultravisor control, hence we cannot restore
+ * it on resume.
+ */
+ if (s390_is_pv()) {
+ return;
+ }
+
if (running && td->stopped) {
/* Set the old TOD when running the VM - start the TOD clock. */
kvm_s390_set_tod_raw(&td->base, &local_err);
@@ -147,7 +156,7 @@ static void kvm_s390_tod_init(Object *obj)
td->stopped = false;
}
-static TypeInfo kvm_s390_tod_info = {
+static const TypeInfo kvm_s390_tod_info = {
.name = TYPE_KVM_S390_TOD,
.parent = TYPE_S390_TOD,
.instance_size = sizeof(S390TODState),
diff --git a/hw/s390x/tod-tcg.c b/hw/s390x/tod-tcg.c
index 9bb94ff72b..2d540dba65 100644
--- a/hw/s390x/tod-tcg.c
+++ b/hw/s390x/tod-tcg.c
@@ -9,7 +9,6 @@
*/
#include "qemu/osdep.h"
-#include "qemu-common.h"
#include "qapi/error.h"
#include "hw/s390x/tod.h"
#include "qemu/timer.h"
@@ -17,6 +16,7 @@
#include "qemu/module.h"
#include "cpu.h"
#include "tcg/tcg_s390x.h"
+#include "sysemu/rtc.h"
static void qemu_s390_tod_get(const S390TODState *td, S390TOD *tod,
Error **errp)
@@ -73,7 +73,7 @@ static void qemu_s390_tod_init(Object *obj)
}
}
-static TypeInfo qemu_s390_tod_info = {
+static const TypeInfo qemu_s390_tod_info = {
.name = TYPE_QEMU_S390_TOD,
.parent = TYPE_S390_TOD,
.instance_size = sizeof(S390TODState),
diff --git a/hw/s390x/tod.c b/hw/s390x/tod.c
index fd5a36bf24..c81b1c0338 100644
--- a/hw/s390x/tod.c
+++ b/hw/s390x/tod.c
@@ -123,7 +123,7 @@ static void s390_tod_class_init(ObjectClass *oc, void *data)
dc->user_creatable = false;
}
-static TypeInfo s390_tod_info = {
+static const TypeInfo s390_tod_info = {
.name = TYPE_S390_TOD,
.parent = TYPE_DEVICE,
.instance_size = sizeof(S390TODState),
diff --git a/hw/s390x/trace-events b/hw/s390x/trace-events
index 8b9213eab9..34da5ea323 100644
--- a/hw/s390x/trace-events
+++ b/hw/s390x/trace-events
@@ -19,3 +19,20 @@ virtio_ccw_set_ind(uint64_t ind_loc, uint8_t ind_old, uint8_t ind_new) "VIRTIO-C
s390_pci_clp_cap(const char *id, uint32_t cap) "PCI: %s: missing expected CLP capability %u"
s390_pci_clp_cap_size(const char *id, uint32_t size, uint32_t cap) "PCI: %s: bad size (%u) for CLP capability %u"
s390_pci_clp_dev_info(const char *id) "PCI: %s: cannot read vfio device info"
+
+# s390-pci-bus.c
+s390_pci_sclp_nodev(const char *str, uint32_t aid) "%s no dev found aid 0x%x"
+s390_pci_iommu_xlate(uint64_t addr) "iommu trans addr 0x%" PRIx64
+s390_pci_msi_ctrl_write(uint64_t data, uint32_t idx, uint32_t vec) "write_msix data 0x%" PRIx64 " idx %d vec 0x%x"
+s390_pcihost(const char *msg) "%s"
+
+# s390-pci-inst.c
+s390_pci_irqs(const char *str, uint32_t id) "%s irqs for adapter id %d"
+s390_pci_kvm_aif(const char *str) "Failed to %s interrupt forwarding"
+
+s390_pci_list_entry(uint32_t g_l2, uint32_t vid, uint32_t did, uint32_t fid, uint32_t fh) "g_l2 %d vendor id 0x%x device id 0x%x fid 0x%x fh 0x%x"
+s390_pci_list(uint32_t rc) "failed rc 0x%x"
+s390_pci_unknown(const char *msg, uint32_t cmd) "%s unknown command 0x%x"
+s390_pci_bar(uint32_t bar, uint32_t addr, uint64_t size, uint32_t barsize) "bar %d addr 0x%x size 0x%" PRIx64 "barsize 0x%x"
+s390_pci_nodev(const char *cmd, uint32_t fh) "%s no pci dev fh 0x%x"
+s390_pci_invalid(const char *cmd, uint32_t fh) "%s invalid space fh 0x%x"
diff --git a/hw/s390x/vhost-scsi-ccw.c b/hw/s390x/vhost-scsi-ccw.c
new file mode 100644
index 0000000000..40dc14bbc7
--- /dev/null
+++ b/hw/s390x/vhost-scsi-ccw.c
@@ -0,0 +1,73 @@
+/*
+ * vhost ccw scsi implementation
+ *
+ * Copyright 2012, 2015 IBM Corp.
+ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/virtio.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "virtio-ccw.h"
+#include "hw/virtio/vhost-scsi.h"
+
+#define TYPE_VHOST_SCSI_CCW "vhost-scsi-ccw"
+OBJECT_DECLARE_SIMPLE_TYPE(VHostSCSICcw, VHOST_SCSI_CCW)
+
+struct VHostSCSICcw {
+ VirtioCcwDevice parent_obj;
+ VHostSCSI vdev;
+};
+
+static void vhost_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp)
+{
+ VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_realize(vdev, BUS(&ccw_dev->bus), errp);
+}
+
+static void vhost_ccw_scsi_instance_init(Object *obj)
+{
+ VHostSCSICcw *dev = VHOST_SCSI_CCW(obj);
+
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+ TYPE_VHOST_SCSI);
+}
+
+static Property vhost_ccw_scsi_properties[] = {
+ DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
+ VIRTIO_CCW_MAX_REV),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
+
+ k->realize = vhost_ccw_scsi_realize;
+ device_class_set_props(dc, vhost_ccw_scsi_properties);
+ set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+}
+
+static const TypeInfo vhost_ccw_scsi = {
+ .name = TYPE_VHOST_SCSI_CCW,
+ .parent = TYPE_VIRTIO_CCW_DEVICE,
+ .instance_size = sizeof(VHostSCSICcw),
+ .instance_init = vhost_ccw_scsi_instance_init,
+ .class_init = vhost_ccw_scsi_class_init,
+};
+
+static void virtio_ccw_scsi_register(void)
+{
+ type_register_static(&vhost_ccw_scsi);
+}
+
+type_init(virtio_ccw_scsi_register)
diff --git a/hw/s390x/vhost-vsock-ccw.c b/hw/s390x/vhost-vsock-ccw.c
index 246416a8f9..07845a9a00 100644
--- a/hw/s390x/vhost-vsock-ccw.c
+++ b/hw/s390x/vhost-vsock-ccw.c
@@ -12,6 +12,15 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "virtio-ccw.h"
+#include "hw/virtio/vhost-vsock.h"
+
+#define TYPE_VHOST_VSOCK_CCW "vhost-vsock-ccw"
+OBJECT_DECLARE_SIMPLE_TYPE(VHostVSockCCWState, VHOST_VSOCK_CCW)
+
+struct VHostVSockCCWState {
+ VirtioCcwDevice parent_obj;
+ VHostVSock vdev;
+};
static Property vhost_vsock_ccw_properties[] = {
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
diff --git a/hw/s390x/virtio-ccw-9p.c b/hw/s390x/virtio-ccw-9p.c
index 88c8884fc5..6f931f5994 100644
--- a/hw/s390x/virtio-ccw-9p.c
+++ b/hw/s390x/virtio-ccw-9p.c
@@ -15,6 +15,15 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "virtio-ccw.h"
+#include "hw/9pfs/virtio-9p.h"
+
+#define TYPE_VIRTIO_9P_CCW "virtio-9p-ccw"
+OBJECT_DECLARE_SIMPLE_TYPE(V9fsCCWState, VIRTIO_9P_CCW)
+
+struct V9fsCCWState {
+ VirtioCcwDevice parent_obj;
+ V9fsVirtioState vdev;
+};
static void virtio_ccw_9p_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
diff --git a/hw/s390x/virtio-ccw-balloon.c b/hw/s390x/virtio-ccw-balloon.c
index 4c7631a433..44287b9bbe 100644
--- a/hw/s390x/virtio-ccw-balloon.c
+++ b/hw/s390x/virtio-ccw-balloon.c
@@ -15,6 +15,15 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "virtio-ccw.h"
+#include "hw/virtio/virtio-balloon.h"
+
+#define TYPE_VIRTIO_BALLOON_CCW "virtio-balloon-ccw"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBalloonCcw, VIRTIO_BALLOON_CCW)
+
+struct VirtIOBalloonCcw {
+ VirtioCcwDevice parent_obj;
+ VirtIOBalloon vdev;
+};
static void virtio_ccw_balloon_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
diff --git a/hw/s390x/virtio-ccw-blk.c b/hw/s390x/virtio-ccw-blk.c
index 2294ce1ce4..8e0e58b77d 100644
--- a/hw/s390x/virtio-ccw-blk.c
+++ b/hw/s390x/virtio-ccw-blk.c
@@ -15,6 +15,15 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "virtio-ccw.h"
+#include "hw/virtio/virtio-blk.h"
+
+#define TYPE_VIRTIO_BLK_CCW "virtio-blk-ccw"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBlkCcw, VIRTIO_BLK_CCW)
+
+struct VirtIOBlkCcw {
+ VirtioCcwDevice parent_obj;
+ VirtIOBlock vdev;
+};
static void virtio_ccw_blk_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
diff --git a/hw/s390x/virtio-ccw-crypto.c b/hw/s390x/virtio-ccw-crypto.c
index 358c74fb4b..0fa2f89443 100644
--- a/hw/s390x/virtio-ccw-crypto.c
+++ b/hw/s390x/virtio-ccw-crypto.c
@@ -14,6 +14,15 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "virtio-ccw.h"
+#include "hw/virtio/virtio-crypto.h"
+
+#define TYPE_VIRTIO_CRYPTO_CCW "virtio-crypto-ccw"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIOCryptoCcw, VIRTIO_CRYPTO_CCW)
+
+struct VirtIOCryptoCcw {
+ VirtioCcwDevice parent_obj;
+ VirtIOCrypto vdev;
+};
static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
diff --git a/hw/s390x/virtio-ccw-gpu.c b/hw/s390x/virtio-ccw-gpu.c
index 5868a2a070..0642c5281d 100644
--- a/hw/s390x/virtio-ccw-gpu.c
+++ b/hw/s390x/virtio-ccw-gpu.c
@@ -14,6 +14,15 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "virtio-ccw.h"
+#include "hw/virtio/virtio-gpu.h"
+
+#define TYPE_VIRTIO_GPU_CCW "virtio-gpu-ccw"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUCcw, VIRTIO_GPU_CCW)
+
+struct VirtIOGPUCcw {
+ VirtioCcwDevice parent_obj;
+ VirtIOGPU vdev;
+};
static void virtio_ccw_gpu_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
@@ -60,6 +69,7 @@ static const TypeInfo virtio_ccw_gpu = {
.class_init = virtio_ccw_gpu_class_init,
};
module_obj(TYPE_VIRTIO_GPU_CCW);
+module_kconfig(VIRTIO_CCW);
static void virtio_ccw_gpu_register(void)
{
diff --git a/hw/s390x/virtio-ccw-input.c b/hw/s390x/virtio-ccw-input.c
index 83136fbba1..61a07ba38d 100644
--- a/hw/s390x/virtio-ccw-input.c
+++ b/hw/s390x/virtio-ccw-input.c
@@ -14,6 +14,26 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "virtio-ccw.h"
+#include "hw/virtio/virtio-input.h"
+
+#define TYPE_VIRTIO_INPUT_CCW "virtio-input-ccw"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIOInputCcw, VIRTIO_INPUT_CCW)
+
+struct VirtIOInputCcw {
+ VirtioCcwDevice parent_obj;
+ VirtIOInput vdev;
+};
+
+#define TYPE_VIRTIO_INPUT_HID_CCW "virtio-input-hid-ccw"
+#define TYPE_VIRTIO_KEYBOARD_CCW "virtio-keyboard-ccw"
+#define TYPE_VIRTIO_MOUSE_CCW "virtio-mouse-ccw"
+#define TYPE_VIRTIO_TABLET_CCW "virtio-tablet-ccw"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIOInputHIDCcw, VIRTIO_INPUT_HID_CCW)
+
+struct VirtIOInputHIDCcw {
+ VirtioCcwDevice parent_obj;
+ VirtIOInputHID vdev;
+};
static void virtio_ccw_input_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
diff --git a/hw/s390x/virtio-ccw-net.c b/hw/s390x/virtio-ccw-net.c
index 3860d4e6ea..484e617659 100644
--- a/hw/s390x/virtio-ccw-net.c
+++ b/hw/s390x/virtio-ccw-net.c
@@ -15,6 +15,15 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "virtio-ccw.h"
+#include "hw/virtio/virtio-net.h"
+
+#define TYPE_VIRTIO_NET_CCW "virtio-net-ccw"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIONetCcw, VIRTIO_NET_CCW)
+
+struct VirtIONetCcw {
+ VirtioCcwDevice parent_obj;
+ VirtIONet vdev;
+};
static void virtio_ccw_net_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
diff --git a/hw/s390x/virtio-ccw-rng.c b/hw/s390x/virtio-ccw-rng.c
index 2e3a9da5e8..a3fffb5138 100644
--- a/hw/s390x/virtio-ccw-rng.c
+++ b/hw/s390x/virtio-ccw-rng.c
@@ -15,6 +15,15 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "virtio-ccw.h"
+#include "hw/virtio/virtio-rng.h"
+
+#define TYPE_VIRTIO_RNG_CCW "virtio-rng-ccw"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIORNGCcw, VIRTIO_RNG_CCW)
+
+struct VirtIORNGCcw {
+ VirtioCcwDevice parent_obj;
+ VirtIORNG vdev;
+};
static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
diff --git a/hw/s390x/virtio-ccw-scsi.c b/hw/s390x/virtio-ccw-scsi.c
index 6e4beef700..d003f89f43 100644
--- a/hw/s390x/virtio-ccw-scsi.c
+++ b/hw/s390x/virtio-ccw-scsi.c
@@ -15,6 +15,15 @@
#include "qapi/error.h"
#include "qemu/module.h"
#include "virtio-ccw.h"
+#include "hw/virtio/virtio-scsi.h"
+
+#define TYPE_VIRTIO_SCSI_CCW "virtio-scsi-ccw"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtIOSCSICcw, VIRTIO_SCSI_CCW)
+
+struct VirtIOSCSICcw {
+ VirtioCcwDevice parent_obj;
+ VirtIOSCSI vdev;
+};
static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
@@ -70,56 +79,9 @@ static const TypeInfo virtio_ccw_scsi = {
.class_init = virtio_ccw_scsi_class_init,
};
-#ifdef CONFIG_VHOST_SCSI
-
-static void vhost_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp)
-{
- VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev);
- DeviceState *vdev = DEVICE(&dev->vdev);
-
- qdev_realize(vdev, BUS(&ccw_dev->bus), errp);
-}
-
-static void vhost_ccw_scsi_instance_init(Object *obj)
-{
- VHostSCSICcw *dev = VHOST_SCSI_CCW(obj);
-
- virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
- TYPE_VHOST_SCSI);
-}
-
-static Property vhost_ccw_scsi_properties[] = {
- DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
- VIRTIO_CCW_MAX_REV),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
-
- k->realize = vhost_ccw_scsi_realize;
- device_class_set_props(dc, vhost_ccw_scsi_properties);
- set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
-}
-
-static const TypeInfo vhost_ccw_scsi = {
- .name = TYPE_VHOST_SCSI_CCW,
- .parent = TYPE_VIRTIO_CCW_DEVICE,
- .instance_size = sizeof(VHostSCSICcw),
- .instance_init = vhost_ccw_scsi_instance_init,
- .class_init = vhost_ccw_scsi_class_init,
-};
-
-#endif
-
static void virtio_ccw_scsi_register(void)
{
type_register_static(&virtio_ccw_scsi);
-#ifdef CONFIG_VHOST_SCSI
- type_register_static(&vhost_ccw_scsi);
-#endif
}
type_init(virtio_ccw_scsi_register)
diff --git a/hw/s390x/virtio-ccw-serial.c b/hw/s390x/virtio-ccw-serial.c
index 61958228d1..8f8d2302f8 100644
--- a/hw/s390x/virtio-ccw-serial.c
+++ b/hw/s390x/virtio-ccw-serial.c
@@ -16,6 +16,14 @@
#include "hw/virtio/virtio-serial.h"
#include "virtio-ccw.h"
+#define TYPE_VIRTIO_SERIAL_CCW "virtio-serial-ccw"
+OBJECT_DECLARE_SIMPLE_TYPE(VirtioSerialCcw, VIRTIO_SERIAL_CCW)
+
+struct VirtioSerialCcw {
+ VirtioCcwDevice parent_obj;
+ VirtIOSerial vdev;
+};
+
static void virtio_ccw_serial_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(ccw_dev);
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 6a2df1c1e9..b4676909dd 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -12,6 +12,7 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
+#include "exec/address-spaces.h"
#include "sysemu/kvm.h"
#include "net/net.h"
#include "hw/virtio/virtio.h"
@@ -19,8 +20,8 @@
#include "hw/virtio/virtio-net.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
+#include "qemu/log.h"
#include "qemu/module.h"
-#include "hw/virtio/virtio-access.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/s390x/adapter.h"
#include "hw/s390x/s390_flic.h"
@@ -86,7 +87,7 @@ const VMStateDescription vmstate_virtio_ccw_dev_tmp = {
.name = "s390_virtio_ccw_dev_tmp",
.pre_save = virtio_ccw_dev_tmp_pre_save,
.post_load = virtio_ccw_dev_tmp_post_load,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_UINT16(config_vector, VirtioCcwDeviceTmp),
VMSTATE_END_OF_LIST()
}
@@ -97,7 +98,7 @@ const VMStateDescription vmstate_virtio_ccw_dev = {
.version_id = 1,
.minimum_version_id = 1,
.post_load = virtio_ccw_dev_post_load,
- .fields = (VMStateField[]) {
+ .fields = (const VMStateField[]) {
VMSTATE_CCW_DEVICE(parent_obj, VirtioCcwDevice),
VMSTATE_PTR_TO_IND_ADDR(indicators, VirtioCcwDevice),
VMSTATE_PTR_TO_IND_ADDR(indicators2, VirtioCcwDevice),
@@ -235,6 +236,7 @@ static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info,
return -EINVAL;
}
virtio_queue_set_num(vdev, index, num);
+ virtio_init_region_cache(vdev, index);
} else if (virtio_queue_get_num(vdev, index) > num) {
/* Fail if we don't have a big enough queue. */
return -EINVAL;
@@ -247,12 +249,11 @@ static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info,
return 0;
}
-static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev)
+static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev)
{
CcwDevice *ccw_dev = CCW_DEVICE(dev);
- virtio_ccw_stop_ioeventfd(dev);
- virtio_reset(vdev);
+ virtio_bus_reset(&dev->bus);
if (dev->indicators) {
release_indicator(&dev->routes.adapter, dev->indicators);
dev->indicators = NULL;
@@ -357,7 +358,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
ret = virtio_ccw_handle_set_vq(sch, ccw, check_len, dev->revision < 1);
break;
case CCW_CMD_VDEV_RESET:
- virtio_ccw_reset_virtio(dev, vdev);
+ virtio_ccw_reset_virtio(dev);
ret = 0;
break;
case CCW_CMD_READ_FEAT:
@@ -534,7 +535,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
}
if (virtio_set_status(vdev, status) == 0) {
if (vdev->status == 0) {
- virtio_ccw_reset_virtio(dev, vdev);
+ virtio_ccw_reset_virtio(dev);
}
if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
virtio_ccw_start_ioeventfd(dev);
@@ -767,10 +768,6 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
sch->cssid, sch->ssid, sch->schid, sch->devno,
ccw_dev->devno.valid ? "user-configured" : "auto-configured");
- if (kvm_enabled() && !kvm_eventfds_enabled()) {
- dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD;
- }
-
/* fd-based ioevents can't be synchronized in record/replay */
if (replay_mode != REPLAY_MODE_NONE) {
dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD;
@@ -919,10 +916,9 @@ static void virtio_ccw_notify(DeviceState *d, uint16_t vector)
static void virtio_ccw_reset(DeviceState *d)
{
VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
- VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);
VirtIOCCWDeviceClass *vdc = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
- virtio_ccw_reset_virtio(dev, vdev);
+ virtio_ccw_reset_virtio(dev);
if (vdc->parent_reset) {
vdc->parent_reset(d);
}
@@ -1261,8 +1257,7 @@ static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size,
DeviceState *qdev = DEVICE(dev);
char virtio_bus_name[] = "virtio-bus";
- qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_CCW_BUS,
- qdev, virtio_bus_name);
+ qbus_init(bus, bus_size, TYPE_VIRTIO_CCW_BUS, qdev, virtio_bus_name);
}
static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data)
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 0168232e3b..fac186c8f6 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -13,24 +13,8 @@
#ifndef HW_S390X_VIRTIO_CCW_H
#define HW_S390X_VIRTIO_CCW_H
-#include "hw/virtio/virtio-blk.h"
-#include "hw/virtio/virtio-net.h"
-#include "hw/virtio/virtio-serial.h"
-#include "hw/virtio/virtio-scsi.h"
#include "qom/object.h"
-#ifdef CONFIG_VHOST_SCSI
-#include "hw/virtio/vhost-scsi.h"
-#endif
-#include "hw/virtio/virtio-balloon.h"
-#include "hw/virtio/virtio-rng.h"
-#include "hw/virtio/virtio-crypto.h"
#include "hw/virtio/virtio-bus.h"
-#ifdef CONFIG_VHOST_VSOCK
-#include "hw/virtio/vhost-vsock.h"
-#endif /* CONFIG_VHOST_VSOCK */
-#include "hw/virtio/virtio-gpu.h"
-#include "hw/virtio/virtio-input.h"
-
#include "hw/s390x/s390_flic.h"
#include "hw/s390x/css.h"
#include "ccw-device.h"
@@ -104,139 +88,6 @@ static inline int virtio_ccw_rev_max(VirtioCcwDevice *dev)
return dev->max_rev;
}
-/* virtio-scsi-ccw */
-
-#define TYPE_VIRTIO_SCSI_CCW "virtio-scsi-ccw"
-OBJECT_DECLARE_SIMPLE_TYPE(VirtIOSCSICcw, VIRTIO_SCSI_CCW)
-
-struct VirtIOSCSICcw {
- VirtioCcwDevice parent_obj;
- VirtIOSCSI vdev;
-};
-
-#ifdef CONFIG_VHOST_SCSI
-/* vhost-scsi-ccw */
-
-#define TYPE_VHOST_SCSI_CCW "vhost-scsi-ccw"
-OBJECT_DECLARE_SIMPLE_TYPE(VHostSCSICcw, VHOST_SCSI_CCW)
-
-struct VHostSCSICcw {
- VirtioCcwDevice parent_obj;
- VHostSCSI vdev;
-};
-#endif
-
-/* virtio-blk-ccw */
-
-#define TYPE_VIRTIO_BLK_CCW "virtio-blk-ccw"
-OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBlkCcw, VIRTIO_BLK_CCW)
-
-struct VirtIOBlkCcw {
- VirtioCcwDevice parent_obj;
- VirtIOBlock vdev;
-};
-
-/* virtio-balloon-ccw */
-
-#define TYPE_VIRTIO_BALLOON_CCW "virtio-balloon-ccw"
-OBJECT_DECLARE_SIMPLE_TYPE(VirtIOBalloonCcw, VIRTIO_BALLOON_CCW)
-
-struct VirtIOBalloonCcw {
- VirtioCcwDevice parent_obj;
- VirtIOBalloon vdev;
-};
-
-/* virtio-serial-ccw */
-
-#define TYPE_VIRTIO_SERIAL_CCW "virtio-serial-ccw"
-OBJECT_DECLARE_SIMPLE_TYPE(VirtioSerialCcw, VIRTIO_SERIAL_CCW)
-
-struct VirtioSerialCcw {
- VirtioCcwDevice parent_obj;
- VirtIOSerial vdev;
-};
-
-/* virtio-net-ccw */
-
-#define TYPE_VIRTIO_NET_CCW "virtio-net-ccw"
-OBJECT_DECLARE_SIMPLE_TYPE(VirtIONetCcw, VIRTIO_NET_CCW)
-
-struct VirtIONetCcw {
- VirtioCcwDevice parent_obj;
- VirtIONet vdev;
-};
-
-/* virtio-rng-ccw */
-
-#define TYPE_VIRTIO_RNG_CCW "virtio-rng-ccw"
-OBJECT_DECLARE_SIMPLE_TYPE(VirtIORNGCcw, VIRTIO_RNG_CCW)
-
-struct VirtIORNGCcw {
- VirtioCcwDevice parent_obj;
- VirtIORNG vdev;
-};
-
-/* virtio-crypto-ccw */
-
-#define TYPE_VIRTIO_CRYPTO_CCW "virtio-crypto-ccw"
-OBJECT_DECLARE_SIMPLE_TYPE(VirtIOCryptoCcw, VIRTIO_CRYPTO_CCW)
-
-struct VirtIOCryptoCcw {
- VirtioCcwDevice parent_obj;
- VirtIOCrypto vdev;
-};
-
VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch);
-#ifdef CONFIG_VIRTFS
-#include "hw/9pfs/virtio-9p.h"
-
-#define TYPE_VIRTIO_9P_CCW "virtio-9p-ccw"
-OBJECT_DECLARE_SIMPLE_TYPE(V9fsCCWState, VIRTIO_9P_CCW)
-
-struct V9fsCCWState {
- VirtioCcwDevice parent_obj;
- V9fsVirtioState vdev;
-};
-
-#endif /* CONFIG_VIRTFS */
-
-#ifdef CONFIG_VHOST_VSOCK
-#define TYPE_VHOST_VSOCK_CCW "vhost-vsock-ccw"
-OBJECT_DECLARE_SIMPLE_TYPE(VHostVSockCCWState, VHOST_VSOCK_CCW)
-
-struct VHostVSockCCWState {
- VirtioCcwDevice parent_obj;
- VHostVSock vdev;
-};
-
-#endif /* CONFIG_VHOST_VSOCK */
-
-#define TYPE_VIRTIO_GPU_CCW "virtio-gpu-ccw"
-OBJECT_DECLARE_SIMPLE_TYPE(VirtIOGPUCcw, VIRTIO_GPU_CCW)
-
-struct VirtIOGPUCcw {
- VirtioCcwDevice parent_obj;
- VirtIOGPU vdev;
-};
-
-#define TYPE_VIRTIO_INPUT_CCW "virtio-input-ccw"
-OBJECT_DECLARE_SIMPLE_TYPE(VirtIOInputCcw, VIRTIO_INPUT_CCW)
-
-struct VirtIOInputCcw {
- VirtioCcwDevice parent_obj;
- VirtIOInput vdev;
-};
-
-#define TYPE_VIRTIO_INPUT_HID_CCW "virtio-input-hid-ccw"
-#define TYPE_VIRTIO_KEYBOARD_CCW "virtio-keyboard-ccw"
-#define TYPE_VIRTIO_MOUSE_CCW "virtio-mouse-ccw"
-#define TYPE_VIRTIO_TABLET_CCW "virtio-tablet-ccw"
-OBJECT_DECLARE_SIMPLE_TYPE(VirtIOInputHIDCcw, VIRTIO_INPUT_HID_CCW)
-
-struct VirtIOInputHIDCcw {
- VirtioCcwDevice parent_obj;
- VirtIOInputHID vdev;
-};
-
#endif