xref: /qemu/hw/s390x/cpu-topology.c (revision 154893a7)
1c809bbc8SPierre Morel /* SPDX-License-Identifier: GPL-2.0-or-later */
2c809bbc8SPierre Morel /*
3c809bbc8SPierre Morel  * CPU Topology
4c809bbc8SPierre Morel  *
5c809bbc8SPierre Morel  * Copyright IBM Corp. 2022, 2023
6c809bbc8SPierre Morel  * Author(s): Pierre Morel <pmorel@linux.ibm.com>
7c809bbc8SPierre Morel  *
8c809bbc8SPierre Morel  * S390 topology handling can be divided in two parts:
9c809bbc8SPierre Morel  *
10c809bbc8SPierre Morel  * - The first part in this file is taking care of all common functions
11c809bbc8SPierre Morel  *   used by KVM and TCG to create and modify the topology.
12c809bbc8SPierre Morel  *
13c809bbc8SPierre Morel  * - The second part, building the topology information data for the
14c809bbc8SPierre Morel  *   guest with CPU and KVM specificity will be implemented inside
15c809bbc8SPierre Morel  *   the target/s390/kvm sub tree.
16c809bbc8SPierre Morel  */
17c809bbc8SPierre Morel 
18c809bbc8SPierre Morel #include "qemu/osdep.h"
19c809bbc8SPierre Morel #include "qapi/error.h"
20c809bbc8SPierre Morel #include "qemu/error-report.h"
21c809bbc8SPierre Morel #include "hw/qdev-properties.h"
22c809bbc8SPierre Morel #include "hw/boards.h"
23c809bbc8SPierre Morel #include "target/s390x/cpu.h"
24c809bbc8SPierre Morel #include "hw/s390x/s390-virtio-ccw.h"
25c809bbc8SPierre Morel #include "hw/s390x/cpu-topology.h"
26a457c2abSPierre Morel #include "qapi/qapi-commands-machine-target.h"
271cfe52b7SPierre Morel #include "qapi/qapi-events-machine-target.h"
28c809bbc8SPierre Morel 
29c809bbc8SPierre Morel /*
30c809bbc8SPierre Morel  * s390_topology is used to keep the topology information.
31c809bbc8SPierre Morel  * .cores_per_socket: tracks information on the count of cores
32c809bbc8SPierre Morel  *                    per socket.
33f4f54b58SPierre Morel  * .polarization: tracks machine polarization.
34c809bbc8SPierre Morel  */
35c809bbc8SPierre Morel S390Topology s390_topology = {
36c809bbc8SPierre Morel     /* will be initialized after the CPU model is realized */
37c809bbc8SPierre Morel     .cores_per_socket = NULL,
38f4f54b58SPierre Morel     .polarization = S390_CPU_POLARIZATION_HORIZONTAL,
39c809bbc8SPierre Morel };
40c809bbc8SPierre Morel 
41c809bbc8SPierre Morel /**
42c809bbc8SPierre Morel  * s390_socket_nb:
43c809bbc8SPierre Morel  * @cpu: s390x CPU
44c809bbc8SPierre Morel  *
45c809bbc8SPierre Morel  * Returns the socket number used inside the cores_per_socket array
46c809bbc8SPierre Morel  * for a topology tree entry
47c809bbc8SPierre Morel  */
s390_socket_nb_from_ids(int drawer_id,int book_id,int socket_id)48c809bbc8SPierre Morel static int s390_socket_nb_from_ids(int drawer_id, int book_id, int socket_id)
49c809bbc8SPierre Morel {
50c809bbc8SPierre Morel     return (drawer_id * current_machine->smp.books + book_id) *
51c809bbc8SPierre Morel            current_machine->smp.sockets + socket_id;
52c809bbc8SPierre Morel }
53c809bbc8SPierre Morel 
54c809bbc8SPierre Morel /**
55c809bbc8SPierre Morel  * s390_socket_nb:
56c809bbc8SPierre Morel  * @cpu: s390x CPU
57c809bbc8SPierre Morel  *
58c809bbc8SPierre Morel  * Returns the socket number used inside the cores_per_socket array
59c809bbc8SPierre Morel  * for a cpu.
60c809bbc8SPierre Morel  */
s390_socket_nb(S390CPU * cpu)61c809bbc8SPierre Morel static int s390_socket_nb(S390CPU *cpu)
62c809bbc8SPierre Morel {
63c809bbc8SPierre Morel     return s390_socket_nb_from_ids(cpu->env.drawer_id, cpu->env.book_id,
64c809bbc8SPierre Morel                                    cpu->env.socket_id);
65c809bbc8SPierre Morel }
66c809bbc8SPierre Morel 
67c809bbc8SPierre Morel /**
68c809bbc8SPierre Morel  * s390_has_topology:
69c809bbc8SPierre Morel  *
70c809bbc8SPierre Morel  * Return: true if the topology is supported by the machine.
71c809bbc8SPierre Morel  */
s390_has_topology(void)72c809bbc8SPierre Morel bool s390_has_topology(void)
73c809bbc8SPierre Morel {
74f530b9e7SPierre Morel     return s390_has_feat(S390_FEAT_CONFIGURATION_TOPOLOGY);
75c809bbc8SPierre Morel }
76c809bbc8SPierre Morel 
77c809bbc8SPierre Morel /**
78c809bbc8SPierre Morel  * s390_topology_init:
79c809bbc8SPierre Morel  * @ms: the machine state where the machine topology is defined
80c809bbc8SPierre Morel  *
81c809bbc8SPierre Morel  * Keep track of the machine topology.
82c809bbc8SPierre Morel  *
83c809bbc8SPierre Morel  * Allocate an array to keep the count of cores per socket.
84c809bbc8SPierre Morel  * The index of the array starts at socket 0 from book 0 and
85c809bbc8SPierre Morel  * drawer 0 up to the maximum allowed by the machine topology.
86c809bbc8SPierre Morel  */
s390_topology_init(MachineState * ms)87c809bbc8SPierre Morel static void s390_topology_init(MachineState *ms)
88c809bbc8SPierre Morel {
89c809bbc8SPierre Morel     CpuTopology *smp = &ms->smp;
90c809bbc8SPierre Morel 
91c809bbc8SPierre Morel     s390_topology.cores_per_socket = g_new0(uint8_t, smp->sockets *
92c809bbc8SPierre Morel                                             smp->books * smp->drawers);
93c809bbc8SPierre Morel }
94c809bbc8SPierre Morel 
95af37bad5SPierre Morel /*
96af37bad5SPierre Morel  * s390_handle_ptf:
97af37bad5SPierre Morel  *
98af37bad5SPierre Morel  * @register 1: contains the function code
99af37bad5SPierre Morel  *
100af37bad5SPierre Morel  * Function codes 0 (horizontal) and 1 (vertical) define the CPU
101af37bad5SPierre Morel  * polarization requested by the guest.
102af37bad5SPierre Morel  *
103af37bad5SPierre Morel  * Function code 2 is handling topology changes and is interpreted
104af37bad5SPierre Morel  * by the SIE.
105af37bad5SPierre Morel  */
s390_handle_ptf(S390CPU * cpu,uint8_t r1,uintptr_t ra)106af37bad5SPierre Morel void s390_handle_ptf(S390CPU *cpu, uint8_t r1, uintptr_t ra)
107af37bad5SPierre Morel {
108af37bad5SPierre Morel     CpuS390Polarization polarization;
109af37bad5SPierre Morel     CPUS390XState *env = &cpu->env;
110af37bad5SPierre Morel     uint64_t reg = env->regs[r1];
111af37bad5SPierre Morel     int fc = reg & S390_TOPO_FC_MASK;
112af37bad5SPierre Morel 
113af37bad5SPierre Morel     if (!s390_has_feat(S390_FEAT_CONFIGURATION_TOPOLOGY)) {
114af37bad5SPierre Morel         s390_program_interrupt(env, PGM_OPERATION, ra);
115af37bad5SPierre Morel         return;
116af37bad5SPierre Morel     }
117af37bad5SPierre Morel 
118af37bad5SPierre Morel     if (env->psw.mask & PSW_MASK_PSTATE) {
119af37bad5SPierre Morel         s390_program_interrupt(env, PGM_PRIVILEGED, ra);
120af37bad5SPierre Morel         return;
121af37bad5SPierre Morel     }
122af37bad5SPierre Morel 
123af37bad5SPierre Morel     if (reg & ~S390_TOPO_FC_MASK) {
124af37bad5SPierre Morel         s390_program_interrupt(env, PGM_SPECIFICATION, ra);
125af37bad5SPierre Morel         return;
126af37bad5SPierre Morel     }
127af37bad5SPierre Morel 
128af37bad5SPierre Morel     polarization = S390_CPU_POLARIZATION_VERTICAL;
129af37bad5SPierre Morel     switch (fc) {
130af37bad5SPierre Morel     case 0:
131af37bad5SPierre Morel         polarization = S390_CPU_POLARIZATION_HORIZONTAL;
132af37bad5SPierre Morel         /* fallthrough */
133af37bad5SPierre Morel     case 1:
134af37bad5SPierre Morel         if (s390_topology.polarization == polarization) {
135af37bad5SPierre Morel             env->regs[r1] |= S390_PTF_REASON_DONE;
136af37bad5SPierre Morel             setcc(cpu, 2);
137af37bad5SPierre Morel         } else {
138af37bad5SPierre Morel             s390_topology.polarization = polarization;
139af37bad5SPierre Morel             s390_cpu_topology_set_changed(true);
1401cfe52b7SPierre Morel             qapi_event_send_cpu_polarization_change(polarization);
141af37bad5SPierre Morel             setcc(cpu, 0);
142af37bad5SPierre Morel         }
143af37bad5SPierre Morel         break;
144af37bad5SPierre Morel     default:
145af37bad5SPierre Morel         /* Note that fc == 2 is interpreted by the SIE */
146af37bad5SPierre Morel         s390_program_interrupt(env, PGM_SPECIFICATION, ra);
147af37bad5SPierre Morel     }
148af37bad5SPierre Morel }
149af37bad5SPierre Morel 
150c809bbc8SPierre Morel /**
1513d6e75f4SPierre Morel  * s390_topology_reset:
1523d6e75f4SPierre Morel  *
1533d6e75f4SPierre Morel  * Generic reset for CPU topology, calls s390_topology_reset()
1543d6e75f4SPierre Morel  * to reset the kernel Modified Topology Change Record.
1553d6e75f4SPierre Morel  */
s390_topology_reset(void)1563d6e75f4SPierre Morel void s390_topology_reset(void)
1573d6e75f4SPierre Morel {
1583d6e75f4SPierre Morel     s390_cpu_topology_set_changed(false);
159af37bad5SPierre Morel     s390_topology.polarization = S390_CPU_POLARIZATION_HORIZONTAL;
1603d6e75f4SPierre Morel }
1613d6e75f4SPierre Morel 
1623d6e75f4SPierre Morel /**
163c809bbc8SPierre Morel  * s390_topology_cpu_default:
164c809bbc8SPierre Morel  * @cpu: pointer to a S390CPU
165c809bbc8SPierre Morel  * @errp: Error pointer
166c809bbc8SPierre Morel  *
167c809bbc8SPierre Morel  * Setup the default topology if no attributes are already set.
168c809bbc8SPierre Morel  * Passing a CPU with some, but not all, attributes set is considered
169c809bbc8SPierre Morel  * an error.
170c809bbc8SPierre Morel  *
171c809bbc8SPierre Morel  * The function calculates the (drawer_id, book_id, socket_id)
172c809bbc8SPierre Morel  * topology by filling the cores starting from the first socket
173c809bbc8SPierre Morel  * (0, 0, 0) up to the last (smp->drawers, smp->books, smp->sockets).
174c809bbc8SPierre Morel  *
175c809bbc8SPierre Morel  * CPU type and dedication have defaults values set in the
176c809bbc8SPierre Morel  * s390x_cpu_properties, entitlement must be adjust depending on the
177c809bbc8SPierre Morel  * dedication.
178c809bbc8SPierre Morel  *
179c809bbc8SPierre Morel  * Returns false if it is impossible to setup a default topology
180c809bbc8SPierre Morel  * true otherwise.
181c809bbc8SPierre Morel  */
s390_topology_cpu_default(S390CPU * cpu,Error ** errp)182c809bbc8SPierre Morel static bool s390_topology_cpu_default(S390CPU *cpu, Error **errp)
183c809bbc8SPierre Morel {
184c809bbc8SPierre Morel     CpuTopology *smp = &current_machine->smp;
185c809bbc8SPierre Morel     CPUS390XState *env = &cpu->env;
186c809bbc8SPierre Morel 
187c809bbc8SPierre Morel     /* All geometry topology attributes must be set or all unset */
188c809bbc8SPierre Morel     if ((env->socket_id < 0 || env->book_id < 0 || env->drawer_id < 0) &&
189c809bbc8SPierre Morel         (env->socket_id >= 0 || env->book_id >= 0 || env->drawer_id >= 0)) {
190c809bbc8SPierre Morel         error_setg(errp,
191c809bbc8SPierre Morel                    "Please define all or none of the topology geometry attributes");
192c809bbc8SPierre Morel         return false;
193c809bbc8SPierre Morel     }
194c809bbc8SPierre Morel 
195c809bbc8SPierre Morel     /* If one value is unset all are unset -> calculate defaults */
196c809bbc8SPierre Morel     if (env->socket_id < 0) {
197c809bbc8SPierre Morel         env->socket_id = s390_std_socket(env->core_id, smp);
198c809bbc8SPierre Morel         env->book_id = s390_std_book(env->core_id, smp);
199c809bbc8SPierre Morel         env->drawer_id = s390_std_drawer(env->core_id, smp);
200c809bbc8SPierre Morel     }
201c809bbc8SPierre Morel 
202c809bbc8SPierre Morel     /*
203c809bbc8SPierre Morel      * When the user specifies the entitlement as 'auto' on the command line,
204c809bbc8SPierre Morel      * QEMU will set the entitlement as:
205c809bbc8SPierre Morel      * Medium when the CPU is not dedicated.
206c809bbc8SPierre Morel      * High when dedicated is true.
207c809bbc8SPierre Morel      */
208c809bbc8SPierre Morel     if (env->entitlement == S390_CPU_ENTITLEMENT_AUTO) {
209c809bbc8SPierre Morel         if (env->dedicated) {
210c809bbc8SPierre Morel             env->entitlement = S390_CPU_ENTITLEMENT_HIGH;
211c809bbc8SPierre Morel         } else {
212c809bbc8SPierre Morel             env->entitlement = S390_CPU_ENTITLEMENT_MEDIUM;
213c809bbc8SPierre Morel         }
214c809bbc8SPierre Morel     }
215c809bbc8SPierre Morel     return true;
216c809bbc8SPierre Morel }
217c809bbc8SPierre Morel 
218c809bbc8SPierre Morel /**
219c809bbc8SPierre Morel  * s390_topology_check:
220c809bbc8SPierre Morel  * @socket_id: socket to check
221c809bbc8SPierre Morel  * @book_id: book to check
222c809bbc8SPierre Morel  * @drawer_id: drawer to check
223c809bbc8SPierre Morel  * @entitlement: entitlement to check
224c809bbc8SPierre Morel  * @dedicated: dedication to check
225c809bbc8SPierre Morel  * @errp: Error pointer
226c809bbc8SPierre Morel  *
227c809bbc8SPierre Morel  * The function checks if the topology
228c809bbc8SPierre Morel  * attributes fits inside the system topology.
229c809bbc8SPierre Morel  *
230c809bbc8SPierre Morel  * Returns false if the specified topology does not match with
231c809bbc8SPierre Morel  * the machine topology.
232c809bbc8SPierre Morel  */
s390_topology_check(uint16_t socket_id,uint16_t book_id,uint16_t drawer_id,uint16_t entitlement,bool dedicated,Error ** errp)233c809bbc8SPierre Morel static bool s390_topology_check(uint16_t socket_id, uint16_t book_id,
234c809bbc8SPierre Morel                                 uint16_t drawer_id, uint16_t entitlement,
235c809bbc8SPierre Morel                                 bool dedicated, Error **errp)
236c809bbc8SPierre Morel {
237c809bbc8SPierre Morel     CpuTopology *smp = &current_machine->smp;
238c809bbc8SPierre Morel 
239c809bbc8SPierre Morel     if (socket_id >= smp->sockets) {
240c809bbc8SPierre Morel         error_setg(errp, "Unavailable socket: %d", socket_id);
241c809bbc8SPierre Morel         return false;
242c809bbc8SPierre Morel     }
243c809bbc8SPierre Morel     if (book_id >= smp->books) {
244c809bbc8SPierre Morel         error_setg(errp, "Unavailable book: %d", book_id);
245c809bbc8SPierre Morel         return false;
246c809bbc8SPierre Morel     }
247c809bbc8SPierre Morel     if (drawer_id >= smp->drawers) {
248c809bbc8SPierre Morel         error_setg(errp, "Unavailable drawer: %d", drawer_id);
249c809bbc8SPierre Morel         return false;
250c809bbc8SPierre Morel     }
251c809bbc8SPierre Morel     if (entitlement >= S390_CPU_ENTITLEMENT__MAX) {
252c809bbc8SPierre Morel         error_setg(errp, "Unknown entitlement: %d", entitlement);
253c809bbc8SPierre Morel         return false;
254c809bbc8SPierre Morel     }
255c809bbc8SPierre Morel     if (dedicated && (entitlement == S390_CPU_ENTITLEMENT_LOW ||
256c809bbc8SPierre Morel                       entitlement == S390_CPU_ENTITLEMENT_MEDIUM)) {
257c809bbc8SPierre Morel         error_setg(errp, "A dedicated CPU implies high entitlement");
258c809bbc8SPierre Morel         return false;
259c809bbc8SPierre Morel     }
260c809bbc8SPierre Morel     return true;
261c809bbc8SPierre Morel }
262c809bbc8SPierre Morel 
263c809bbc8SPierre Morel /**
264a457c2abSPierre Morel  * s390_topology_need_report
265a457c2abSPierre Morel  * @cpu: Current cpu
266a457c2abSPierre Morel  * @drawer_id: future drawer ID
267a457c2abSPierre Morel  * @book_id: future book ID
268a457c2abSPierre Morel  * @socket_id: future socket ID
269a457c2abSPierre Morel  * @entitlement: future entitlement
270a457c2abSPierre Morel  * @dedicated: future dedicated
271a457c2abSPierre Morel  *
272a457c2abSPierre Morel  * A modified topology change report is needed if the topology
273a457c2abSPierre Morel  * tree or the topology attributes change.
274a457c2abSPierre Morel  */
s390_topology_need_report(S390CPU * cpu,int drawer_id,int book_id,int socket_id,uint16_t entitlement,bool dedicated)275a457c2abSPierre Morel static bool s390_topology_need_report(S390CPU *cpu, int drawer_id,
276a457c2abSPierre Morel                                       int book_id, int socket_id,
277a457c2abSPierre Morel                                       uint16_t entitlement, bool dedicated)
278a457c2abSPierre Morel {
279a457c2abSPierre Morel     return cpu->env.drawer_id != drawer_id ||
280a457c2abSPierre Morel            cpu->env.book_id != book_id ||
281a457c2abSPierre Morel            cpu->env.socket_id != socket_id ||
282a457c2abSPierre Morel            cpu->env.entitlement != entitlement ||
283a457c2abSPierre Morel            cpu->env.dedicated != dedicated;
284a457c2abSPierre Morel }
285a457c2abSPierre Morel 
286a457c2abSPierre Morel /**
287c809bbc8SPierre Morel  * s390_update_cpu_props:
288c809bbc8SPierre Morel  * @ms: the machine state
289c809bbc8SPierre Morel  * @cpu: the CPU for which to update the properties from the environment.
290c809bbc8SPierre Morel  *
291c809bbc8SPierre Morel  */
s390_update_cpu_props(MachineState * ms,S390CPU * cpu)292c809bbc8SPierre Morel static void s390_update_cpu_props(MachineState *ms, S390CPU *cpu)
293c809bbc8SPierre Morel {
294c809bbc8SPierre Morel     CpuInstanceProperties *props;
295c809bbc8SPierre Morel 
296c809bbc8SPierre Morel     props = &ms->possible_cpus->cpus[cpu->env.core_id].props;
297c809bbc8SPierre Morel 
298c809bbc8SPierre Morel     props->socket_id = cpu->env.socket_id;
299c809bbc8SPierre Morel     props->book_id = cpu->env.book_id;
300c809bbc8SPierre Morel     props->drawer_id = cpu->env.drawer_id;
301c809bbc8SPierre Morel }
302c809bbc8SPierre Morel 
303c809bbc8SPierre Morel /**
304c809bbc8SPierre Morel  * s390_topology_setup_cpu:
305c809bbc8SPierre Morel  * @ms: MachineState used to initialize the topology structure on
306c809bbc8SPierre Morel  *      first call.
307c809bbc8SPierre Morel  * @cpu: the new S390CPU to insert in the topology structure
308c809bbc8SPierre Morel  * @errp: the error pointer
309c809bbc8SPierre Morel  *
310c809bbc8SPierre Morel  * Called from CPU hotplug to check and setup the CPU attributes
311c809bbc8SPierre Morel  * before the CPU is inserted in the topology.
312c809bbc8SPierre Morel  * There is no need to update the MTCR explicitly here because it
313c809bbc8SPierre Morel  * will be updated by KVM on creation of the new CPU.
314c809bbc8SPierre Morel  */
s390_topology_setup_cpu(MachineState * ms,S390CPU * cpu,Error ** errp)315c809bbc8SPierre Morel void s390_topology_setup_cpu(MachineState *ms, S390CPU *cpu, Error **errp)
316c809bbc8SPierre Morel {
317c809bbc8SPierre Morel     int entry;
318c809bbc8SPierre Morel 
319c809bbc8SPierre Morel     /*
320c809bbc8SPierre Morel      * We do not want to initialize the topology if the CPU model
321c809bbc8SPierre Morel      * does not support topology, consequently, we have to wait for
322c809bbc8SPierre Morel      * the first CPU to be realized, which realizes the CPU model
323c809bbc8SPierre Morel      * to initialize the topology structures.
324c809bbc8SPierre Morel      *
325c809bbc8SPierre Morel      * s390_topology_setup_cpu() is called from the CPU hotplug.
326c809bbc8SPierre Morel      */
327c809bbc8SPierre Morel     if (!s390_topology.cores_per_socket) {
328c809bbc8SPierre Morel         s390_topology_init(ms);
329c809bbc8SPierre Morel     }
330c809bbc8SPierre Morel 
331c809bbc8SPierre Morel     if (!s390_topology_cpu_default(cpu, errp)) {
332c809bbc8SPierre Morel         return;
333c809bbc8SPierre Morel     }
334c809bbc8SPierre Morel 
335c809bbc8SPierre Morel     if (!s390_topology_check(cpu->env.socket_id, cpu->env.book_id,
336c809bbc8SPierre Morel                              cpu->env.drawer_id, cpu->env.entitlement,
337c809bbc8SPierre Morel                              cpu->env.dedicated, errp)) {
338c809bbc8SPierre Morel         return;
339c809bbc8SPierre Morel     }
340c809bbc8SPierre Morel 
341c809bbc8SPierre Morel     /* Do we still have space in the socket */
342c809bbc8SPierre Morel     entry = s390_socket_nb(cpu);
343c809bbc8SPierre Morel     if (s390_topology.cores_per_socket[entry] >= ms->smp.cores) {
344c809bbc8SPierre Morel         error_setg(errp, "No more space on this socket");
345c809bbc8SPierre Morel         return;
346c809bbc8SPierre Morel     }
347c809bbc8SPierre Morel 
348c809bbc8SPierre Morel     /* Update the count of cores in sockets */
349c809bbc8SPierre Morel     s390_topology.cores_per_socket[entry] += 1;
350c809bbc8SPierre Morel 
351c809bbc8SPierre Morel     /* topology tree is reflected in props */
352c809bbc8SPierre Morel     s390_update_cpu_props(ms, cpu);
353c809bbc8SPierre Morel }
354a457c2abSPierre Morel 
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)355a457c2abSPierre Morel static void s390_change_topology(uint16_t core_id,
356a457c2abSPierre Morel                                  bool has_socket_id, uint16_t socket_id,
357a457c2abSPierre Morel                                  bool has_book_id, uint16_t book_id,
358a457c2abSPierre Morel                                  bool has_drawer_id, uint16_t drawer_id,
359a457c2abSPierre Morel                                  bool has_entitlement,
360a457c2abSPierre Morel                                  CpuS390Entitlement entitlement,
361a457c2abSPierre Morel                                  bool has_dedicated, bool dedicated,
362a457c2abSPierre Morel                                  Error **errp)
363a457c2abSPierre Morel {
364a457c2abSPierre Morel     MachineState *ms = current_machine;
365a457c2abSPierre Morel     int old_socket_entry;
366a457c2abSPierre Morel     int new_socket_entry;
367a457c2abSPierre Morel     bool report_needed;
368a457c2abSPierre Morel     S390CPU *cpu;
369a457c2abSPierre Morel 
370a457c2abSPierre Morel     cpu = s390_cpu_addr2state(core_id);
371a457c2abSPierre Morel     if (!cpu) {
372a457c2abSPierre Morel         error_setg(errp, "Core-id %d does not exist!", core_id);
373a457c2abSPierre Morel         return;
374a457c2abSPierre Morel     }
375a457c2abSPierre Morel 
376a457c2abSPierre Morel     /* Get attributes not provided from cpu and verify the new topology */
377a457c2abSPierre Morel     if (!has_socket_id) {
378a457c2abSPierre Morel         socket_id = cpu->env.socket_id;
379a457c2abSPierre Morel     }
380a457c2abSPierre Morel     if (!has_book_id) {
381a457c2abSPierre Morel         book_id = cpu->env.book_id;
382a457c2abSPierre Morel     }
383a457c2abSPierre Morel     if (!has_drawer_id) {
384a457c2abSPierre Morel         drawer_id = cpu->env.drawer_id;
385a457c2abSPierre Morel     }
386a457c2abSPierre Morel     if (!has_dedicated) {
387a457c2abSPierre Morel         dedicated = cpu->env.dedicated;
388a457c2abSPierre Morel     }
389a457c2abSPierre Morel 
390a457c2abSPierre Morel     /*
391a457c2abSPierre Morel      * When the user specifies the entitlement as 'auto' on the command line,
392a457c2abSPierre Morel      * QEMU will set the entitlement as:
393a457c2abSPierre Morel      * Medium when the CPU is not dedicated.
394a457c2abSPierre Morel      * High when dedicated is true.
395a457c2abSPierre Morel      */
396a457c2abSPierre Morel     if (!has_entitlement || entitlement == S390_CPU_ENTITLEMENT_AUTO) {
397a457c2abSPierre Morel         if (dedicated) {
398a457c2abSPierre Morel             entitlement = S390_CPU_ENTITLEMENT_HIGH;
399a457c2abSPierre Morel         } else {
400a457c2abSPierre Morel             entitlement = S390_CPU_ENTITLEMENT_MEDIUM;
401a457c2abSPierre Morel         }
402a457c2abSPierre Morel     }
403a457c2abSPierre Morel 
404a457c2abSPierre Morel     if (!s390_topology_check(socket_id, book_id, drawer_id,
405a457c2abSPierre Morel                              entitlement, dedicated, errp)) {
406a457c2abSPierre Morel         return;
407a457c2abSPierre Morel     }
408a457c2abSPierre Morel 
409a457c2abSPierre Morel     /* Check for space on new socket */
410a457c2abSPierre Morel     old_socket_entry = s390_socket_nb(cpu);
411a457c2abSPierre Morel     new_socket_entry = s390_socket_nb_from_ids(drawer_id, book_id, socket_id);
412a457c2abSPierre Morel 
413a457c2abSPierre Morel     if (new_socket_entry != old_socket_entry) {
414a457c2abSPierre Morel         if (s390_topology.cores_per_socket[new_socket_entry] >=
415a457c2abSPierre Morel             ms->smp.cores) {
416a457c2abSPierre Morel             error_setg(errp, "No more space on this socket");
417a457c2abSPierre Morel             return;
418a457c2abSPierre Morel         }
419a457c2abSPierre Morel         /* Update the count of cores in sockets */
420a457c2abSPierre Morel         s390_topology.cores_per_socket[new_socket_entry] += 1;
421a457c2abSPierre Morel         s390_topology.cores_per_socket[old_socket_entry] -= 1;
422a457c2abSPierre Morel     }
423a457c2abSPierre Morel 
424a457c2abSPierre Morel     /* Check if we will need to report the modified topology */
425a457c2abSPierre Morel     report_needed = s390_topology_need_report(cpu, drawer_id, book_id,
426a457c2abSPierre Morel                                               socket_id, entitlement,
427a457c2abSPierre Morel                                               dedicated);
428a457c2abSPierre Morel 
429a457c2abSPierre Morel     /* All checks done, report new topology into the vCPU */
430a457c2abSPierre Morel     cpu->env.drawer_id = drawer_id;
431a457c2abSPierre Morel     cpu->env.book_id = book_id;
432a457c2abSPierre Morel     cpu->env.socket_id = socket_id;
433a457c2abSPierre Morel     cpu->env.dedicated = dedicated;
434a457c2abSPierre Morel     cpu->env.entitlement = entitlement;
435a457c2abSPierre Morel 
436a457c2abSPierre Morel     /* topology tree is reflected in props */
437a457c2abSPierre Morel     s390_update_cpu_props(ms, cpu);
438a457c2abSPierre Morel 
439a457c2abSPierre Morel     /* Advertise the topology change */
440a457c2abSPierre Morel     if (report_needed) {
441a457c2abSPierre Morel         s390_cpu_topology_set_changed(true);
442a457c2abSPierre Morel     }
443a457c2abSPierre Morel }
444a457c2abSPierre Morel 
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)445a457c2abSPierre Morel void qmp_set_cpu_topology(uint16_t core,
446a457c2abSPierre Morel                           bool has_socket, uint16_t socket,
447a457c2abSPierre Morel                           bool has_book, uint16_t book,
448a457c2abSPierre Morel                           bool has_drawer, uint16_t drawer,
449a457c2abSPierre Morel                           bool has_entitlement, CpuS390Entitlement entitlement,
450a457c2abSPierre Morel                           bool has_dedicated, bool dedicated,
451a457c2abSPierre Morel                           Error **errp)
452a457c2abSPierre Morel {
453a457c2abSPierre Morel     if (!s390_has_topology()) {
454a457c2abSPierre Morel         error_setg(errp, "This machine doesn't support topology");
455a457c2abSPierre Morel         return;
456a457c2abSPierre Morel     }
457a457c2abSPierre Morel 
458a457c2abSPierre Morel     s390_change_topology(core, has_socket, socket, has_book, book,
459a457c2abSPierre Morel                          has_drawer, drawer, has_entitlement, entitlement,
460a457c2abSPierre Morel                          has_dedicated, dedicated, errp);
461a457c2abSPierre Morel }
462154893a7SPierre Morel 
qmp_query_s390x_cpu_polarization(Error ** errp)463154893a7SPierre Morel CpuPolarizationInfo *qmp_query_s390x_cpu_polarization(Error **errp)
464154893a7SPierre Morel {
465154893a7SPierre Morel     CpuPolarizationInfo *info = g_new0(CpuPolarizationInfo, 1);
466154893a7SPierre Morel 
467154893a7SPierre Morel     info->polarization = s390_topology.polarization;
468154893a7SPierre Morel     return info;
469154893a7SPierre Morel }
470