]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - arch/x86/kvm/i8259.c
KVM: Move IO APIC to its own lock
[net-next-2.6.git] / arch / x86 / kvm / i8259.c
index ccc941af4eaf2909e0a57e96cbfdb6f6eec0d4d6..d057c0cbd2457d1b665cdfa9fefd71cdbc726d22 100644 (file)
@@ -38,7 +38,15 @@ static void pic_clear_isr(struct kvm_kpic_state *s, int 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)
@@ -176,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)
@@ -294,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;