Merge tag 'pull-request-2023-10-20' of https://gitlab.com/thuth/qemu into staging

* s390x CPU topology support
* Simplify the KVM register synchronization code
* Disable the analyze-migration.py test on s390x

# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmUyDYMRHHRodXRoQHJl
# ZGhhdC5jb20ACgkQLtnXdP5wLbUlgBAAkF3dvW0vMcb653sCI5vt2GHIvQQtc2Rw
# ghRRcTBZ7wyVxKHtqohCh7/byzDW5YEuCWUyLsc2oIz/84pc00VR/5Ng1EAxLAfe
# mvzzjr4jX96SmoO0DbJpqJQXaUPNYdmoshbRL0I3wkIfGtkvGRM8zHZuYINOg0hw
# bH6gWZ2QL/NFjXh0uAOaJB1+hRtPWvHD2rnVt0g9U9W5QhRxGJqti5YEaLBH7hh5
# RydsquRZ/E6uFw4pMjjvCxDaswPwejddrP2YeR5Fd5Zo+Kzp53r9Hf/eJwlZ8yFL
# 5f1dRb19NZYpW1hZuJVOP8tkPydYxAM85vkUunI7Qg4gez5KI0Nz6hQozw6ufMlQ
# r8L17fwQMsCrwcRypImYNXyyrtHlNH5Y8FjqTct8aK64Bw3e7Qqi7d3ybFAuYZ+D
# k2EJ8Rlwhbg69h+Q+ucHx4NkYu9+2MFS6G7w5EcM6xl3WHSwUxh9orlEMsIkyHS3
# OMFMTr1jjfFdEN6EafhPwFE/xKglFF2Fe3u6NoR+5pkv3UA5Z87giitxoekYecpH
# J96P3anORpWW75qvOF+nccqrd7OrUL1/yYdOyJh5Tkm0oCIeQ9E5extVf3Gne3E/
# yWzr00GJRiHFO2qbGStgKHTQLItgQpccwNpSzEdgHCqwLbXl6e3Hoq42VIFOlbN/
# ZtgpyUkuYyQ=
# =xDb+
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 19 Oct 2023 22:17:55 PDT
# gpg:                using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5
# gpg:                issuer "thuth@redhat.com"
# gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full]
# gpg:                 aka "Thomas Huth <thuth@redhat.com>" [full]
# gpg:                 aka "Thomas Huth <huth@tuxfamily.org>" [full]
# gpg:                 aka "Thomas Huth <th.huth@posteo.de>" [unknown]
# Primary key fingerprint: 27B8 8847 EEE0 2501 18F3  EAB9 2ED9 D774 FE70 2DB5

