| From dcbb466353d8053369a280a000e0774d51dfe222 Mon Sep 17 00:00:00 2001 |
| From: Jan Kiszka <jan.kiszka@siemens.com> |
| Date: Wed, 24 Feb 2010 10:41:58 +0100 |
| Subject: [PATCH] KVM: x86: Kick VCPU outside PIC lock again |
| |
| commit 8452259b8aefef73981b2ffbc23d5245d19bd140 in tip. |
| |
| This restores the deferred VCPU kicking before 956f97cf. We need this |
| over -rt as wake_up* requires non-atomic context in this configuration. |
| |
| Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> |
| Cc: Avi Kivity <avi@redhat.com> |
| Cc: Gleb Natapov <gleb@redhat.com> |
| LKML-Reference: <4B84F466.2080009@siemens.com> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c |
| index 07771da..ca426bd 100644 |
| --- a/arch/x86/kvm/i8259.c |
| +++ b/arch/x86/kvm/i8259.c |
| @@ -32,6 +32,29 @@ |
| #include <linux/kvm_host.h> |
| #include "trace.h" |
| |
| +static void pic_lock(struct kvm_pic *s) |
| + __acquires(&s->lock) |
| +{ |
| + raw_spin_lock(&s->lock); |
| +} |
| + |
| +static void pic_unlock(struct kvm_pic *s) |
| + __releases(&s->lock) |
| +{ |
| + bool wakeup = s->wakeup_needed; |
| + struct kvm_vcpu *vcpu; |
| + |
| + s->wakeup_needed = false; |
| + |
| + raw_spin_unlock(&s->lock); |
| + |
| + if (wakeup) { |
| + vcpu = s->kvm->bsp_vcpu; |
| + if (vcpu) |
| + kvm_vcpu_kick(vcpu); |
| + } |
| +} |
| + |
| static void pic_clear_isr(struct kvm_kpic_state *s, int irq) |
| { |
| s->isr &= ~(1 << irq); |
| @@ -44,19 +67,19 @@ static void pic_clear_isr(struct kvm_kpic_state *s, int irq) |
| * Other interrupt may be delivered to PIC while lock is dropped but |
| * it should be safe since PIC state is already updated at this stage. |
| */ |
| - raw_spin_unlock(&s->pics_state->lock); |
| + pic_unlock(s->pics_state); |
| kvm_notify_acked_irq(s->pics_state->kvm, SELECT_PIC(irq), irq); |
| - raw_spin_lock(&s->pics_state->lock); |
| + pic_lock(s->pics_state); |
| } |
| |
| void kvm_pic_clear_isr_ack(struct kvm *kvm) |
| { |
| struct kvm_pic *s = pic_irqchip(kvm); |
| |
| - raw_spin_lock(&s->lock); |
| + pic_lock(s); |
| s->pics[0].isr_ack = 0xff; |
| s->pics[1].isr_ack = 0xff; |
| - raw_spin_unlock(&s->lock); |
| + pic_unlock(s); |
| } |
| |
| /* |
| @@ -157,9 +180,9 @@ static void pic_update_irq(struct kvm_pic *s) |
| |
| void kvm_pic_update_irq(struct kvm_pic *s) |
| { |
| - raw_spin_lock(&s->lock); |
| + pic_lock(s); |
| pic_update_irq(s); |
| - raw_spin_unlock(&s->lock); |
| + pic_unlock(s); |
| } |
| |
| int kvm_pic_set_irq(void *opaque, int irq, int level) |
| @@ -167,14 +190,14 @@ int kvm_pic_set_irq(void *opaque, int irq, int level) |
| struct kvm_pic *s = opaque; |
| int ret = -1; |
| |
| - raw_spin_lock(&s->lock); |
| + pic_lock(s); |
| if (irq >= 0 && irq < PIC_NUM_PINS) { |
| ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, level); |
| pic_update_irq(s); |
| trace_kvm_pic_set_irq(irq >> 3, irq & 7, s->pics[irq >> 3].elcr, |
| s->pics[irq >> 3].imr, ret == 0); |
| } |
| - raw_spin_unlock(&s->lock); |
| + pic_unlock(s); |
| |
| return ret; |
| } |
| @@ -204,7 +227,7 @@ int kvm_pic_read_irq(struct kvm *kvm) |
| int irq, irq2, intno; |
| struct kvm_pic *s = pic_irqchip(kvm); |
| |
| - raw_spin_lock(&s->lock); |
| + pic_lock(s); |
| irq = pic_get_irq(&s->pics[0]); |
| if (irq >= 0) { |
| pic_intack(&s->pics[0], irq); |
| @@ -229,7 +252,7 @@ int kvm_pic_read_irq(struct kvm *kvm) |
| intno = s->pics[0].irq_base + irq; |
| } |
| pic_update_irq(s); |
| - raw_spin_unlock(&s->lock); |
| + pic_unlock(s); |
| |
| return intno; |
| } |
| @@ -443,7 +466,7 @@ static int picdev_write(struct kvm_io_device *this, |
| printk(KERN_ERR "PIC: non byte write\n"); |
| return 0; |
| } |
| - raw_spin_lock(&s->lock); |
| + pic_lock(s); |
| switch (addr) { |
| case 0x20: |
| case 0x21: |
| @@ -456,7 +479,7 @@ static int picdev_write(struct kvm_io_device *this, |
| elcr_ioport_write(&s->pics[addr & 1], addr, data); |
| break; |
| } |
| - raw_spin_unlock(&s->lock); |
| + pic_unlock(s); |
| return 0; |
| } |
| |
| @@ -473,7 +496,7 @@ static int picdev_read(struct kvm_io_device *this, |
| printk(KERN_ERR "PIC: non byte read\n"); |
| return 0; |
| } |
| - raw_spin_lock(&s->lock); |
| + pic_lock(s); |
| switch (addr) { |
| case 0x20: |
| case 0x21: |
| @@ -487,7 +510,7 @@ static int picdev_read(struct kvm_io_device *this, |
| break; |
| } |
| *(unsigned char *)val = data; |
| - raw_spin_unlock(&s->lock); |
| + pic_unlock(s); |
| return 0; |
| } |
| |
| @@ -504,7 +527,7 @@ static void pic_irq_request(void *opaque, int level) |
| s->output = level; |
| if (vcpu && level && (s->pics[0].isr_ack & (1 << irq))) { |
| s->pics[0].isr_ack &= ~(1 << irq); |
| - kvm_vcpu_kick(vcpu); |
| + s->wakeup_needed = true; |
| } |
| } |
| |
| diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h |
| index 34b1591..cd1f362 100644 |
| --- a/arch/x86/kvm/irq.h |
| +++ b/arch/x86/kvm/irq.h |
| @@ -63,6 +63,7 @@ struct kvm_kpic_state { |
| |
| struct kvm_pic { |
| raw_spinlock_t lock; |
| + bool wakeup_needed; |
| unsigned pending_acks; |
| struct kvm *kvm; |
| struct kvm_kpic_state pics[2]; /* 0 is master pic, 1 is slave pic */ |
| -- |
| 1.7.1.1 |
| |