On Wed, 2022-10-12 at 18:20 +0200, Pierre Morel wrote: > In the S390x CPU topology the core_id specifies the CPU address > and the position of the core withing the topology. > > Let's build the topology based on the core_id. > s390x/cpu topology: core_id sets s390x CPU topology > > In the S390x CPU topology the core_id specifies the CPU address > and the position of the cpu withing the topology. > > Let's build the topology based on the core_id. > > Signed-off-by: Pierre Morel <pmo...@linux.ibm.com> > --- > include/hw/s390x/cpu-topology.h | 45 +++++++++++ > hw/s390x/cpu-topology.c | 132 ++++++++++++++++++++++++++++++++ > hw/s390x/s390-virtio-ccw.c | 21 +++++ > hw/s390x/meson.build | 1 + > 4 files changed, 199 insertions(+) > create mode 100644 include/hw/s390x/cpu-topology.h > create mode 100644 hw/s390x/cpu-topology.c > > diff --git a/include/hw/s390x/cpu-topology.h b/include/hw/s390x/cpu-topology.h > new file mode 100644 > index 0000000000..66c171d0bc > --- /dev/null > +++ b/include/hw/s390x/cpu-topology.h > @@ -0,0 +1,45 @@ > +/* > + * CPU Topology > + * > + * Copyright 2022 IBM Corp. > + * > + * 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. > + */ > +#ifndef HW_S390X_CPU_TOPOLOGY_H > +#define HW_S390X_CPU_TOPOLOGY_H > + > +#include "hw/qdev-core.h" > +#include "qom/object.h" > + > +typedef struct S390TopoContainer { > + int active_count; > +} S390TopoContainer; > + > +#define S390_TOPOLOGY_CPU_IFL 0x03 > +#define S390_TOPOLOGY_MAX_ORIGIN ((63 + S390_MAX_CPUS) / 64) > +typedef struct S390TopoTLE { > + uint64_t mask[S390_TOPOLOGY_MAX_ORIGIN]; > +} S390TopoTLE;
Since this actually represents multiple TLEs, you might want to change the name of the struct to reflect this. S390TopoTLEList maybe? > + > +struct S390Topology { > + SysBusDevice parent_obj; > + int cpus; > + S390TopoContainer *socket; > + S390TopoTLE *tle; > + MachineState *ms; > +}; > + > +#define TYPE_S390_CPU_TOPOLOGY "s390-topology" > +OBJECT_DECLARE_SIMPLE_TYPE(S390Topology, S390_CPU_TOPOLOGY) > + > +S390Topology *s390_get_topology(void); > +void s390_topology_new_cpu(int core_id); > + > +static inline bool s390_has_topology(void) > +{ > + return false; > +} > + > +#endif > diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c > new file mode 100644 > index 0000000000..42b22a1831 > --- /dev/null > +++ b/hw/s390x/cpu-topology.c > @@ -0,0 +1,132 @@ > +/* > + * CPU Topology > + * > + * Copyright IBM Corp. 2022 > + * Author(s): Pierre Morel <pmo...@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/sysbus.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" > + > +S390Topology *s390_get_topology(void) > +{ > + static S390Topology *s390Topology; > + > + if (!s390Topology) { > + s390Topology = S390_CPU_TOPOLOGY( > + object_resolve_path(TYPE_S390_CPU_TOPOLOGY, NULL)); > + } > + > + return s390Topology; > +} > + > +/* > + * s390_topology_new_cpu: > + * @core_id: the core ID is machine wide > + * > + * The topology returned by s390_get_topology(), gives us the CPU > + * topology established by the -smp QEMU aruments. s/aruments/arguments/ > + * The core-id gives: > + * - the Container TLE (Topology List Entry) containing the CPU TLE. > + * - in the CPU TLE the origin, or offset of the first bit in the core mask > + * - the bit in the CPU TLE core mask > + */ Not sure if that comment helps if you don't already know how the topology list works. > +void s390_topology_new_cpu(int core_id) > +{ > + S390Topology *topo = s390_get_topology(); > + int socket_id; > + int bit, origin; > + > + /* In the case no Topology is used nothing is to be done here */ > + if (!topo) { > + return; > + } > + > + socket_id = core_id / topo->cpus; > + > + /* > + * At the core level, each CPU is represented by a bit in a 64bit > + * unsigned long which represent the presence of a CPU. > + * The firmware assume that all CPU in a CPU TLE have the same s/firmware assume/architecture specifies/ > + * type, polarization and are all dedicated or shared. > + * In that case the origin variable represents the offset of the first > + * CPU in the CPU container. This sentence is repeated further down. > + * More than 64 CPUs per socket are represented in several CPU containers > + * inside the socket container. > + * The only reason to have several S390TopologyCores inside a socket is > + * to have more than 64 CPUs. > + * In that case the origin variable represents the offset of the first > CPU > + * in the CPU container. More than 64 CPUs per socket are represented in > + * several CPU containers inside the socket container. > + */ In the last version you had: + /* + * At the core level, each CPU is represented by a bit in a 64bit + * unsigned long. Set on plug and clear on unplug of a CPU. + * The firmware assume that all CPU in a CPU TLE have the same + * type, polarization and are all dedicated or shared. + * In the case a socket contains CPU with different type, polarization + * or entitlement then they will be defined in different CPU containers. + * Currently we assume all CPU are identical IFL CPUs and that they are + * all dedicated CPUs. + * The only reason to have several S390TopologyCores inside a socket is + * to have more than 64 CPUs. + * In that case the origin field, representing the offset of the first CPU + * in the CPU container allows to represent up to the maximal number of + * CPU inside several CPU containers inside the socket container. + */ I would modify it thus (with better line wrapping): + /* + * At the core level, each CPU is represented by a bit in a 64bit + * unsigned long. + * The architecture specifies that all CPU in a CPU TLE have the same + * type, polarization and are all dedicated or shared. + * In the case that a socket contains CPUs with different type, polarization + * or entitlement then they will be defined in different CPU containers. + * Currently we assume all CPU are identical IFL CPUs and that they are + * all dedicated CPUs. + * Therefore, the only reason to have several S390TopologyCores inside a socket is + * to support CPU id differences > 64. + * In that case, the origin field in a container represents the offset of the first CPU + * in that CPU container, thereby allowing representation of all CPUs via multiple containers. + */ > + bit = core_id; > + origin = bit / 64; > + bit %= 64; > + bit = 63 - bit; I'm not convinced that that is more readable than just origin = core_id / 64; bit = 63 - (core_id % 64); but that is for you to decide. > + > + topo->socket[socket_id].active_count++; > + set_bit(bit, &topo->tle[socket_id].mask[origin]); > +} > + > +/** > + * s390_topology_realize: > + * @dev: the device state > + * @errp: the error pointer (not used) > + * > + * During realize the machine CPU topology is initialized with the > + * QEMU -smp parameters. > + * The maximum count of CPU TLE in the all Topology can not be greater > + * than the maximum CPUs. > + */ > +static void s390_topology_realize(DeviceState *dev, Error **errp) > +{ > + MachineState *ms = MACHINE(qdev_get_machine()); > + S390Topology *topo = S390_CPU_TOPOLOGY(dev); > + > + topo->cpus = ms->smp.cores * ms->smp.threads; > + > + topo->socket = g_new0(S390TopoContainer, ms->smp.sockets); > + topo->tle = g_new0(S390TopoTLE, ms->smp.max_cpus); As Cédric pointed out, the number of TLE(List)s should be the same as the sockets. > + > + topo->ms = ms; > +} [...]