* tag 'pull-request-2023-10-20' of https://gitlab.com/thuth/qemu: (24 commits)
  tests/qtest/migration-test: Disable the analyze-migration.py test on s390x
  target/s390x/kvm: Simplify the GPRs, ACRs, CRs and prefix synchronization code
  target/s390x/kvm: Turn KVM_CAP_SYNC_REGS into a hard requirement
  tests/avocado: s390x cpu topology bad move
  tests/avocado: s390x cpu topology dedicated errors
  tests/avocado: s390x cpu topology test socket full
  tests/avocado: s390x cpu topology test dedicated CPU
  tests/avocado: s390x cpu topology entitlement tests
  tests/avocado: s390x cpu topology polarization
  tests/avocado: s390x cpu topology core
  docs/s390x/cpu topology: document s390x cpu topology
  qapi/s390x/cpu topology: add query-s390x-cpu-polarization command
  qapi/s390x/cpu topology: CPU_POLARIZATION_CHANGE QAPI event
  machine: adding s390 topology to info hotpluggable-cpus
  machine: adding s390 topology to query-cpu-fast
  qapi/s390x/cpu topology: set-cpu-topology qmp command
  target/s390x/cpu topology: activate CPU topology
  s390x/cpu topology: interception of PTF instruction
  s390x/cpu topology: resetting the Topology-Change-Report
  s390x/sclp: reporting the maximum nested topology entries
  ...

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi
2023-10-20 06:46:41 -07:00
35 changed files with 2288 additions and 128 deletions
+11
View File
@@ -1714,6 +1714,16 @@ F: hw/s390x/event-facility.c
F: hw/s390x/sclp*.c
L: qemu-s390x@nongnu.org
S390 CPU topology
M: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
S: Supported
F: include/hw/s390x/cpu-topology.h
F: hw/s390x/cpu-topology.c
F: target/s390x/kvm/stsi-topology.c
F: docs/devel/s390-cpu-topology.rst
F: docs/system/s390x/cpu-topology.rst
F: tests/avocado/s390_topology.py
X86 Machines
------------
PC
@@ -1797,6 +1807,7 @@ F: hw/core/null-machine.c
F: hw/core/numa.c
F: hw/cpu/cluster.c
F: qapi/machine.json
F: qapi/machine-common.json
F: qapi/machine-target.json
F: include/hw/boards.h
F: include/hw/core/cpu.h
+1
View File
@@ -14,6 +14,7 @@ Details about QEMU's various subsystems including how to add features to them.
migration
multi-process
reset
s390-cpu-topology
s390-dasd-ipl
tracing
vfio-migration
+170
View File
@@ -0,0 +1,170 @@
QAPI interface for S390 CPU topology
====================================
The following sections will explain the QAPI interface for S390 CPU topology
with the help of exemplary output.
For this, let's assume that QEMU has been started with the following
command, defining 4 CPUs, where CPU[0] is defined by the -smp argument and will
have default values:
.. code-block:: bash
qemu-system-s390x \
-enable-kvm \
-cpu z14,ctop=on \
-smp 1,drawers=3,books=3,sockets=2,cores=2,maxcpus=36 \
-device z14-s390x-cpu,core-id=19,entitlement=high \
-device z14-s390x-cpu,core-id=11,entitlement=low \
-device z14-s390x-cpu,core-id=112,entitlement=high \
...
Additions to query-cpus-fast
----------------------------
The command query-cpus-fast allows querying the topology tree and
modifiers for all configured vCPUs.
.. code-block:: QMP
{ "execute": "query-cpus-fast" }
{
"return": [
{
"dedicated": false,
"thread-id": 536993,
"props": {
"core-id": 0,
"socket-id": 0,
"drawer-id": 0,
"book-id": 0
},
"cpu-state": "operating",
"entitlement": "medium",
"qom-path": "/machine/unattached/device[0]",
"cpu-index": 0,
"target": "s390x"
},
{
"dedicated": false,
"thread-id": 537003,
"props": {
"core-id": 19,
"socket-id": 1,
"drawer-id": 0,
"book-id": 2
},
"cpu-state": "operating",
"entitlement": "high",
"qom-path": "/machine/peripheral-anon/device[0]",
"cpu-index": 19,
"target": "s390x"
},
{
"dedicated": false,
"thread-id": 537004,
"props": {
"core-id": 11,
"socket-id": 1,
"drawer-id": 0,
"book-id": 1
},
"cpu-state": "operating",
"entitlement": "low",
"qom-path": "/machine/peripheral-anon/device[1]",
"cpu-index": 11,
"target": "s390x"
},
{
"dedicated": true,
"thread-id": 537005,
"props": {
"core-id": 112,
"socket-id": 0,
"drawer-id": 3,
"book-id": 2
},
"cpu-state": "operating",
"entitlement": "high",
"qom-path": "/machine/peripheral-anon/device[2]",
"cpu-index": 112,
"target": "s390x"
}
]
}
QAPI command: set-cpu-topology
------------------------------
The command set-cpu-topology allows modifying the topology tree
or the topology modifiers of a vCPU in the configuration.
.. code-block:: QMP
{ "execute": "set-cpu-topology",
"arguments": {
"core-id": 11,
"socket-id": 0,
"book-id": 0,
"drawer-id": 0,
"entitlement": "low",
"dedicated": false
}
}
{"return": {}}
The core-id parameter is the only mandatory parameter and every
unspecified parameter keeps its previous value.
QAPI event CPU_POLARIZATION_CHANGE
----------------------------------
When a guest requests a modification of the polarization,
QEMU sends a CPU_POLARIZATION_CHANGE event.
When requesting the change, the guest only specifies horizontal or
vertical polarization.
It is the job of the entity administrating QEMU to set the dedication and fine
grained vertical entitlement in response to this event.
Note that a vertical polarized dedicated vCPU can only have a high
entitlement, giving 6 possibilities for vCPU polarization:
- Horizontal
- Horizontal dedicated
- Vertical low
- Vertical medium
- Vertical high
- Vertical high dedicated
Example of the event received when the guest issues the CPU instruction
Perform Topology Function PTF(0) to request an horizontal polarization:
.. code-block:: QMP
{
"timestamp": {
"seconds": 1687870305,
"microseconds": 566299
},
"event": "CPU_POLARIZATION_CHANGE",
"data": {
"polarization": "horizontal"
}
}
QAPI query command: query-s390x-cpu-polarization
------------------------------------------------
The query command query-s390x-cpu-polarization returns the current
CPU polarization of the machine.
In this case the guest previously issued a PTF(1) to request vertical polarization:
.. code-block:: QMP
{ "execute": "query-s390x-cpu-polarization" }
{
"return": {
"polarization": "vertical"
}
}
+244
View File
@@ -0,0 +1,244 @@
.. _cpu-topology-s390x:
CPU topology on s390x
=====================
Since QEMU 8.2, CPU topology on s390x provides up to 3 levels of
topology containers: drawers, books and sockets. They define a
tree-shaped hierarchy.
The socket container has one or more CPU entries.
Each of these CPU entries consists of a bitmap and three CPU attributes:
- CPU type
- entitlement
- dedication
Each bit set in the bitmap correspond to a core-id of a vCPU with matching
attributes.
This documentation provides general information on S390 CPU topology,
how to enable it and explains the new CPU attributes.
For information on how to modify the S390 CPU topology and how to
monitor polarization changes, see ``docs/devel/s390-cpu-topology.rst``.
Prerequisites
-------------
To use the CPU topology, you need to run with KVM on a s390x host that
uses the Linux kernel v6.0 or newer (which provide the so-called
``KVM_CAP_S390_CPU_TOPOLOGY`` capability that allows QEMU to signal the
CPU topology facility via the so-called STFLE bit 11 to the VM).
Enabling CPU topology
---------------------
Currently, CPU topology is only enabled in the host model by default.
Enabling CPU topology in a CPU model is done by setting the CPU flag
``ctop`` to ``on`` as in:
.. code-block:: bash
-cpu gen16b,ctop=on
Having the topology disabled by default allows migration between
old and new QEMU without adding new flags.
Default topology usage
----------------------
The CPU topology can be specified on the QEMU command line
with the ``-smp`` or the ``-device`` QEMU command arguments.
Note also that since 7.2 threads are no longer supported in the topology
and the ``-smp`` command line argument accepts only ``threads=1``.
If none of the containers attributes (drawers, books, sockets) are
specified for the ``-smp`` flag, the number of these containers
is 1.
Thus the following two options will result in the same topology:
.. code-block:: bash
-smp cpus=5,drawer=1,books=1,sockets=8,cores=4,maxcpus=32
and
.. code-block:: bash
-smp cpus=5,sockets=8,cores=4,maxcpus=32
When a CPU is defined by the ``-smp`` command argument, its position
inside the topology is calculated by adding the CPUs to the topology
based on the core-id starting with core-0 at position 0 of socket-0,
book-0, drawer-0 and filling all CPUs of socket-0 before filling socket-1
of book-0 and so on up to the last socket of the last book of the last
drawer.
When a CPU is defined by the ``-device`` command argument, the
tree topology attributes must all be defined or all not defined.
.. code-block:: bash
-device gen16b-s390x-cpu,drawer-id=1,book-id=1,socket-id=2,core-id=1
or
.. code-block:: bash
-device gen16b-s390x-cpu,core-id=1,dedicated=true
If none of the tree attributes (drawer, book, sockets), are specified
for the ``-device`` argument, like for all CPUs defined with the ``-smp``
command argument the topology tree attributes will be set by simply
adding the CPUs to the topology based on the core-id.
QEMU will not try to resolve collisions and will report an error if the
CPU topology defined explicitly or implicitly on a ``-device``
argument collides with the definition of a CPU implicitly defined
on the ``-smp`` argument.
When the topology modifier attributes are not defined for the
``-device`` command argument they takes following default values:
- dedicated: ``false``
- entitlement: ``medium``
Hot plug
++++++++
New CPUs can be plugged using the device_add hmp command as in:
.. code-block:: bash
(qemu) device_add gen16b-s390x-cpu,core-id=9
The placement of the CPU is derived from the core-id as described above.
The topology can of course also be fully defined:
.. code-block:: bash
(qemu) device_add gen16b-s390x-cpu,drawer-id=1,book-id=1,socket-id=2,core-id=1
Examples
++++++++
In the following machine we define 8 sockets with 4 cores each.
.. code-block:: bash
$ qemu-system-s390x -m 2G \
-cpu gen16b,ctop=on \
-smp cpus=5,sockets=8,cores=4,maxcpus=32 \
-device host-s390x-cpu,core-id=14 \
A new CPUs can be plugged using the device_add hmp command as before:
.. code-block:: bash
(qemu) device_add gen16b-s390x-cpu,core-id=9
The core-id defines the placement of the core in the topology by
starting with core 0 in socket 0 up to maxcpus.
In the example above:
* There are 5 CPUs provided to the guest with the ``-smp`` command line
They will take the core-ids 0,1,2,3,4
As we have 4 cores in a socket, we have 4 CPUs provided
to the guest in socket 0, with core-ids 0,1,2,3.
The last CPU, with core-id 4, will be on socket 1.
* the core with ID 14 provided by the ``-device`` command line will
be placed in socket 3, with core-id 14
* the core with ID 9 provided by the ``device_add`` qmp command will
be placed in socket 2, with core-id 9
Polarization, entitlement and dedication
----------------------------------------
Polarization
++++++++++++
The polarization affects how the CPUs of a shared host are utilized/distributed
among guests.
The guest determines the polarization by using the PTF instruction.
Polarization defines two models of CPU provisioning: horizontal
and vertical.
The horizontal polarization is the default model on boot and after
subsystem reset. When horizontal polarization is in effect all vCPUs should
have about equal resource provisioning.
In the vertical polarization model vCPUs are unequal, but overall more resources
might be available.
The guest can make use of the vCPU entitlement information provided by the host
to optimize kernel thread scheduling.
A subsystem reset puts all vCPU of the configuration into the
horizontal polarization.
Entitlement
+++++++++++
The vertical polarization specifies that the guest's vCPU can get
different real CPU provisioning:
- a vCPU with vertical high entitlement specifies that this
vCPU gets 100% of the real CPU provisioning.
- a vCPU with vertical medium entitlement specifies that this
vCPU shares the real CPU with other vCPUs.
- a vCPU with vertical low entitlement specifies that this
vCPU only gets real CPU provisioning when no other vCPUs needs it.
In the case a vCPU with vertical high entitlement does not use
the real CPU, the unused "slack" can be dispatched to other vCPU
with medium or low entitlement.
A vCPU can be "dedicated" in which case the vCPU is fully dedicated to a single
real CPU.
The dedicated bit is an indication of affinity of a vCPU for a real CPU
while the entitlement indicates the sharing or exclusivity of use.
Defining the topology on the command line
-----------------------------------------
The topology can entirely be defined using -device cpu statements,
with the exception of CPU 0 which must be defined with the -smp
argument.
For example, here we set the position of the cores 1,2,3 to
drawer 1, book 1, socket 2 and cores 0,9 and 14 to drawer 0,
book 0, socket 0 without defining entitlement or dedication.
Core 4 will be set on its default position on socket 1
(since we have 4 core per socket) and we define it as dedicated and
with vertical high entitlement.
.. code-block:: bash
$ qemu-system-s390x -m 2G \
-cpu gen16b,ctop=on \
-smp cpus=1,sockets=8,cores=4,maxcpus=32 \
\
-device gen16b-s390x-cpu,drawer-id=1,book-id=1,socket-id=2,core-id=1 \
-device gen16b-s390x-cpu,drawer-id=1,book-id=1,socket-id=2,core-id=2 \
-device gen16b-s390x-cpu,drawer-id=1,book-id=1,socket-id=2,core-id=3 \
\
-device gen16b-s390x-cpu,drawer-id=0,book-id=0,socket-id=0,core-id=9 \
-device gen16b-s390x-cpu,drawer-id=0,book-id=0,socket-id=0,core-id=14 \
\
-device gen16b-s390x-cpu,core-id=4,dedicated=on,entitlement=high
The entitlement defined for the CPU 4 will only be used after the guest
successfully enables vertical polarization by using the PTF instruction.
+1
View File
@@ -34,3 +34,4 @@ Architectural features
.. toctree::
s390x/bootdevices
s390x/protvirt
s390x/cpu-topology
+6
View File
@@ -71,6 +71,12 @@ void hmp_hotpluggable_cpus(Monitor *mon, const QDict *qdict)
if (c->has_node_id) {
monitor_printf(mon, " node-id: \"%" PRIu64 "\"\n", c->node_id);
}
if (c->has_drawer_id) {
monitor_printf(mon, " drawer-id: \"%" PRIu64 "\"\n", c->drawer_id);
}
if (c->has_book_id) {
monitor_printf(mon, " book-id: \"%" PRIu64 "\"\n", c->book_id);
}
if (c->has_socket_id) {
monitor_printf(mon, " socket-id: \"%" PRIu64 "\"\n", c->socket_id);
}
+41 -7
View File
@@ -33,6 +33,14 @@ static char *cpu_hierarchy_to_string(MachineState *ms)
MachineClass *mc = MACHINE_GET_CLASS(ms);
GString *s = g_string_new(NULL);
if (mc->smp_props.drawers_supported) {
g_string_append_printf(s, "drawers (%u) * ", ms->smp.drawers);
}
if (mc->smp_props.books_supported) {
g_string_append_printf(s, "books (%u) * ", ms->smp.books);
}
g_string_append_printf(s, "sockets (%u)", ms->smp.sockets);
if (mc->smp_props.dies_supported) {
@@ -75,6 +83,8 @@ void machine_parse_smp_config(MachineState *ms,
{
MachineClass *mc = MACHINE_GET_CLASS(ms);
unsigned cpus = config->has_cpus ? config->cpus : 0;
unsigned drawers = config->has_drawers ? config->drawers : 0;
unsigned books = config->has_books ? config->books : 0;
unsigned sockets = config->has_sockets ? config->sockets : 0;
unsigned dies = config->has_dies ? config->dies : 0;
unsigned clusters = config->has_clusters ? config->clusters : 0;
@@ -87,6 +97,8 @@ void machine_parse_smp_config(MachineState *ms,
* explicit configuration like "cpus=0" is not allowed.
*/
if ((config->has_cpus && config->cpus == 0) ||
(config->has_drawers && config->drawers == 0) ||
(config->has_books && config->books == 0) ||
(config->has_sockets && config->sockets == 0) ||
(config->has_dies && config->dies == 0) ||
(config->has_clusters && config->clusters == 0) ||
@@ -113,6 +125,19 @@ void machine_parse_smp_config(MachineState *ms,
dies = dies > 0 ? dies : 1;
clusters = clusters > 0 ? clusters : 1;
if (!mc->smp_props.books_supported && books > 1) {
error_setg(errp, "books not supported by this machine's CPU topology");
return;
}
books = books > 0 ? books : 1;
if (!mc->smp_props.drawers_supported && drawers > 1) {
error_setg(errp,
"drawers not supported by this machine's CPU topology");
return;
}
drawers = drawers > 0 ? drawers : 1;
/* compute missing values based on the provided ones */
if (cpus == 0 && maxcpus == 0) {
sockets = sockets > 0 ? sockets : 1;
@@ -126,33 +151,41 @@ void machine_parse_smp_config(MachineState *ms,
if (sockets == 0) {
cores = cores > 0 ? cores : 1;
threads = threads > 0 ? threads : 1;
sockets = maxcpus / (dies * clusters * cores * threads);
sockets = maxcpus /
(drawers * books * dies * clusters * cores * threads);
} else if (cores == 0) {
threads = threads > 0 ? threads : 1;
cores = maxcpus / (sockets * dies * clusters * threads);
cores = maxcpus /
(drawers * books * sockets * dies * clusters * threads);
}
} else {
/* prefer cores over sockets since 6.2 */
if (cores == 0) {
sockets = sockets > 0 ? sockets : 1;
threads = threads > 0 ? threads : 1;
cores = maxcpus / (sockets * dies * clusters * threads);
cores = maxcpus /
(drawers * books * sockets * dies * clusters * threads);
} else if (sockets == 0) {
threads = threads > 0 ? threads : 1;
sockets = maxcpus / (dies * clusters * cores * threads);
sockets = maxcpus /
(drawers * books * dies * clusters * cores * threads);
}
}
/* try to calculate omitted threads at last */
if (threads == 0) {
threads = maxcpus / (sockets * dies * clusters * cores);
threads = maxcpus /
(drawers * books * sockets * dies * clusters * cores);
}
}
maxcpus = maxcpus > 0 ? maxcpus : sockets * dies * clusters * cores * threads;
maxcpus = maxcpus > 0 ? maxcpus : drawers * books * sockets * dies *
clusters * cores * threads;
cpus = cpus > 0 ? cpus : maxcpus;
ms->smp.cpus = cpus;
ms->smp.drawers = drawers;
ms->smp.books = books;
ms->smp.sockets = sockets;
ms->smp.dies = dies;
ms->smp.clusters = clusters;
@@ -163,7 +196,8 @@ void machine_parse_smp_config(MachineState *ms,
mc->smp_props.has_clusters = config->has_clusters;
/* sanity-check of the computed topology */
if (sockets * dies * clusters * cores * threads != maxcpus) {
if (drawers * books * sockets * dies * clusters * cores * threads !=
maxcpus) {
g_autofree char *topo_msg = cpu_hierarchy_to_string(ms);
error_setg(errp, "Invalid CPU topology: "
"product of the hierarchy must match maxcpus: "
+4
View File
@@ -863,6 +863,8 @@ static void machine_get_smp(Object *obj, Visitor *v, const char *name,
MachineState *ms = MACHINE(obj);
SMPConfiguration *config = &(SMPConfiguration){
.has_cpus = true, .cpus = ms->smp.cpus,
.has_drawers = true, .drawers = ms->smp.drawers,
.has_books = true, .books = ms->smp.books,
.has_sockets = true, .sockets = ms->smp.sockets,
.has_dies = true, .dies = ms->smp.dies,
.has_clusters = true, .clusters = ms->smp.clusters,
@@ -1137,6 +1139,8 @@ static void machine_initfn(Object *obj)
/* default to mc->default_cpus */
ms->smp.cpus = mc->default_cpus;
ms->smp.max_cpus = mc->default_cpus;
ms->smp.drawers = 1;
ms->smp.books = 1;
ms->smp.sockets = 1;
ms->smp.dies = 1;
ms->smp.clusters = 1;
+13
View File
@@ -1139,3 +1139,16 @@ const PropertyInfo qdev_prop_uuid = {
.set = set_uuid,
.set_default_value = set_default_uuid_auto,
};
/* --- s390 cpu entitlement policy --- */
QEMU_BUILD_BUG_ON(sizeof(CpuS390Entitlement) != sizeof(int));
const PropertyInfo qdev_prop_cpus390entitlement = {
.name = "CpuS390Entitlement",
.description = "low/medium (default)/high",
.enum_table = &CpuS390Entitlement_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
};
+469
View File
@@ -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;
}
+1
View File
@@ -23,6 +23,7 @@ s390x_ss.add(when: 'CONFIG_KVM', if_true: files(
's390-skeys-kvm.c',
's390-stattrib-kvm.c',
's390-pci-kvm.c',
'cpu-topology.c',
))
s390x_ss.add(when: 'CONFIG_TCG', if_true: files(
'tod-tcg.c',
+27 -2
View File
@@ -45,6 +45,7 @@
#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;
@@ -123,6 +124,9 @@ static void subsystem_reset(void)
device_cold_reset(dev);
}
}
if (s390_has_topology()) {
s390_topology_reset();
}
}
static int virtio_ccw_hcall_notify(const uint64_t *args)
@@ -309,10 +313,18 @@ static void s390_cpu_plug(HotplugHandler *hotplug_dev,
{
MachineState *ms = MACHINE(hotplug_dev);
S390CPU *cpu = S390_CPU(dev);
ERRP_GUARD();
g_assert(!ms->possible_cpus->cpus[cpu->env.core_id].cpu);
ms->possible_cpus->cpus[cpu->env.core_id].cpu = OBJECT(dev);
if (s390_has_topology()) {
s390_topology_setup_cpu(ms, cpu, errp);
if (*errp) {
return;
}
}
if (dev->hotplugged) {
raise_irq_cpu_hotplug();
}
@@ -562,11 +574,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;
@@ -744,6 +765,8 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
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;
@@ -853,6 +876,8 @@ 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);
+5
View File
@@ -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);
+9 -1
View File
@@ -135,12 +135,16 @@ typedef struct {
* @clusters_supported - whether clusters are supported by the machine
* @has_clusters - whether clusters are explicitly specified in the user
* provided SMP configuration
* @books_supported - whether books are supported by the machine
* @drawers_supported - whether drawers are supported by the machine
*/
typedef struct {
bool prefer_sockets;
bool dies_supported;
bool clusters_supported;
bool has_clusters;
bool books_supported;
bool drawers_supported;
} SMPCompatProps;
/**
@@ -323,7 +327,9 @@ typedef struct DeviceMemoryState {
/**
* CpuTopology:
* @cpus: the number of present logical processors on the machine
* @sockets: the number of sockets on the machine
* @drawers: the number of drawers on the machine
* @books: the number of books in one drawer
* @sockets: the number of sockets in one book
* @dies: the number of dies in one socket
* @clusters: the number of clusters in one die
* @cores: the number of cores in one cluster
@@ -332,6 +338,8 @@ typedef struct DeviceMemoryState {
*/
typedef struct CpuTopology {
unsigned int cpus;
unsigned int drawers;
unsigned int books;
unsigned int sockets;
unsigned int dies;
unsigned int clusters;
+4
View File
@@ -22,6 +22,7 @@ extern const PropertyInfo qdev_prop_audiodev;
extern const PropertyInfo qdev_prop_off_auto_pcibar;
extern const PropertyInfo qdev_prop_pcie_link_speed;
extern const PropertyInfo qdev_prop_pcie_link_width;
extern const PropertyInfo qdev_prop_cpus390entitlement;
#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
@@ -73,5 +74,8 @@ extern const PropertyInfo qdev_prop_pcie_link_width;
#define DEFINE_PROP_UUID_NODEFAULT(_name, _state, _field) \
DEFINE_PROP(_name, _state, _field, qdev_prop_uuid, QemuUUID)
#define DEFINE_PROP_CPUS390ENTITLEMENT(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_cpus390entitlement, \
CpuS390Entitlement)
#endif
+83
View File
@@ -0,0 +1,83 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* CPU Topology
*
* Copyright IBM Corp. 2022, 2023
* Author(s): Pierre Morel <pmorel@linux.ibm.com>
*
*/
#ifndef HW_S390X_CPU_TOPOLOGY_H
#define HW_S390X_CPU_TOPOLOGY_H
#ifndef CONFIG_USER_ONLY
#include "qemu/queue.h"
#include "hw/boards.h"
#include "qapi/qapi-types-machine-target.h"
#define S390_TOPOLOGY_CPU_IFL 0x03
typedef struct S390TopologyId {
uint8_t sentinel;
uint8_t drawer;
uint8_t book;
uint8_t socket;
uint8_t type;
uint8_t vertical:1;
uint8_t entitlement:2;
uint8_t dedicated;
uint8_t origin;
} S390TopologyId;
typedef struct S390TopologyEntry {
QTAILQ_ENTRY(S390TopologyEntry) next;
S390TopologyId id;
uint64_t mask;
} S390TopologyEntry;
typedef struct S390Topology {
uint8_t *cores_per_socket;
CpuS390Polarization polarization;
} S390Topology;
typedef QTAILQ_HEAD(, S390TopologyEntry) S390TopologyList;
#ifdef CONFIG_KVM
bool s390_has_topology(void);
void s390_topology_setup_cpu(MachineState *ms, S390CPU *cpu, Error **errp);
void s390_topology_reset(void);
#else
static inline bool s390_has_topology(void)
{
return false;
}
static inline void s390_topology_setup_cpu(MachineState *ms,
S390CPU *cpu,
Error **errp) {}
static inline void s390_topology_reset(void)
{
/* Unreachable, CPU topology not implemented for TCG */
assert(false);
}
#endif
extern S390Topology s390_topology;
static inline int s390_std_socket(int n, CpuTopology *smp)
{
return (n / smp->cores) % smp->sockets;
}
static inline int s390_std_book(int n, CpuTopology *smp)
{
return (n / (smp->cores * smp->sockets)) % smp->books;
}
static inline int s390_std_drawer(int n, CpuTopology *smp)
{
return (n / (smp->cores * smp->sockets * smp->books)) % smp->drawers;
}
#endif /* CONFIG_USER_ONLY */
#endif
+6
View File
@@ -30,6 +30,12 @@ struct S390CcwMachineState {
uint8_t loadparm[8];
};
#define S390_PTF_REASON_NONE (0x00 << 8)
#define S390_PTF_REASON_DONE (0x01 << 8)
#define S390_PTF_REASON_BUSY (0x02 << 8)
#define S390_TOPO_FC_MASK 0xffUL
void s390_handle_ptf(S390CPU *cpu, uint8_t r1, uintptr_t ra);
struct S390CcwMachineClass {
/*< private >*/
MachineClass parent_class;
+3 -1
View File
@@ -112,11 +112,13 @@ typedef struct CPUEntry {
} QEMU_PACKED CPUEntry;
#define SCLP_READ_SCP_INFO_FIXED_CPU_OFFSET 128
#define SCLP_READ_SCP_INFO_MNEST 4
typedef struct ReadInfo {
SCCBHeader h;
uint16_t rnmax;
uint8_t rnsize;
uint8_t _reserved1[16 - 11]; /* 11-15 */
uint8_t _reserved1[15 - 11]; /* 11-14 */
uint8_t stsi_parm; /* 15-15 */
uint16_t entries_cpu; /* 16-17 */
uint16_t offset_cpu; /* 18-19 */
uint8_t _reserved2[24 - 20]; /* 20-23 */
+21
View File
@@ -0,0 +1,21 @@
# -*- Mode: Python -*-
# vim: filetype=python
#
# This work is licensed under the terms of the GNU GPL, version 2 or later.
# See the COPYING file in the top-level directory.
##
# = Machines S390 data types
##
##
# @CpuS390Entitlement:
#
# An enumeration of CPU entitlements that can be assumed by a virtual
# S390 CPU
#
# Since: 8.2
##
{ 'enum': 'CpuS390Entitlement',
'prefix': 'S390_CPU_ENTITLEMENT',
'data': [ 'auto', 'low', 'medium', 'high' ] }
+121
View File
@@ -4,6 +4,8 @@
# This work is licensed under the terms of the GNU GPL, version 2 or later.
# See the COPYING file in the top-level directory.
{ 'include': 'machine-common.json' }
##
# @CpuModelInfo:
#
@@ -361,3 +363,122 @@
'TARGET_MIPS',
'TARGET_LOONGARCH64',
'TARGET_RISCV' ] } }
##
# @CpuS390Polarization:
#
# An enumeration of CPU polarization that can be assumed by a virtual
# S390 CPU
#
# Since: 8.2
##
{ 'enum': 'CpuS390Polarization',
'prefix': 'S390_CPU_POLARIZATION',
'data': [ 'horizontal', 'vertical' ],
'if': 'TARGET_S390X'
}
##
# @set-cpu-topology:
#
# Modify the topology by moving the CPU inside the topology tree,
# or by changing a modifier attribute of a CPU.
# Absent values will not be modified.
#
# @core-id: the vCPU ID to be moved
#
# @socket-id: destination socket to move the vCPU to
#
# @book-id: destination book to move the vCPU to
#
# @drawer-id: destination drawer to move the vCPU to
#
# @entitlement: entitlement to set
#
# @dedicated: whether the provisioning of real to virtual CPU is dedicated
#
# Features:
#
# @unstable: This command is experimental.
#
# Returns: Nothing on success.
#
# Since: 8.2
##
{ 'command': 'set-cpu-topology',
'data': {
'core-id': 'uint16',
'*socket-id': 'uint16',
'*book-id': 'uint16',
'*drawer-id': 'uint16',
'*entitlement': 'CpuS390Entitlement',
'*dedicated': 'bool'
},
'features': [ 'unstable' ],
'if': { 'all': [ 'TARGET_S390X' , 'CONFIG_KVM' ] }
}
##
# @CPU_POLARIZATION_CHANGE:
#
# Emitted when the guest asks to change the polarization.
#
# The guest can tell the host (via the PTF instruction) whether the
# CPUs should be provisioned using horizontal or vertical polarization.
#
# On horizontal polarization the host is expected to provision all vCPUs
# equally.
#
# On vertical polarization the host can provision each vCPU differently.
# The guest will get information on the details of the provisioning
# the next time it uses the STSI(15) instruction.
#
# @polarization: polarization specified by the guest
#
# Features:
#
# @unstable: This event is experimental.
#
# Since: 8.2
#
# Example:
#
# <- { "event": "CPU_POLARIZATION_CHANGE",
# "data": { "polarization": "horizontal" },
# "timestamp": { "seconds": 1401385907, "microseconds": 422329 } }
##
{ 'event': 'CPU_POLARIZATION_CHANGE',
'data': { 'polarization': 'CpuS390Polarization' },
'features': [ 'unstable' ],
'if': { 'all': [ 'TARGET_S390X', 'CONFIG_KVM' ] }
}
##
# @CpuPolarizationInfo:
#
# The result of a CPU polarization query.
#
# @polarization: the CPU polarization
#
# Since: 8.2
##
{ 'struct': 'CpuPolarizationInfo',
'data': { 'polarization': 'CpuS390Polarization' },
'if': { 'all': [ 'TARGET_S390X', 'CONFIG_KVM' ] }
}
##
# @query-s390x-cpu-polarization:
#
# Features:
#
# @unstable: This command is experimental.
#
# Returns: the machine's CPU polarization
#
# Since: 8.2
##
{ 'command': 'query-s390x-cpu-polarization', 'returns': 'CpuPolarizationInfo',
'features': [ 'unstable' ],
'if': { 'all': [ 'TARGET_S390X', 'CONFIG_KVM' ] }
}

Some files were not shown because too many files have changed in this diff Show More