]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
KVM: use smp_send_reschedule in kvm_vcpu_kick
authorMarcelo Tosatti <mtosatti@redhat.com>
Thu, 7 May 2009 20:55:12 +0000 (17:55 -0300)
committerAvi Kivity <avi@redhat.com>
Sun, 10 May 2009 16:32:23 +0000 (19:32 +0300)
KVM uses a function call IPI to cause the exit of a guest running on a
physical cpu. For virtual interrupt notification there is no need to
wait on IPI receival, or to execute any function.

This is exactly what the reschedule IPI does, without the overhead
of function IPI. So use it instead of smp_call_function_single in
kvm_vcpu_kick.

Also change the "guest_mode" variable to a bit in vcpu->requests, and
use that to collapse multiple IPI's that would be issued between the
first one and zeroing of guest mode.

This allows kvm_vcpu_kick to called with interrupts disabled.

Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
arch/ia64/kernel/irq_ia64.c
arch/ia64/kvm/kvm-ia64.c
arch/x86/kernel/smp.c
arch/x86/kvm/x86.c
include/linux/kvm_host.h

index acc4d19ae62ad17fd956f914a0829a6bda3b8589..b448197728be5cc22b91fd92f2c49d2cee0f455f 100644 (file)
@@ -610,6 +610,9 @@ static struct irqaction ipi_irqaction = {
        .name =         "IPI"
 };
 
+/*
+ * KVM uses this interrupt to force a cpu out of guest mode
+ */
 static struct irqaction resched_irqaction = {
        .handler =      dummy_handler,
        .flags =        IRQF_DISABLED,
index be4413e1f43ff335bd9c6a8d7941da58208bdbf8..80c57b0a21c479ee593fb095bc8429089eced2f5 100644 (file)
@@ -668,7 +668,7 @@ again:
        host_ctx = kvm_get_host_context(vcpu);
        guest_ctx = kvm_get_guest_context(vcpu);
 
-       vcpu->guest_mode = 1;
+       clear_bit(KVM_REQ_KICK, &vcpu->requests);
 
        r = kvm_vcpu_pre_transition(vcpu);
        if (r < 0)
@@ -685,7 +685,7 @@ again:
        kvm_vcpu_post_transition(vcpu);
 
        vcpu->arch.launched = 1;
-       vcpu->guest_mode = 0;
+       set_bit(KVM_REQ_KICK, &vcpu->requests);
        local_irq_enable();
 
        /*
@@ -1879,24 +1879,18 @@ void kvm_arch_hardware_unsetup(void)
 {
 }
 
-static void vcpu_kick_intr(void *info)
-{
-#ifdef DEBUG
-       struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info;
-       printk(KERN_DEBUG"vcpu_kick_intr %p \n", vcpu);
-#endif
-}
-
 void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
 {
-       int ipi_pcpu = vcpu->cpu;
-       int cpu = get_cpu();
+       int me;
+       int cpu = vcpu->cpu;
 
        if (waitqueue_active(&vcpu->wq))
                wake_up_interruptible(&vcpu->wq);
 
-       if (vcpu->guest_mode && cpu != ipi_pcpu)
-               smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0);
+       me = get_cpu();
+       if (cpu != me && (unsigned) cpu < nr_cpu_ids && cpu_online(cpu))
+               if (!test_and_set_bit(KVM_REQ_KICK, &vcpu->requests))
+                       smp_send_reschedule(cpu);
        put_cpu();
 }
 
index 13f33ea8ccaaf1ae8e23cc2a39f57d84d6d3c910..3b2e55e8ad2b8c2906e01aed063d0db9faee2ef5 100644 (file)
@@ -172,6 +172,9 @@ void smp_reschedule_interrupt(struct pt_regs *regs)
 {
        ack_APIC_irq();
        inc_irq_stat(irq_resched_count);
+       /*
+        * KVM uses this interrupt to force a cpu out of guest mode
+        */
 }
 
 void smp_call_function_interrupt(struct pt_regs *regs)
index 23c0d56bec792ef4655722ea5b4953ed0ba52249..c6d3ff3f7f97570a08129368838b47507f9f787a 100644 (file)
@@ -3226,6 +3226,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
 
        local_irq_disable();
 
+       clear_bit(KVM_REQ_KICK, &vcpu->requests);
+       smp_mb__after_clear_bit();
+
        if (vcpu->requests || need_resched() || signal_pending(current)) {
                local_irq_enable();
                preempt_enable();
@@ -3233,13 +3236,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
                goto out;
        }
 
-       vcpu->guest_mode = 1;
-       /*
-        * Make sure that guest_mode assignment won't happen after
-        * testing the pending IRQ vector bitmap.
-        */
-       smp_wmb();
-
        if (vcpu->arch.exception.pending)
                __queue_exception(vcpu);
        else
@@ -3284,7 +3280,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
        set_debugreg(vcpu->arch.host_dr6, 6);
        set_debugreg(vcpu->arch.host_dr7, 7);
 
-       vcpu->guest_mode = 0;
+       set_bit(KVM_REQ_KICK, &vcpu->requests);
        local_irq_enable();
 
        ++vcpu->stat.exits;
@@ -4567,30 +4563,20 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
               || vcpu->arch.nmi_pending;
 }
 
-static void vcpu_kick_intr(void *info)
-{
-#ifdef DEBUG
-       struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info;
-       printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu);
-#endif
-}
-
 void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
 {
-       int ipi_pcpu = vcpu->cpu;
-       int cpu;
+       int me;
+       int cpu = vcpu->cpu;
 
        if (waitqueue_active(&vcpu->wq)) {
                wake_up_interruptible(&vcpu->wq);
                ++vcpu->stat.halt_wakeup;
        }
-       /*
-        * We may be called synchronously with irqs disabled in guest mode,
-        * So need not to call smp_call_function_single() in that case.
-        */
-       cpu = get_cpu();
-       if (vcpu->guest_mode && vcpu->cpu != cpu)
-               smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0);
+
+       me = get_cpu();
+       if (cpu != me && (unsigned)cpu < nr_cpu_ids && cpu_online(cpu))
+               if (!test_and_set_bit(KVM_REQ_KICK, &vcpu->requests))
+                       smp_send_reschedule(cpu);
        put_cpu();
 }
 
index 095ebb6393ffe106facb2a682a6e79c39327c59a..db847ffdd17f699bbc73ad6c0a50f8e913747d59 100644 (file)
@@ -38,6 +38,7 @@
 #define KVM_REQ_UNHALT             6
 #define KVM_REQ_MMU_SYNC           7
 #define KVM_REQ_KVMCLOCK_UPDATE    8
+#define KVM_REQ_KICK               9
 
 #define KVM_USERSPACE_IRQ_SOURCE_ID    0
 
@@ -72,7 +73,6 @@ struct kvm_vcpu {
        struct mutex mutex;
        int   cpu;
        struct kvm_run *run;
-       int guest_mode;
        unsigned long requests;
        unsigned long guest_debug;
        int fpu_active;