]> git.proxmox.com Git - mirror_qemu.git/blame - tests/avocado/s390_topology.py
tests/avocado/machine_aspeed.py: Update buildroot images to 2023.11
[mirror_qemu.git] / tests / avocado / s390_topology.py
CommitLineData
e5bc49d5
PM
1# Functional test that boots a Linux kernel and checks the console
2#
3# Copyright IBM Corp. 2023
4#
5# Author:
6# Pierre Morel <pmorel@linux.ibm.com>
7#
8# This work is licensed under the terms of the GNU GPL, version 2 or
9# later. See the COPYING file in the top-level directory.
10
11import os
12import shutil
13import time
14
15from avocado_qemu import QemuSystemTest
16from avocado_qemu import exec_command
17from avocado_qemu import exec_command_and_wait_for_pattern
18from avocado_qemu import interrupt_interactive_console_until_pattern
19from avocado_qemu import wait_for_console_pattern
20from avocado.utils import process
21from avocado.utils import archive
22
23
24class S390CPUTopology(QemuSystemTest):
25 """
26 S390x CPU topology consists of 4 topology layers, from bottom to top,
27 the cores, sockets, books and drawers and 2 modifiers attributes,
28 the entitlement and the dedication.
29 See: docs/system/s390x/cpu-topology.rst.
30
31 S390x CPU topology is setup in different ways:
32 - implicitly from the '-smp' argument by completing each topology
33 level one after the other beginning with drawer 0, book 0 and
34 socket 0.
35 - explicitly from the '-device' argument on the QEMU command line
36 - explicitly by hotplug of a new CPU using QMP or HMP
37 - it is modified by using QMP 'set-cpu-topology'
38
39 The S390x modifier attribute entitlement depends on the machine
40 polarization, which can be horizontal or vertical.
41 The polarization is changed on a request from the guest.
42 """
43 timeout = 90
cb042c73 44 event_timeout = 10
e5bc49d5
PM
45
46 KERNEL_COMMON_COMMAND_LINE = ('printk.time=0 '
47 'root=/dev/ram '
48 'selinux=0 '
49 'rdinit=/bin/sh')
50
51 def wait_until_booted(self):
52 wait_for_console_pattern(self, 'no job control',
53 failure_message='Kernel panic - not syncing',
54 vm=None)
55
56 def check_topology(self, c, s, b, d, e, t):
57 res = self.vm.qmp('query-cpus-fast')
58 cpus = res['return']
59 for cpu in cpus:
60 core = cpu['props']['core-id']
61 socket = cpu['props']['socket-id']
62 book = cpu['props']['book-id']
63 drawer = cpu['props']['drawer-id']
64 entitlement = cpu.get('entitlement')
65 dedicated = cpu.get('dedicated')
66 if core == c:
67 self.assertEqual(drawer, d)
68 self.assertEqual(book, b)
69 self.assertEqual(socket, s)
70 self.assertEqual(entitlement, e)
71 self.assertEqual(dedicated, t)
72
73 def kernel_init(self):
74 """
75 We need a VM that supports CPU topology,
76 currently this only the case when using KVM, not TCG.
77 We need a kernel supporting the CPU topology.
78 We need a minimal root filesystem with a shell.
79 """
80 self.require_accelerator("kvm")
81 kernel_url = ('https://archives.fedoraproject.org/pub/archive'
82 '/fedora-secondary/releases/35/Server/s390x/os'
83 '/images/kernel.img')
84 kernel_hash = '0d1aaaf303f07cf0160c8c48e56fe638'
85 kernel_path = self.fetch_asset(kernel_url, algorithm='md5',
86 asset_hash=kernel_hash)
87
88 initrd_url = ('https://archives.fedoraproject.org/pub/archive'
89 '/fedora-secondary/releases/35/Server/s390x/os'
90 '/images/initrd.img')
91 initrd_hash = 'a122057d95725ac030e2ec51df46e172'
92 initrd_path_xz = self.fetch_asset(initrd_url, algorithm='md5',
93 asset_hash=initrd_hash)
94 initrd_path = os.path.join(self.workdir, 'initrd-raw.img')
95 archive.lzma_uncompress(initrd_path_xz, initrd_path)
96
97 self.vm.set_console()
98 kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE
99 self.vm.add_args('-nographic',
100 '-enable-kvm',
101 '-cpu', 'max,ctop=on',
102 '-m', '512',
103 '-kernel', kernel_path,
104 '-initrd', initrd_path,
105 '-append', kernel_command_line)
106
cb042c73
PM
107 def system_init(self):
108 self.log.info("System init")
109 exec_command_and_wait_for_pattern(self,
110 """ mount proc -t proc /proc;
111 mount sys -t sysfs /sys;
112 cat /sys/devices/system/cpu/dispatching """,
113 '0')
114
e5bc49d5
PM
115 def test_single(self):
116 """
117 This test checks the simplest topology with a single CPU.
118
119 :avocado: tags=arch:s390x
120 :avocado: tags=machine:s390-ccw-virtio
121 """
122 self.kernel_init()
123 self.vm.launch()
124 self.wait_until_booted()
125 self.check_topology(0, 0, 0, 0, 'medium', False)
126
127 def test_default(self):
128 """
129 This test checks the implicit topology.
130
131 :avocado: tags=arch:s390x
132 :avocado: tags=machine:s390-ccw-virtio
133 """
134 self.kernel_init()
135 self.vm.add_args('-smp',
136 '13,drawers=2,books=2,sockets=3,cores=2,maxcpus=24')
137 self.vm.launch()
138 self.wait_until_booted()
139 self.check_topology(0, 0, 0, 0, 'medium', False)
140 self.check_topology(1, 0, 0, 0, 'medium', False)
141 self.check_topology(2, 1, 0, 0, 'medium', False)
142 self.check_topology(3, 1, 0, 0, 'medium', False)
143 self.check_topology(4, 2, 0, 0, 'medium', False)
144 self.check_topology(5, 2, 0, 0, 'medium', False)
145 self.check_topology(6, 0, 1, 0, 'medium', False)
146 self.check_topology(7, 0, 1, 0, 'medium', False)
147 self.check_topology(8, 1, 1, 0, 'medium', False)
148 self.check_topology(9, 1, 1, 0, 'medium', False)
149 self.check_topology(10, 2, 1, 0, 'medium', False)
150 self.check_topology(11, 2, 1, 0, 'medium', False)
151 self.check_topology(12, 0, 0, 1, 'medium', False)
152
153 def test_move(self):
154 """
155 This test checks the topology modification by moving a CPU
156 to another socket: CPU 0 is moved from socket 0 to socket 2.
157
158 :avocado: tags=arch:s390x
159 :avocado: tags=machine:s390-ccw-virtio
160 """
161 self.kernel_init()
162 self.vm.add_args('-smp',
163 '1,drawers=2,books=2,sockets=3,cores=2,maxcpus=24')
164 self.vm.launch()
165 self.wait_until_booted()
166
167 self.check_topology(0, 0, 0, 0, 'medium', False)
168 res = self.vm.qmp('set-cpu-topology',
169 {'core-id': 0, 'socket-id': 2, 'entitlement': 'low'})
170 self.assertEqual(res['return'], {})
171 self.check_topology(0, 2, 0, 0, 'low', False)
172
173 def test_dash_device(self):
174 """
175 This test verifies that a CPU defined with the '-device'
176 command line option finds its right place inside the topology.
177
178 :avocado: tags=arch:s390x
179 :avocado: tags=machine:s390-ccw-virtio
180 """
181 self.kernel_init()
182 self.vm.add_args('-smp',
183 '1,drawers=2,books=2,sockets=3,cores=2,maxcpus=24')
184 self.vm.add_args('-device', 'max-s390x-cpu,core-id=10')
185 self.vm.add_args('-device',
186 'max-s390x-cpu,'
187 'core-id=1,socket-id=0,book-id=1,drawer-id=1,entitlement=low')
188 self.vm.add_args('-device',
189 'max-s390x-cpu,'
190 'core-id=2,socket-id=0,book-id=1,drawer-id=1,entitlement=medium')
191 self.vm.add_args('-device',
192 'max-s390x-cpu,'
193 'core-id=3,socket-id=1,book-id=1,drawer-id=1,entitlement=high')
194 self.vm.add_args('-device',
195 'max-s390x-cpu,'
196 'core-id=4,socket-id=1,book-id=1,drawer-id=1')
197 self.vm.add_args('-device',
198 'max-s390x-cpu,'
199 'core-id=5,socket-id=2,book-id=1,drawer-id=1,dedicated=true')
200
201 self.vm.launch()
202 self.wait_until_booted()
203
204 self.check_topology(10, 2, 1, 0, 'medium', False)
205 self.check_topology(1, 0, 1, 1, 'low', False)
206 self.check_topology(2, 0, 1, 1, 'medium', False)
207 self.check_topology(3, 1, 1, 1, 'high', False)
208 self.check_topology(4, 1, 1, 1, 'medium', False)
209 self.check_topology(5, 2, 1, 1, 'high', True)
cb042c73
PM
210
211
212 def guest_set_dispatching(self, dispatching):
213 exec_command(self,
214 f'echo {dispatching} > /sys/devices/system/cpu/dispatching')
215 self.vm.event_wait('CPU_POLARIZATION_CHANGE', self.event_timeout)
216 exec_command_and_wait_for_pattern(self,
217 'cat /sys/devices/system/cpu/dispatching', dispatching)
218
219
220 def test_polarization(self):
221 """
222 This test verifies that QEMU modifies the entitlement change after
223 several guest polarization change requests.
224
225 :avocado: tags=arch:s390x
226 :avocado: tags=machine:s390-ccw-virtio
227 """
228 self.kernel_init()
229 self.vm.launch()
230 self.wait_until_booted()
231
232 self.system_init()
233 res = self.vm.qmp('query-s390x-cpu-polarization')
234 self.assertEqual(res['return']['polarization'], 'horizontal')
235 self.check_topology(0, 0, 0, 0, 'medium', False)
236
237 self.guest_set_dispatching('1');
238 res = self.vm.qmp('query-s390x-cpu-polarization')
239 self.assertEqual(res['return']['polarization'], 'vertical')
240 self.check_topology(0, 0, 0, 0, 'medium', False)
241
242 self.guest_set_dispatching('0');
243 res = self.vm.qmp('query-s390x-cpu-polarization')
244 self.assertEqual(res['return']['polarization'], 'horizontal')
245 self.check_topology(0, 0, 0, 0, 'medium', False)
16ab722e
PM
246
247
248 def check_polarization(self, polarization):
249 #We need to wait for the change to have been propagated to the kernel
250 exec_command_and_wait_for_pattern(self,
251 "\n".join([
252 "timeout 1 sh -c 'while true",
253 'do',
254 ' syspath="/sys/devices/system/cpu/cpu0/polarization"',
255 ' polarization="$(cat "$syspath")" || exit',
256 f' if [ "$polarization" = "{polarization}" ]; then',
257 ' exit 0',
258 ' fi',
259 ' sleep 0.01',
260 #searched for strings mustn't show up in command, '' to obfuscate
261 "done' && echo succ''ess || echo fail''ure",
262 ]),
263 "success", "failure")
264
265
266 def test_entitlement(self):
267 """
268 This test verifies that QEMU modifies the entitlement
269 after a guest request and that the guest sees the change.
270
271 :avocado: tags=arch:s390x
272 :avocado: tags=machine:s390-ccw-virtio
273 """
274 self.kernel_init()
275 self.vm.launch()
276 self.wait_until_booted()
277
278 self.system_init()
279
280 self.check_polarization('horizontal')
281 self.check_topology(0, 0, 0, 0, 'medium', False)
282
283 self.guest_set_dispatching('1')
284 self.check_polarization('vertical:medium')
285 self.check_topology(0, 0, 0, 0, 'medium', False)
286
287 res = self.vm.qmp('set-cpu-topology',
288 {'core-id': 0, 'entitlement': 'low'})
289 self.assertEqual(res['return'], {})
290 self.check_polarization('vertical:low')
291 self.check_topology(0, 0, 0, 0, 'low', False)
292
293 res = self.vm.qmp('set-cpu-topology',
294 {'core-id': 0, 'entitlement': 'medium'})
295 self.assertEqual(res['return'], {})
296 self.check_polarization('vertical:medium')
297 self.check_topology(0, 0, 0, 0, 'medium', False)
298
299 res = self.vm.qmp('set-cpu-topology',
300 {'core-id': 0, 'entitlement': 'high'})
301 self.assertEqual(res['return'], {})
302 self.check_polarization('vertical:high')
303 self.check_topology(0, 0, 0, 0, 'high', False)
304
305 self.guest_set_dispatching('0');
306 self.check_polarization("horizontal")
307 self.check_topology(0, 0, 0, 0, 'high', False)
471676bf
PM
308
309
310 def test_dedicated(self):
311 """
312 This test verifies that QEMU adjusts the entitlement correctly when a
313 CPU is made dedicated.
314 QEMU retains the entitlement value when horizontal polarization is in effect.
315 For the guest, the field shows the effective value of the entitlement.
316
317 :avocado: tags=arch:s390x
318 :avocado: tags=machine:s390-ccw-virtio
319 """
320 self.kernel_init()
321 self.vm.launch()
322 self.wait_until_booted()
323
324 self.system_init()
325
326 self.check_polarization("horizontal")
327
328 res = self.vm.qmp('set-cpu-topology',
329 {'core-id': 0, 'dedicated': True})
330 self.assertEqual(res['return'], {})
331 self.check_topology(0, 0, 0, 0, 'high', True)
332 self.check_polarization("horizontal")
333
334 self.guest_set_dispatching('1');
335 self.check_topology(0, 0, 0, 0, 'high', True)
336 self.check_polarization("vertical:high")
337
338 self.guest_set_dispatching('0');
339 self.check_topology(0, 0, 0, 0, 'high', True)
340 self.check_polarization("horizontal")
944e0300
PM
341
342
343 def test_socket_full(self):
344 """
345 This test verifies that QEMU does not accept to overload a socket.
346 The socket-id 0 on book-id 0 already contains CPUs 0 and 1 and can
347 not accept any new CPU while socket-id 0 on book-id 1 is free.
348
349 :avocado: tags=arch:s390x
350 :avocado: tags=machine:s390-ccw-virtio
351 """
352 self.kernel_init()
353 self.vm.add_args('-smp',
354 '3,drawers=2,books=2,sockets=3,cores=2,maxcpus=24')
355 self.vm.launch()
356 self.wait_until_booted()
357
358 self.system_init()
359
360 res = self.vm.qmp('set-cpu-topology',
361 {'core-id': 2, 'socket-id': 0, 'book-id': 0})
362 self.assertEqual(res['error']['class'], 'GenericError')
363
364 res = self.vm.qmp('set-cpu-topology',
365 {'core-id': 2, 'socket-id': 0, 'book-id': 1})
366 self.assertEqual(res['return'], {})
22ac7809
PM
367
368 def test_dedicated_error(self):
369 """
370 This test verifies that QEMU refuses to lower the entitlement
371 of a dedicated CPU
372
373 :avocado: tags=arch:s390x
374 :avocado: tags=machine:s390-ccw-virtio
375 """
376 self.kernel_init()
377 self.vm.launch()
378 self.wait_until_booted()
379
380 self.system_init()
381
382 res = self.vm.qmp('set-cpu-topology',
383 {'core-id': 0, 'dedicated': True})
384 self.assertEqual(res['return'], {})
385
386 self.check_topology(0, 0, 0, 0, 'high', True)
387
388 self.guest_set_dispatching('1');
389
390 self.check_topology(0, 0, 0, 0, 'high', True)
391
392 res = self.vm.qmp('set-cpu-topology',
393 {'core-id': 0, 'entitlement': 'low', 'dedicated': True})
394 self.assertEqual(res['error']['class'], 'GenericError')
395
396 res = self.vm.qmp('set-cpu-topology',
397 {'core-id': 0, 'entitlement': 'low'})
398 self.assertEqual(res['error']['class'], 'GenericError')
399
400 res = self.vm.qmp('set-cpu-topology',
401 {'core-id': 0, 'entitlement': 'medium', 'dedicated': True})
402 self.assertEqual(res['error']['class'], 'GenericError')
403
404 res = self.vm.qmp('set-cpu-topology',
405 {'core-id': 0, 'entitlement': 'medium'})
406 self.assertEqual(res['error']['class'], 'GenericError')
407
408 res = self.vm.qmp('set-cpu-topology',
409 {'core-id': 0, 'entitlement': 'low', 'dedicated': False})
410 self.assertEqual(res['return'], {})
411
412 res = self.vm.qmp('set-cpu-topology',
413 {'core-id': 0, 'entitlement': 'medium', 'dedicated': False})
414 self.assertEqual(res['return'], {})
219922ef
PM
415
416 def test_move_error(self):
417 """
418 This test verifies that QEMU refuses to move a CPU to an
419 nonexistent location
420
421 :avocado: tags=arch:s390x
422 :avocado: tags=machine:s390-ccw-virtio
423 """
424 self.kernel_init()
425 self.vm.launch()
426 self.wait_until_booted()
427
428 self.system_init()
429
430 res = self.vm.qmp('set-cpu-topology', {'core-id': 0, 'drawer-id': 1})
431 self.assertEqual(res['error']['class'], 'GenericError')
432
433 res = self.vm.qmp('set-cpu-topology', {'core-id': 0, 'book-id': 1})
434 self.assertEqual(res['error']['class'], 'GenericError')
435
436 res = self.vm.qmp('set-cpu-topology', {'core-id': 0, 'socket-id': 1})
437 self.assertEqual(res['error']['class'], 'GenericError')
438
439 self.check_topology(0, 0, 0, 0, 'medium', False)