KVM: x86: VMX: __kvm_apic_update_irr must update the IRR atomically
[linux-2.6-microblaze.git] / arch / x86 / kvm / lapic.c
index 113ca96..b17b37e 100644 (file)
@@ -637,16 +637,22 @@ bool __kvm_apic_update_irr(u32 *pir, void *regs, int *max_irr)
        *max_irr = -1;
 
        for (i = vec = 0; i <= 7; i++, vec += 32) {
+               u32 *p_irr = (u32 *)(regs + APIC_IRR + i * 0x10);
+
+               irr_val = *p_irr;
                pir_val = READ_ONCE(pir[i]);
-               irr_val = *((u32 *)(regs + APIC_IRR + i * 0x10));
+
                if (pir_val) {
+                       pir_val = xchg(&pir[i], 0);
+
                        prev_irr_val = irr_val;
-                       irr_val |= xchg(&pir[i], 0);
-                       *((u32 *)(regs + APIC_IRR + i * 0x10)) = irr_val;
-                       if (prev_irr_val != irr_val) {
-                               max_updated_irr =
-                                       __fls(irr_val ^ prev_irr_val) + vec;
-                       }
+                       do {
+                               irr_val = prev_irr_val | pir_val;
+                       } while (prev_irr_val != irr_val &&
+                                !try_cmpxchg(p_irr, &prev_irr_val, irr_val));
+
+                       if (prev_irr_val != irr_val)
+                               max_updated_irr = __fls(irr_val ^ prev_irr_val) + vec;
                }
                if (irr_val)
                        *max_irr = __fls(irr_val) + vec;