scsi: ufs: mcq: Use active_reqs to check busy in clock scaling
[platform/kernel/linux-rpi.git] / tools / testing / selftests / kvm / aarch64 / psci_test.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * psci_test - Tests relating to KVM's PSCI implementation.
4  *
5  * Copyright (c) 2021 Google LLC.
6  *
7  * This test includes:
8  *  - A regression test for a race between KVM servicing the PSCI CPU_ON call
9  *    and userspace reading the targeted vCPU's registers.
10  *  - A test for KVM's handling of PSCI SYSTEM_SUSPEND and the associated
11  *    KVM_SYSTEM_EVENT_SUSPEND UAPI.
12  */
13
14 #define _GNU_SOURCE
15
16 #include <linux/psci.h>
17
18 #include "kvm_util.h"
19 #include "processor.h"
20 #include "test_util.h"
21
22 #define CPU_ON_ENTRY_ADDR 0xfeedf00dul
23 #define CPU_ON_CONTEXT_ID 0xdeadc0deul
24
25 static uint64_t psci_cpu_on(uint64_t target_cpu, uint64_t entry_addr,
26                             uint64_t context_id)
27 {
28         struct arm_smccc_res res;
29
30         smccc_hvc(PSCI_0_2_FN64_CPU_ON, target_cpu, entry_addr, context_id,
31                   0, 0, 0, 0, &res);
32
33         return res.a0;
34 }
35
36 static uint64_t psci_affinity_info(uint64_t target_affinity,
37                                    uint64_t lowest_affinity_level)
38 {
39         struct arm_smccc_res res;
40
41         smccc_hvc(PSCI_0_2_FN64_AFFINITY_INFO, target_affinity, lowest_affinity_level,
42                   0, 0, 0, 0, 0, &res);
43
44         return res.a0;
45 }
46
47 static uint64_t psci_system_suspend(uint64_t entry_addr, uint64_t context_id)
48 {
49         struct arm_smccc_res res;
50
51         smccc_hvc(PSCI_1_0_FN64_SYSTEM_SUSPEND, entry_addr, context_id,
52                   0, 0, 0, 0, 0, &res);
53
54         return res.a0;
55 }
56
57 static uint64_t psci_features(uint32_t func_id)
58 {
59         struct arm_smccc_res res;
60
61         smccc_hvc(PSCI_1_0_FN_PSCI_FEATURES, func_id, 0, 0, 0, 0, 0, 0, &res);
62
63         return res.a0;
64 }
65
66 static void vcpu_power_off(struct kvm_vcpu *vcpu)
67 {
68         struct kvm_mp_state mp_state = {
69                 .mp_state = KVM_MP_STATE_STOPPED,
70         };
71
72         vcpu_mp_state_set(vcpu, &mp_state);
73 }
74
75 static struct kvm_vm *setup_vm(void *guest_code, struct kvm_vcpu **source,
76                                struct kvm_vcpu **target)
77 {
78         struct kvm_vcpu_init init;
79         struct kvm_vm *vm;
80
81         vm = vm_create(2);
82
83         vm_ioctl(vm, KVM_ARM_PREFERRED_TARGET, &init);
84         init.features[0] |= (1 << KVM_ARM_VCPU_PSCI_0_2);
85
86         *source = aarch64_vcpu_add(vm, 0, &init, guest_code);
87         *target = aarch64_vcpu_add(vm, 1, &init, guest_code);
88
89         return vm;
90 }
91
92 static void enter_guest(struct kvm_vcpu *vcpu)
93 {
94         struct ucall uc;
95
96         vcpu_run(vcpu);
97         if (get_ucall(vcpu, &uc) == UCALL_ABORT)
98                 REPORT_GUEST_ASSERT(uc);
99 }
100
101 static void assert_vcpu_reset(struct kvm_vcpu *vcpu)
102 {
103         uint64_t obs_pc, obs_x0;
104
105         vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.pc), &obs_pc);
106         vcpu_get_reg(vcpu, ARM64_CORE_REG(regs.regs[0]), &obs_x0);
107
108         TEST_ASSERT(obs_pc == CPU_ON_ENTRY_ADDR,
109                     "unexpected target cpu pc: %lx (expected: %lx)",
110                     obs_pc, CPU_ON_ENTRY_ADDR);
111         TEST_ASSERT(obs_x0 == CPU_ON_CONTEXT_ID,
112                     "unexpected target context id: %lx (expected: %lx)",
113                     obs_x0, CPU_ON_CONTEXT_ID);
114 }
115
116 static void guest_test_cpu_on(uint64_t target_cpu)
117 {
118         uint64_t target_state;
119
120         GUEST_ASSERT(!psci_cpu_on(target_cpu, CPU_ON_ENTRY_ADDR, CPU_ON_CONTEXT_ID));
121
122         do {
123                 target_state = psci_affinity_info(target_cpu, 0);
124
125                 GUEST_ASSERT((target_state == PSCI_0_2_AFFINITY_LEVEL_ON) ||
126                              (target_state == PSCI_0_2_AFFINITY_LEVEL_OFF));
127         } while (target_state != PSCI_0_2_AFFINITY_LEVEL_ON);
128
129         GUEST_DONE();
130 }
131
132 static void host_test_cpu_on(void)
133 {
134         struct kvm_vcpu *source, *target;
135         uint64_t target_mpidr;
136         struct kvm_vm *vm;
137         struct ucall uc;
138
139         vm = setup_vm(guest_test_cpu_on, &source, &target);
140
141         /*
142          * make sure the target is already off when executing the test.
143          */
144         vcpu_power_off(target);
145
146         vcpu_get_reg(target, KVM_ARM64_SYS_REG(SYS_MPIDR_EL1), &target_mpidr);
147         vcpu_args_set(source, 1, target_mpidr & MPIDR_HWID_BITMASK);
148         enter_guest(source);
149
150         if (get_ucall(source, &uc) != UCALL_DONE)
151                 TEST_FAIL("Unhandled ucall: %lu", uc.cmd);
152
153         assert_vcpu_reset(target);
154         kvm_vm_free(vm);
155 }
156
157 static void guest_test_system_suspend(void)
158 {
159         uint64_t ret;
160
161         /* assert that SYSTEM_SUSPEND is discoverable */
162         GUEST_ASSERT(!psci_features(PSCI_1_0_FN_SYSTEM_SUSPEND));
163         GUEST_ASSERT(!psci_features(PSCI_1_0_FN64_SYSTEM_SUSPEND));
164
165         ret = psci_system_suspend(CPU_ON_ENTRY_ADDR, CPU_ON_CONTEXT_ID);
166         GUEST_SYNC(ret);
167 }
168
169 static void host_test_system_suspend(void)
170 {
171         struct kvm_vcpu *source, *target;
172         struct kvm_run *run;
173         struct kvm_vm *vm;
174
175         vm = setup_vm(guest_test_system_suspend, &source, &target);
176         vm_enable_cap(vm, KVM_CAP_ARM_SYSTEM_SUSPEND, 0);
177
178         vcpu_power_off(target);
179         run = source->run;
180
181         enter_guest(source);
182
183         TEST_ASSERT(run->exit_reason == KVM_EXIT_SYSTEM_EVENT,
184                     "Unhandled exit reason: %u (%s)",
185                     run->exit_reason, exit_reason_str(run->exit_reason));
186         TEST_ASSERT(run->system_event.type == KVM_SYSTEM_EVENT_SUSPEND,
187                     "Unhandled system event: %u (expected: %u)",
188                     run->system_event.type, KVM_SYSTEM_EVENT_SUSPEND);
189
190         kvm_vm_free(vm);
191 }
192
193 int main(void)
194 {
195         TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_SYSTEM_SUSPEND));
196
197         host_test_cpu_on();
198         host_test_system_suspend();
199         return 0;
200 }