qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v14 02/11] s390x/cpu topology: add topology entries on CPU ho


From: Thomas Huth
Subject: Re: [PATCH v14 02/11] s390x/cpu topology: add topology entries on CPU hotplug
Date: Tue, 10 Jan 2023 14:00:07 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.13.0

On 05/01/2023 15.53, Pierre Morel wrote:
The topology information are attributes of the CPU and are
specified during the CPU device creation.

On hot plug, we gather the topology information on the core,
creates a list of topology entries, each entry contains a single
core mask of each core with identical topology and finaly we
orders the list in topological order.
The topological order is, from higher to lower priority:
- physical topology
     - drawer
     - book
     - socket
     - core origin, offset in 64bit increment from core 0.
- modifier attributes
     - CPU type
     - polarization entitlement
     - dedication

The possibility to insert a CPU in a mask is dependent on the
number of cores allowed in a socket, a book or a drawer, the
checking is done during the hot plug of the CPU to have an
immediate answer.

If the complete topology is not specified, the core is added
in the physical topology based on its core ID and it gets
defaults values for the modifier attributes.

This way, starting QEMU without specifying the topology can
still get some adventage of the CPU topology.

s/adventage/advantage/

Signed-off-by: Pierre Morel <pmorel@linux.ibm.com>
---
  include/hw/s390x/cpu-topology.h |  48 ++++++
  hw/s390x/cpu-topology.c         | 293 ++++++++++++++++++++++++++++++++
  hw/s390x/s390-virtio-ccw.c      |  10 ++
  hw/s390x/meson.build            |   1 +
  4 files changed, 352 insertions(+)
  create mode 100644 hw/s390x/cpu-topology.c

diff --git a/include/hw/s390x/cpu-topology.h b/include/hw/s390x/cpu-topology.h
index d945b57fc3..b3fd752d8d 100644
--- a/include/hw/s390x/cpu-topology.h
+++ b/include/hw/s390x/cpu-topology.h
@@ -10,7 +10,11 @@
  #ifndef HW_S390X_CPU_TOPOLOGY_H
  #define HW_S390X_CPU_TOPOLOGY_H
+#include "qemu/queue.h"
+#include "hw/boards.h"
+
  #define S390_TOPOLOGY_CPU_IFL   0x03
+#define S390_TOPOLOGY_MAX_ORIGIN ((63 + S390_MAX_CPUS) / 64)
#define S390_TOPOLOGY_POLARITY_HORIZONTAL 0x00
  #define S390_TOPOLOGY_POLARITY_VERTICAL_LOW    0x01
@@ -20,4 +24,48 @@
  #define S390_TOPOLOGY_SHARED    0x00
  #define S390_TOPOLOGY_DEDICATED 0x01
+typedef union s390_topology_id {
+    uint64_t id;
+    struct {
+        uint64_t level_6:8; /* byte 0 BE */
+        uint64_t level_5:8; /* byte 1 BE */
+        uint64_t drawer:8;  /* byte 2 BE */
+        uint64_t book:8;    /* byte 3 BE */
+        uint64_t socket:8;  /* byte 4 BE */
+        uint64_t rsrv:5;
+        uint64_t d:1;
+        uint64_t p:2;       /* byte 5 BE */
+        uint64_t type:8;    /* byte 6 BE */
+        uint64_t origin:2;
+        uint64_t core:6;    /* byte 7 BE */
+    };
+} s390_topology_id;

Bitmasks are OK for code that will definitely only ever work with KVM ... but this will certainly fail completely if we ever try to get it running with TCG later. Do we care? ... if so, you should certainly avoid a bitfield here. Especially since most of the fields are 8-bit anyway and could easily be represented by a "uint8_t" variable. Otherwise, just ignore my comment.

+#define TOPO_CPU_MASK       0x000000000000003fUL
+
+typedef struct S390TopologyEntry {
+    s390_topology_id id;
+    QTAILQ_ENTRY(S390TopologyEntry) next;
+    uint64_t mask;
+} S390TopologyEntry;
+
+typedef struct S390Topology {
+    QTAILQ_HEAD(, S390TopologyEntry) list;
+    uint8_t *sockets;

So this "uint8_t" basically is a hidden limit of a maximum of 256 sockets that can be used for per book? Do we check that limit somewhere? (I looked for it, but I didn't spot such a check)

+    CpuTopology *smp;
+} S390Topology;
+
+#ifdef CONFIG_KVM
+bool s390_has_topology(void);
+void s390_topology_set_cpu(MachineState *ms, S390CPU *cpu, Error **errp);
+#else
+static inline bool s390_has_topology(void)
+{
+       return false;
+}
+static inline void s390_topology_set_cpu(MachineState *ms,
+                                         S390CPU *cpu,
+                                         Error **errp) {}
+#endif
+extern S390Topology s390_topology;
+
  #endif
diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c
new file mode 100644
index 0000000000..438055c612
--- /dev/null
+++ b/hw/s390x/cpu-topology.c
@@ -0,0 +1,293 @@
+/*
+ * CPU Topology
+ *
+ * Copyright IBM Corp. 2022

Want to update to 2023 now?

+ * Author(s): Pierre Morel <pmorel@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 "qapi/error.h"
+#include "qemu/error-report.h"
+#include "hw/qdev-properties.h"
+#include "hw/boards.h"
+#include "qemu/typedefs.h"
+#include "target/s390x/cpu.h"
+#include "hw/s390x/s390-virtio-ccw.h"
+#include "hw/s390x/cpu-topology.h"
+
+/*
+ * s390_topology is used to keep the topology information.
+ * .list: queue the topology entries inside which
+ *        we keep the information on the CPU topology.
+ *
+ * .smp: keeps track of the machine topology.
+ *
+ * .socket: tracks information on the count of cores per socket.
+ *
+ */
+S390Topology s390_topology = {
+    .list = QTAILQ_HEAD_INITIALIZER(s390_topology.list),
+    .sockets = NULL, /* will be initialized after the cpu model is realized */
+};
+
+/**
+ * s390_socket_nb:
+ * @id: s390_topology_id
+ *
+ * Returns the socket number used inside the socket array.
+ */
+static int s390_socket_nb(s390_topology_id id)
+{
+    return (id.socket + 1) * (id.book + 1) * (id.drawer + 1); > +}
I think there might be an off-by-one error in here - you likely need a "- 1" at the very end.

For example, assume that we have one socket, one book and one drawer, so id.socket, id.book and id.drawer would all be 0. The function then returns 1 ...

+static void s390_topology_init(MachineState *ms)
+{
+    CpuTopology *smp = &ms->smp;
+
+    s390_topology.smp = smp;
+    if (!s390_topology.sockets) {
+        s390_topology.sockets = g_new0(uint8_t, smp->sockets *
+                                       smp->books * smp->drawers);

... but here you only allocated one byte. So you later access s390_topology.sockets[s390_socket_nb(id)], i.e. s390_topology.sockets[1] which is out of bounds.

+    }
+}

 Thomas





reply via email to

[Prev in Thread] Current Thread [Next in Thread]