Skip to content

Commit

Permalink
KVM: use smp_send_reschedule in kvm_vcpu_kick
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Marcelo Tosatti authored and Avi Kivity committed Jun 10, 2009
1 parent d149c73 commit 32f8840
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 40 deletions.
3 changes: 3 additions & 0 deletions arch/ia64/kernel/irq_ia64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
22 changes: 8 additions & 14 deletions arch/ia64/kvm/kvm-ia64.c
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
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)
Expand All @@ -685,7 +685,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
kvm_vcpu_post_transition(vcpu);

vcpu->arch.launched = 1;
vcpu->guest_mode = 0;
set_bit(KVM_REQ_KICK, &vcpu->requests);
local_irq_enable();

/*
Expand Down Expand Up @@ -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();
}

Expand Down
3 changes: 3 additions & 0 deletions arch/x86/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
36 changes: 11 additions & 25 deletions arch/x86/kvm/x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -3230,20 +3230,16 @@ 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();
r = 1;
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
Expand Down Expand Up @@ -3288,7 +3284,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;
Expand Down Expand Up @@ -4571,30 +4567,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();
}

Expand Down
2 changes: 1 addition & 1 deletion include/linux/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 32f8840

Please sign in to comment.