@@ -31,6 +31,10 @@ 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);
}
@@ -71,6 +75,7 @@ void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp)
{
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;
@@ -83,6 +88,7 @@ void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp)
* 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) ||
@@ -111,6 +117,13 @@ void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp)
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;
@@ -124,33 +137,34 @@ void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp)
if (sockets == 0) {
cores = cores > 0 ? cores : 1;
threads = threads > 0 ? threads : 1;
- sockets = maxcpus / (books * dies * cores * threads);
+ sockets = maxcpus / (drawers * books * dies * cores * threads);
} else if (cores == 0) {
threads = threads > 0 ? threads : 1;
- cores = maxcpus / (books * sockets * dies * threads);
+ cores = maxcpus / (drawers * books * sockets * dies * threads);
}
} else {
/* prefer cores over sockets since 6.2 */
if (cores == 0) {
sockets = sockets > 0 ? sockets : 1;
threads = threads > 0 ? threads : 1;
- cores = maxcpus / (books * sockets * dies * threads);
+ cores = maxcpus / (drawers * books * sockets * dies * threads);
} else if (sockets == 0) {
threads = threads > 0 ? threads : 1;
- sockets = maxcpus / (books * dies * cores * threads);
+ sockets = maxcpus / (drawers * books * dies * cores * threads);
}
}
/* try to calculate omitted threads at last */
if (threads == 0) {
- threads = maxcpus / (books * sockets * dies * cores);
+ threads = maxcpus / (drawers * books * sockets * dies * cores);
}
}
- maxcpus = maxcpus > 0 ? maxcpus : books * sockets * dies * cores * threads;
+ maxcpus = maxcpus > 0 ? maxcpus : drawers * books * sockets * dies * 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;
@@ -159,7 +173,7 @@ void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp)
ms->smp.max_cpus = maxcpus;
/* sanity-check of the computed topology */
- if (books * sockets * dies * cores * threads != maxcpus) {
+ if (drawers * books * sockets * dies * 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: "
@@ -740,6 +740,7 @@ 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,
@@ -931,6 +932,7 @@ 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;
@@ -667,6 +667,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
nc->nmi_monitor_handler = s390_nmi;
mc->default_ram_id = "s390.ram";
mc->smp_props.books_supported = true;
+ mc->smp_props.drawers_supported = true;
}
static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp)
@@ -129,11 +129,13 @@ typedef struct {
* @prefer_sockets - whether sockets are preferred over cores in smp parsing
* @dies_supported - whether dies are supported by the machine
* @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 books_supported;
+ bool drawers_supported;
} SMPCompatProps;
/**
@@ -298,6 +300,7 @@ typedef struct DeviceMemoryState {
/**
* CpuTopology:
* @cpus: the number of present logical processors on the machine
+ * @drawers: the number of drawers on the machine
* @books: the number of books on the machine
* @sockets: the number of sockets on the machine
* @dies: the number of dies in one socket
@@ -307,6 +310,7 @@ typedef struct DeviceMemoryState {
*/
typedef struct CpuTopology {
unsigned int cpus;
+ unsigned int drawers;
unsigned int books;
unsigned int sockets;
unsigned int dies;
@@ -866,13 +866,14 @@
# a CPU is being hotplugged.
#
# @node-id: NUMA node ID the CPU belongs to
+# @drawer-id: drawer number within node/board the CPU belongs to
# @book-id: book number within node/board the CPU belongs to
# @socket-id: socket number within node/board the CPU belongs to
# @die-id: die number within node/board the CPU belongs to (Since 4.1)
# @core-id: core number within die the CPU belongs to
# @thread-id: thread number within core the CPU belongs to
#
-# Note: currently there are 6 properties that could be present
+# Note: currently there are 7 properties that could be present
# but management should be prepared to pass through other
# properties with device_add command to allow for future
# interface extension. This also requires the filed names to be kept in
@@ -882,6 +883,7 @@
##
{ 'struct': 'CpuInstanceProperties',
'data': { '*node-id': 'int',
+ '*drawer-id': 'int',
'*book-id': 'int',
'*socket-id': 'int',
'*die-id': 'int',
@@ -1394,6 +1396,8 @@
#
# @cpus: number of virtual CPUs in the virtual machine
#
+# @drawers: number of drawers in the CPU topology
+#
# @books: number of books in the CPU topology
#
# @sockets: number of sockets in the CPU topology
@@ -1410,6 +1414,7 @@
##
{ 'struct': 'SMPConfiguration', 'data': {
'*cpus': 'int',
+ '*drawers': 'int',
'*books': 'int',
'*sockets': 'int',
'*dies': 'int',
@@ -720,6 +720,9 @@ static QemuOptsList qemu_smp_opts = {
{
.name = "cpus",
.type = QEMU_OPT_NUMBER,
+ }, {
+ .name = "drawers",
+ .type = QEMU_OPT_NUMBER,
}, {
.name = "books",
.type = QEMU_OPT_NUMBER,
S390 CPU topology may have up to 5 topology containers. The first container above the cores is level 2, the sockets, and the level 3, containing sockets are the books. We introduce here the drawers, drawers is the level containing books. Let's add drawers, level4, containers to the CPU topology. Signed-off-by: Pierre Morel <pmorel@linux.ibm.com> --- hw/core/machine-smp.c | 28 +++++++++++++++++++++------- hw/core/machine.c | 2 ++ hw/s390x/s390-virtio-ccw.c | 1 + include/hw/boards.h | 4 ++++ qapi/machine.json | 7 ++++++- softmmu/vl.c | 3 +++ 6 files changed, 37 insertions(+), 8 deletions(-)