Merge tag 'driver-core-5.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / arch / x86 / kvm / ioapic.c
index d859ae8890d0a6d144427cff8e36fa18078c715a..9fd2dd89a1c5e304dcb179304cff8915c1a2f4ee 100644 (file)
@@ -271,8 +271,9 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
 {
        unsigned index;
        bool mask_before, mask_after;
-       int old_remote_irr, old_delivery_status;
        union kvm_ioapic_redirect_entry *e;
+       unsigned long vcpu_bitmap;
+       int old_remote_irr, old_delivery_status, old_dest_id, old_dest_mode;
 
        switch (ioapic->ioregsel) {
        case IOAPIC_REG_VERSION:
@@ -296,6 +297,8 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
                /* Preserve read-only fields */
                old_remote_irr = e->fields.remote_irr;
                old_delivery_status = e->fields.delivery_status;
+               old_dest_id = e->fields.dest_id;
+               old_dest_mode = e->fields.dest_mode;
                if (ioapic->ioregsel & 1) {
                        e->bits &= 0xffffffff;
                        e->bits |= (u64) val << 32;
@@ -321,7 +324,34 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
                if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG
                    && ioapic->irr & (1 << index))
                        ioapic_service(ioapic, index, false);
-               kvm_make_scan_ioapic_request(ioapic->kvm);
+               if (e->fields.delivery_mode == APIC_DM_FIXED) {
+                       struct kvm_lapic_irq irq;
+
+                       irq.shorthand = 0;
+                       irq.vector = e->fields.vector;
+                       irq.delivery_mode = e->fields.delivery_mode << 8;
+                       irq.dest_id = e->fields.dest_id;
+                       irq.dest_mode = e->fields.dest_mode;
+                       bitmap_zero(&vcpu_bitmap, 16);
+                       kvm_bitmap_or_dest_vcpus(ioapic->kvm, &irq,
+                                                &vcpu_bitmap);
+                       if (old_dest_mode != e->fields.dest_mode ||
+                           old_dest_id != e->fields.dest_id) {
+                               /*
+                                * Update vcpu_bitmap with vcpus specified in
+                                * the previous request as well. This is done to
+                                * keep ioapic_handled_vectors synchronized.
+                                */
+                               irq.dest_id = old_dest_id;
+                               irq.dest_mode = old_dest_mode;
+                               kvm_bitmap_or_dest_vcpus(ioapic->kvm, &irq,
+                                                        &vcpu_bitmap);
+                       }
+                       kvm_make_scan_ioapic_request_mask(ioapic->kvm,
+                                                         &vcpu_bitmap);
+               } else {
+                       kvm_make_scan_ioapic_request(ioapic->kvm);
+               }
                break;
        }
 }