Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM/ARM64: KVM: Emulate PSCI v0.2 CPU_SUSPEND

This patch adds emulation of PSCI v0.2 CPU_SUSPEND function call for
KVM ARM/ARM64. This is a CPU-level function call which can suspend
current CPU or current CPU cluster. We don't have VCPU clusters in
KVM so we only suspend the current VCPU.

The CPU_SUSPEND emulation is not tested much because currently there
is no CPUIDLE driver in Linux kernel that uses PSCI CPU_SUSPEND. The
PSCI CPU_SUSPEND implementation in ARM64 kernel was tested using a
Simple CPUIDLE driver which is not published due to unstable DT-bindings
for PSCI.
(For more info, http://lwn.net/Articles/574950/)

For simplicity, we implement CPU_SUSPEND emulation similar to WFI
(Wait-for-interrupt) emulation and we also treat power-down request
to be same as stand-by request. This is consistent with section
5.4.1 and section 5.4.2 of PSCI v0.2 specification.

Signed-off-by: Anup Patel <anup.patel@linaro.org>
Signed-off-by: Pranavkumar Sawargaonkar <pranavkumar@linaro.org>
Acked-by: Christoffer Dall <christoffer.dall@linaro.org>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>

authored by

Anup Patel and committed by
Christoffer Dall
b376d02b aa8aeefe

+24 -4
+24 -4
arch/arm/kvm/psci.c
··· 37 37 return 0; 38 38 } 39 39 40 + static unsigned long kvm_psci_vcpu_suspend(struct kvm_vcpu *vcpu) 41 + { 42 + /* 43 + * NOTE: For simplicity, we make VCPU suspend emulation to be 44 + * same-as WFI (Wait-for-interrupt) emulation. 45 + * 46 + * This means for KVM the wakeup events are interrupts and 47 + * this is consistent with intended use of StateID as described 48 + * in section 5.4.1 of PSCI v0.2 specification (ARM DEN 0022A). 49 + * 50 + * Further, we also treat power-down request to be same as 51 + * stand-by request as-per section 5.4.2 clause 3 of PSCI v0.2 52 + * specification (ARM DEN 0022A). This means all suspend states 53 + * for KVM will preserve the register state. 54 + */ 55 + kvm_vcpu_block(vcpu); 56 + 57 + return PSCI_RET_SUCCESS; 58 + } 59 + 40 60 static void kvm_psci_vcpu_off(struct kvm_vcpu *vcpu) 41 61 { 42 62 vcpu->arch.pause = true; ··· 203 183 */ 204 184 val = 2; 205 185 break; 186 + case PSCI_0_2_FN_CPU_SUSPEND: 187 + case PSCI_0_2_FN64_CPU_SUSPEND: 188 + val = kvm_psci_vcpu_suspend(vcpu); 189 + break; 206 190 case PSCI_0_2_FN_CPU_OFF: 207 191 kvm_psci_vcpu_off(vcpu); 208 192 val = PSCI_RET_SUCCESS; ··· 258 234 */ 259 235 val = PSCI_RET_INTERNAL_FAILURE; 260 236 ret = 0; 261 - break; 262 - case PSCI_0_2_FN_CPU_SUSPEND: 263 - case PSCI_0_2_FN64_CPU_SUSPEND: 264 - val = PSCI_RET_NOT_SUPPORTED; 265 237 break; 266 238 default: 267 239 return -EINVAL;