aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2009-05-07 16:55:12 -0400
committerAvi Kivity <avi@redhat.com>2009-06-10 04:48:53 -0400
commit32f8840064d88cc3f6e85203aec7b6b57bebcb97 (patch)
tree29a42942c71e9bdf1f3e71aa1674a29aa13ce320
parentd149c731e4f71982247a14409951259f36271dd7 (diff)
KVM: use smp_send_reschedule in kvm_vcpu_kick
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>
-rw-r--r--arch/ia64/kernel/irq_ia64.c3
-rw-r--r--arch/ia64/kvm/kvm-ia64.c22
-rw-r--r--arch/x86/kernel/smp.c3
-rw-r--r--arch/x86/kvm/x86.c36
-rw-r--r--include/linux/kvm_host.h2
5 files changed, 26 insertions, 40 deletions
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index acc4d19ae62a..b448197728be 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -610,6 +610,9 @@ static struct irqaction ipi_irqaction = {
610 .name = "IPI" 610 .name = "IPI"
611}; 611};
612 612
613/*
614 * KVM uses this interrupt to force a cpu out of guest mode
615 */
613static struct irqaction resched_irqaction = { 616static struct irqaction resched_irqaction = {
614 .handler = dummy_handler, 617 .handler = dummy_handler,
615 .flags = IRQF_DISABLED, 618 .flags = IRQF_DISABLED,
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index be4413e1f43f..80c57b0a21c4 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -668,7 +668,7 @@ again:
668 host_ctx = kvm_get_host_context(vcpu); 668 host_ctx = kvm_get_host_context(vcpu);
669 guest_ctx = kvm_get_guest_context(vcpu); 669 guest_ctx = kvm_get_guest_context(vcpu);
670 670
671 vcpu->guest_mode = 1; 671 clear_bit(KVM_REQ_KICK, &vcpu->requests);
672 672
673 r = kvm_vcpu_pre_transition(vcpu); 673 r = kvm_vcpu_pre_transition(vcpu);
674 if (r < 0) 674 if (r < 0)
@@ -685,7 +685,7 @@ again:
685 kvm_vcpu_post_transition(vcpu); 685 kvm_vcpu_post_transition(vcpu);
686 686
687 vcpu->arch.launched = 1; 687 vcpu->arch.launched = 1;
688 vcpu->guest_mode = 0; 688 set_bit(KVM_REQ_KICK, &vcpu->requests);
689 local_irq_enable(); 689 local_irq_enable();
690 690
691 /* 691 /*
@@ -1879,24 +1879,18 @@ void kvm_arch_hardware_unsetup(void)
1879{ 1879{
1880} 1880}
1881 1881
1882static void vcpu_kick_intr(void *info)
1883{
1884#ifdef DEBUG
1885 struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info;
1886 printk(KERN_DEBUG"vcpu_kick_intr %p \n", vcpu);
1887#endif
1888}
1889
1890void kvm_vcpu_kick(struct kvm_vcpu *vcpu) 1882void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
1891{ 1883{
1892 int ipi_pcpu = vcpu->cpu; 1884 int me;
1893 int cpu = get_cpu(); 1885 int cpu = vcpu->cpu;
1894 1886
1895 if (waitqueue_active(&vcpu->wq)) 1887 if (waitqueue_active(&vcpu->wq))
1896 wake_up_interruptible(&vcpu->wq); 1888 wake_up_interruptible(&vcpu->wq);
1897 1889
1898 if (vcpu->guest_mode && cpu != ipi_pcpu) 1890 me = get_cpu();
1899 smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0); 1891 if (cpu != me && (unsigned) cpu < nr_cpu_ids && cpu_online(cpu))
1892 if (!test_and_set_bit(KVM_REQ_KICK, &vcpu->requests))
1893 smp_send_reschedule(cpu);
1900 put_cpu(); 1894 put_cpu();
1901} 1895}
1902 1896
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index 13f33ea8ccaa..3b2e55e8ad2b 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -172,6 +172,9 @@ void smp_reschedule_interrupt(struct pt_regs *regs)
172{ 172{
173 ack_APIC_irq(); 173 ack_APIC_irq();
174 inc_irq_stat(irq_resched_count); 174 inc_irq_stat(irq_resched_count);
175 /*
176 * KVM uses this interrupt to force a cpu out of guest mode
177 */
175} 178}
176 179
177void smp_call_function_interrupt(struct pt_regs *regs) 180void smp_call_function_interrupt(struct pt_regs *regs)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 75927700a26d..3c4c327490af 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3230,6 +3230,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
3230 3230
3231 local_irq_disable(); 3231 local_irq_disable();
3232 3232
3233 clear_bit(KVM_REQ_KICK, &vcpu->requests);
3234 smp_mb__after_clear_bit();
3235
3233 if (vcpu->requests || need_resched() || signal_pending(current)) { 3236 if (vcpu->requests || need_resched() || signal_pending(current)) {
3234 local_irq_enable(); 3237 local_irq_enable();
3235 preempt_enable(); 3238 preempt_enable();
@@ -3237,13 +3240,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
3237 goto out; 3240 goto out;
3238 } 3241 }
3239 3242
3240 vcpu->guest_mode = 1;
3241 /*
3242 * Make sure that guest_mode assignment won't happen after
3243 * testing the pending IRQ vector bitmap.
3244 */
3245 smp_wmb();
3246
3247 if (vcpu->arch.exception.pending) 3243 if (vcpu->arch.exception.pending)
3248 __queue_exception(vcpu); 3244 __queue_exception(vcpu);
3249 else 3245 else
@@ -3288,7 +3284,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
3288 set_debugreg(vcpu->arch.host_dr6, 6); 3284 set_debugreg(vcpu->arch.host_dr6, 6);
3289 set_debugreg(vcpu->arch.host_dr7, 7); 3285 set_debugreg(vcpu->arch.host_dr7, 7);
3290 3286
3291 vcpu->guest_mode = 0; 3287 set_bit(KVM_REQ_KICK, &vcpu->requests);
3292 local_irq_enable(); 3288 local_irq_enable();
3293 3289
3294 ++vcpu->stat.exits; 3290 ++vcpu->stat.exits;
@@ -4571,30 +4567,20 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
4571 || vcpu->arch.nmi_pending; 4567 || vcpu->arch.nmi_pending;
4572} 4568}
4573 4569
4574static void vcpu_kick_intr(void *info)
4575{
4576#ifdef DEBUG
4577 struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info;
4578 printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu);
4579#endif
4580}
4581
4582void kvm_vcpu_kick(struct kvm_vcpu *vcpu) 4570void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
4583{ 4571{
4584 int ipi_pcpu = vcpu->cpu; 4572 int me;
4585 int cpu; 4573 int cpu = vcpu->cpu;
4586 4574
4587 if (waitqueue_active(&vcpu->wq)) { 4575 if (waitqueue_active(&vcpu->wq)) {
4588 wake_up_interruptible(&vcpu->wq); 4576 wake_up_interruptible(&vcpu->wq);
4589 ++vcpu->stat.halt_wakeup; 4577 ++vcpu->stat.halt_wakeup;
4590 } 4578 }
4591 /* 4579
4592 * We may be called synchronously with irqs disabled in guest mode, 4580 me = get_cpu();
4593 * So need not to call smp_call_function_single() in that case. 4581 if (cpu != me && (unsigned)cpu < nr_cpu_ids && cpu_online(cpu))
4594 */ 4582 if (!test_and_set_bit(KVM_REQ_KICK, &vcpu->requests))
4595 cpu = get_cpu(); 4583 smp_send_reschedule(cpu);
4596 if (vcpu->guest_mode && vcpu->cpu != cpu)
4597 smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0);
4598 put_cpu(); 4584 put_cpu();
4599} 4585}
4600 4586
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index bdce8e1303c9..161816284192 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -38,6 +38,7 @@
38#define KVM_REQ_UNHALT 6 38#define KVM_REQ_UNHALT 6
39#define KVM_REQ_MMU_SYNC 7 39#define KVM_REQ_MMU_SYNC 7
40#define KVM_REQ_KVMCLOCK_UPDATE 8 40#define KVM_REQ_KVMCLOCK_UPDATE 8
41#define KVM_REQ_KICK 9
41 42
42#define KVM_USERSPACE_IRQ_SOURCE_ID 0 43#define KVM_USERSPACE_IRQ_SOURCE_ID 0
43 44
@@ -72,7 +73,6 @@ struct kvm_vcpu {
72 struct mutex mutex; 73 struct mutex mutex;
73 int cpu; 74 int cpu;
74 struct kvm_run *run; 75 struct kvm_run *run;
75 int guest_mode;
76 unsigned long requests; 76 unsigned long requests;
77 unsigned long guest_debug; 77 unsigned long guest_debug;
78 int fpu_active; 78 int fpu_active;