string: factorize skip_spaces and export it to be generally available
[safe/jmp/linux-2.6] / arch / x86 / kvm / i8259.c
index 3aacd33..d057c0c 100644 (file)
 #include <linux/kvm_host.h>
 #include "trace.h"
 
-static void pic_lock(struct kvm_pic *s)
-       __acquires(&s->lock)
-{
-       spin_lock(&s->lock);
-}
-
-static void pic_unlock(struct kvm_pic *s)
-       __releases(&s->lock)
-{
-       spin_unlock(&s->lock);
-}
-
 static void pic_clear_isr(struct kvm_kpic_state *s, int irq)
 {
        s->isr &= ~(1 << irq);
        s->isr_ack |= (1 << irq);
        if (s != &s->pics_state->pics[0])
                irq += 8;
+       /*
+        * We are dropping lock while calling ack notifiers since ack
+        * notifier callbacks for assigned devices call into PIC recursively.
+        * 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.
+        */
+       spin_unlock(&s->pics_state->lock);
        kvm_notify_acked_irq(s->pics_state->kvm, SELECT_PIC(irq), irq);
+       spin_lock(&s->pics_state->lock);
 }
 
 void kvm_pic_clear_isr_ack(struct kvm *kvm)
 {
        struct kvm_pic *s = pic_irqchip(kvm);
-       pic_lock(s);
+       spin_lock(&s->lock);
        s->pics[0].isr_ack = 0xff;
        s->pics[1].isr_ack = 0xff;
-       pic_unlock(s);
+       spin_unlock(&s->lock);
 }
 
 /*
@@ -160,9 +156,9 @@ static void pic_update_irq(struct kvm_pic *s)
 
 void kvm_pic_update_irq(struct kvm_pic *s)
 {
-       pic_lock(s);
+       spin_lock(&s->lock);
        pic_update_irq(s);
-       pic_unlock(s);
+       spin_unlock(&s->lock);
 }
 
 int kvm_pic_set_irq(void *opaque, int irq, int level)
@@ -170,14 +166,14 @@ int kvm_pic_set_irq(void *opaque, int irq, int level)
        struct kvm_pic *s = opaque;
        int ret = -1;
 
-       pic_lock(s);
+       spin_lock(&s->lock);
        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);
        }
-       pic_unlock(s);
+       spin_unlock(&s->lock);
 
        return ret;
 }
@@ -188,16 +184,18 @@ int kvm_pic_set_irq(void *opaque, int irq, int level)
 static inline void pic_intack(struct kvm_kpic_state *s, int irq)
 {
        s->isr |= 1 << irq;
-       if (s->auto_eoi) {
-               if (s->rotate_on_auto_eoi)
-                       s->priority_add = (irq + 1) & 7;
-               pic_clear_isr(s, irq);
-       }
        /*
         * We don't clear a level sensitive interrupt here
         */
        if (!(s->elcr & (1 << irq)))
                s->irr &= ~(1 << irq);
+
+       if (s->auto_eoi) {
+               if (s->rotate_on_auto_eoi)
+                       s->priority_add = (irq + 1) & 7;
+               pic_clear_isr(s, irq);
+       }
+
 }
 
 int kvm_pic_read_irq(struct kvm *kvm)
@@ -205,7 +203,7 @@ int kvm_pic_read_irq(struct kvm *kvm)
        int irq, irq2, intno;
        struct kvm_pic *s = pic_irqchip(kvm);
 
-       pic_lock(s);
+       spin_lock(&s->lock);
        irq = pic_get_irq(&s->pics[0]);
        if (irq >= 0) {
                pic_intack(&s->pics[0], irq);
@@ -230,29 +228,18 @@ int kvm_pic_read_irq(struct kvm *kvm)
                intno = s->pics[0].irq_base + irq;
        }
        pic_update_irq(s);
-       pic_unlock(s);
+       spin_unlock(&s->lock);
 
        return intno;
 }
 
 void kvm_pic_reset(struct kvm_kpic_state *s)
 {
-       int irq, irqbase, n;
+       int irq;
        struct kvm *kvm = s->pics_state->irq_request_opaque;
        struct kvm_vcpu *vcpu0 = kvm->bsp_vcpu;
+       u8 irr = s->irr, isr = s->imr;
 
-       if (s == &s->pics_state->pics[0])
-               irqbase = 0;
-       else
-               irqbase = 8;
-
-       for (irq = 0; irq < PIC_NUM_PINS/2; irq++) {
-               if (vcpu0 && kvm_apic_accept_pic_intr(vcpu0))
-                       if (s->irr & (1 << irq) || s->isr & (1 << irq)) {
-                               n = irq + irqbase;
-                               kvm_notify_acked_irq(kvm, SELECT_PIC(n), n);
-                       }
-       }
        s->last_irr = 0;
        s->irr = 0;
        s->imr = 0;
@@ -268,6 +255,13 @@ void kvm_pic_reset(struct kvm_kpic_state *s)
        s->rotate_on_auto_eoi = 0;
        s->special_fully_nested_mode = 0;
        s->init4 = 0;
+
+       for (irq = 0; irq < PIC_NUM_PINS/2; irq++) {
+               if (vcpu0 && kvm_apic_accept_pic_intr(vcpu0))
+                       if (irr & (1 << irq) || isr & (1 << irq)) {
+                               pic_clear_isr(s, irq);
+                       }
+       }
 }
 
 static void pic_ioport_write(void *opaque, u32 addr, u32 val)
@@ -310,9 +304,9 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val)
                                priority = get_priority(s, s->isr);
                                if (priority != 8) {
                                        irq = (priority + s->priority_add) & 7;
-                                       pic_clear_isr(s, irq);
                                        if (cmd == 5)
                                                s->priority_add = (irq + 1) & 7;
+                                       pic_clear_isr(s, irq);
                                        pic_update_irq(s->pics_state);
                                }
                                break;
@@ -448,7 +442,7 @@ static int picdev_write(struct kvm_io_device *this,
                        printk(KERN_ERR "PIC: non byte write\n");
                return 0;
        }
-       pic_lock(s);
+       spin_lock(&s->lock);
        switch (addr) {
        case 0x20:
        case 0x21:
@@ -461,7 +455,7 @@ static int picdev_write(struct kvm_io_device *this,
                elcr_ioport_write(&s->pics[addr & 1], addr, data);
                break;
        }
-       pic_unlock(s);
+       spin_unlock(&s->lock);
        return 0;
 }
 
@@ -478,7 +472,7 @@ static int picdev_read(struct kvm_io_device *this,
                        printk(KERN_ERR "PIC: non byte read\n");
                return 0;
        }
-       pic_lock(s);
+       spin_lock(&s->lock);
        switch (addr) {
        case 0x20:
        case 0x21:
@@ -492,7 +486,7 @@ static int picdev_read(struct kvm_io_device *this,
                break;
        }
        *(unsigned char *)val = data;
-       pic_unlock(s);
+       spin_unlock(&s->lock);
        return 0;
 }