aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoffer Dall <cdall@cs.columbia.edu>2012-02-23 00:11:57 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2012-07-23 14:08:34 +0100
commit0658df91d21a8c2df82e6ef36177ac8c7007c8b3 (patch)
treeae19e8186e2c0100c2d1751f1a1e5451547b806b
parent2b743ecc7f098c02a8c3fe40dabc8ee173c800df (diff)
downloadlinux-kvm-arm-kvm-a15-v10-stage-v3.5.tar.gz
ARM: KVM: Guest wait-for-interrupts (WFI) supportkvm-a15-v10-stage-v3.5
When the guest executes a WFI instruction the operation is trapped to KVM, which emulates the instruction in software. There is no correlation between a guest executing a WFI instruction and actually putting the hardware into a low-power mode, since a KVM guest is essentially a process and the WFI instruction can be seen as 'sleep' call from this process. Therefore, we flag the VCPU to be in wait_for_interrupts mode and call the main KVM function kvm_vcpu_block() function. This function will put the thread on a wait-queue and call schedule. When an interrupt comes in through KVM_IRQ_LINE (see previous patch) we signal the VCPU thread and unflag the VCPU to no longer wait for interrupts. All calls to kvm_arch_vcpu_ioctl_run() result in a call to kvm_vcpu_block() as long as the VCPU is in wfi-mode. Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
-rw-r--r--arch/arm/kvm/arm.c15
-rw-r--r--arch/arm/kvm/emulate.c12
-rw-r--r--arch/arm/kvm/trace.h16
3 files changed, 42 insertions, 1 deletions
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index b18f68fafa004..f3b206ac1fe55 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -306,9 +306,17 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
return -EINVAL;
}
+/**
+ * kvm_arch_vcpu_runnable - determine if the vcpu can be scheduled
+ * @v: The VCPU pointer
+ *
+ * If the guest CPU is not waiting for interrupts (or waiting and
+ * an interrupt is pending) then it is by definition runnable.
+ */
int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
{
- return 0;
+ return !!v->arch.irq_lines ||
+ !v->arch.wait_for_interrupts;
}
int kvm_arch_vcpu_in_guest_mode(struct kvm_vcpu *v)
@@ -538,6 +546,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
*/
cond_resched();
+ if (vcpu->arch.wait_for_interrupts)
+ kvm_vcpu_block(vcpu);
+
update_vttbr(vcpu->kvm);
/*
@@ -635,6 +646,8 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level)
* trigger a world-switch round on the running physical CPU to set the
* virtual IRQ/FIQ fields in the HCR appropriately.
*/
+ if (irq_level->level)
+ vcpu->arch.wait_for_interrupts = 0;
kvm_vcpu_kick(vcpu);
return 0;
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index 99432d83006fb..564add20f2e02 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -505,9 +505,21 @@ int kvm_handle_cp15_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
return emulate_cp15(vcpu, &params);
}
+/**
+ * kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest
+ * @vcpu: the vcpu pointer
+ * @run: the kvm_run structure pointer
+ *
+ * Simply sets the wait_for_interrupts flag on the vcpu structure, which will
+ * halt execution of world-switches and schedule other host processes until
+ * there is an incoming IRQ or FIQ to the VM.
+ */
int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
+ trace_kvm_wfi(vcpu->arch.regs.pc);
vcpu->stat.wfi_exits++;
+ if (!vcpu->arch.irq_lines)
+ vcpu->arch.wait_for_interrupts = 1;
return 0;
}
diff --git a/arch/arm/kvm/trace.h b/arch/arm/kvm/trace.h
index 325106c8f88c4..28ed1a18b289e 100644
--- a/arch/arm/kvm/trace.h
+++ b/arch/arm/kvm/trace.h
@@ -90,6 +90,22 @@ TRACE_EVENT(kvm_emulate_cp15_imp,
__entry->CRm, __entry->Op2)
);
+TRACE_EVENT(kvm_wfi,
+ TP_PROTO(unsigned long vcpu_pc),
+ TP_ARGS(vcpu_pc),
+
+ TP_STRUCT__entry(
+ __field( unsigned long, vcpu_pc )
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_pc = vcpu_pc;
+ ),
+
+ TP_printk("guest executed wfi at: 0x%08lx", __entry->vcpu_pc)
+);
+
+
#endif /* _TRACE_KVM_H */
#undef TRACE_INCLUDE_PATH