]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/arm/kvm/arm.c
Merge remote-tracking branch 'y2038/y2038'
[karo-tx-linux.git] / arch / arm / kvm / arm.c
index 78b286994577183b8d9ef415ae3ba5f6a41113c4..eab83b2435b8b8ed2abc6342e3a22e19da80d623 100644 (file)
@@ -271,6 +271,16 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
        return kvm_timer_should_fire(vcpu);
 }
 
+void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu)
+{
+       kvm_timer_schedule(vcpu);
+}
+
+void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu)
+{
+       kvm_timer_unschedule(vcpu);
+}
+
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
        /* Force users to call KVM_ARM_VCPU_INIT */
@@ -308,7 +318,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
 int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
                                    struct kvm_mp_state *mp_state)
 {
-       if (vcpu->arch.pause)
+       if (vcpu->arch.power_off)
                mp_state->mp_state = KVM_MP_STATE_STOPPED;
        else
                mp_state->mp_state = KVM_MP_STATE_RUNNABLE;
@@ -321,10 +331,10 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
 {
        switch (mp_state->mp_state) {
        case KVM_MP_STATE_RUNNABLE:
-               vcpu->arch.pause = false;
+               vcpu->arch.power_off = false;
                break;
        case KVM_MP_STATE_STOPPED:
-               vcpu->arch.pause = true;
+               vcpu->arch.power_off = true;
                break;
        default:
                return -EINVAL;
@@ -342,7 +352,8 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
  */
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
-       return !!v->arch.irq_lines || kvm_vgic_vcpu_pending_irq(v);
+       return ((!!v->arch.irq_lines || kvm_vgic_vcpu_pending_irq(v))
+               && !v->arch.power_off && !v->arch.pause);
 }
 
 /* Just ensure a guest exit from a particular CPU */
@@ -468,11 +479,38 @@ bool kvm_arch_intc_initialized(struct kvm *kvm)
        return vgic_initialized(kvm);
 }
 
-static void vcpu_pause(struct kvm_vcpu *vcpu)
+static void kvm_arm_halt_guest(struct kvm *kvm) __maybe_unused;
+static void kvm_arm_resume_guest(struct kvm *kvm) __maybe_unused;
+
+static void kvm_arm_halt_guest(struct kvm *kvm)
+{
+       int i;
+       struct kvm_vcpu *vcpu;
+
+       kvm_for_each_vcpu(i, vcpu, kvm)
+               vcpu->arch.pause = true;
+       force_vm_exit(cpu_all_mask);
+}
+
+static void kvm_arm_resume_guest(struct kvm *kvm)
+{
+       int i;
+       struct kvm_vcpu *vcpu;
+
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               wait_queue_head_t *wq = kvm_arch_vcpu_wq(vcpu);
+
+               vcpu->arch.pause = false;
+               wake_up_interruptible(wq);
+       }
+}
+
+static void vcpu_sleep(struct kvm_vcpu *vcpu)
 {
        wait_queue_head_t *wq = kvm_arch_vcpu_wq(vcpu);
 
-       wait_event_interruptible(*wq, !vcpu->arch.pause);
+       wait_event_interruptible(*wq, ((!vcpu->arch.power_off) &&
+                                      (!vcpu->arch.pause)));
 }
 
 static int kvm_vcpu_initialized(struct kvm_vcpu *vcpu)
@@ -522,8 +560,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
                update_vttbr(vcpu->kvm);
 
-               if (vcpu->arch.pause)
-                       vcpu_pause(vcpu);
+               if (vcpu->arch.power_off || vcpu->arch.pause)
+                       vcpu_sleep(vcpu);
 
                /*
                 * Disarming the background timer must be done in a
@@ -549,11 +587,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                        run->exit_reason = KVM_EXIT_INTR;
                }
 
-               if (ret <= 0 || need_new_vmid_gen(vcpu->kvm)) {
+               if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
+                       vcpu->arch.power_off || vcpu->arch.pause) {
                        local_irq_enable();
+                       kvm_timer_sync_hwstate(vcpu);
                        kvm_vgic_sync_hwstate(vcpu);
                        preempt_enable();
-                       kvm_timer_sync_hwstate(vcpu);
                        continue;
                }
 
@@ -596,14 +635,19 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
                 * guest time.
                 */
                kvm_guest_exit();
-               trace_kvm_exit(kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
+               trace_kvm_exit(ret, kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
+
+               /*
+                * We must sync the timer state before the vgic state so that
+                * the vgic can properly sample the updated state of the
+                * interrupt line.
+                */
+               kvm_timer_sync_hwstate(vcpu);
 
                kvm_vgic_sync_hwstate(vcpu);
 
                preempt_enable();
 
-               kvm_timer_sync_hwstate(vcpu);
-
                ret = handle_exit(vcpu, run, ret);
        }
 
@@ -765,12 +809,12 @@ static int kvm_arch_vcpu_ioctl_vcpu_init(struct kvm_vcpu *vcpu,
        vcpu_reset_hcr(vcpu);
 
        /*
-        * Handle the "start in power-off" case by marking the VCPU as paused.
+        * Handle the "start in power-off" case.
         */
        if (test_bit(KVM_ARM_VCPU_POWER_OFF, vcpu->arch.features))
-               vcpu->arch.pause = true;
+               vcpu->arch.power_off = true;
        else
-               vcpu->arch.pause = false;
+               vcpu->arch.power_off = false;
 
        return 0;
 }