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