KVM: Merge kvm_ioapic_get_delivery_bitmask into kvm_get_intr_delivery_bitmask
[linux-2.6.git] / virt / kvm / irq_comm.c
index d165e056f79bb3c70260da1718903a8c0486be36..1c6ff6d1b8422fc7f1db46fee8605ce9a29b2cf1 100644 (file)
@@ -47,15 +47,54 @@ void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
                                   union kvm_ioapic_redirect_entry *entry,
                                   unsigned long *deliver_bitmask)
 {
+       int i;
+       struct kvm *kvm = ioapic->kvm;
        struct kvm_vcpu *vcpu;
 
-       kvm_ioapic_get_delivery_bitmask(ioapic, entry->fields.dest_id,
-                                       entry->fields.dest_mode,
-                                       deliver_bitmask);
+       bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
+
+       if (entry->fields.dest_mode == 0) {     /* Physical mode. */
+               if (entry->fields.dest_id == 0xFF) {    /* Broadcast. */
+                       for (i = 0; i < KVM_MAX_VCPUS; ++i)
+                               if (kvm->vcpus[i] && kvm->vcpus[i]->arch.apic)
+                                       __set_bit(i, deliver_bitmask);
+                       /* Lowest priority shouldn't combine with broadcast */
+                       if (entry->fields.delivery_mode ==
+                           IOAPIC_LOWEST_PRIORITY && printk_ratelimit())
+                               printk(KERN_INFO "kvm: apic: phys broadcast "
+                                                 "and lowest prio\n");
+                       return;
+               }
+               for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+                       vcpu = kvm->vcpus[i];
+                       if (!vcpu)
+                               continue;
+                       if (kvm_apic_match_physical_addr(vcpu->arch.apic,
+                                       entry->fields.dest_id)) {
+                               if (vcpu->arch.apic)
+                                       __set_bit(i, deliver_bitmask);
+                               break;
+                       }
+               }
+       } else if (entry->fields.dest_id != 0) /* Logical mode, MDA non-zero. */
+               for (i = 0; i < KVM_MAX_VCPUS; ++i) {
+                       vcpu = kvm->vcpus[i];
+                       if (!vcpu)
+                               continue;
+                       if (vcpu->arch.apic &&
+                           kvm_apic_match_logical_addr(vcpu->arch.apic,
+                                       entry->fields.dest_id))
+                               __set_bit(i, deliver_bitmask);
+               }
+
        switch (entry->fields.delivery_mode) {
        case IOAPIC_LOWEST_PRIORITY:
+               /* Select one in deliver_bitmask */
                vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm,
                                entry->fields.vector, deliver_bitmask);
+               bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
+               if (!vcpu)
+                       return;
                __set_bit(vcpu->vcpu_id, deliver_bitmask);
                break;
        case IOAPIC_FIXED:
@@ -65,7 +104,7 @@ void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic,
                if (printk_ratelimit())
                        printk(KERN_INFO "kvm: unsupported delivery mode %d\n",
                                entry->fields.delivery_mode);
-               *deliver_bitmask = 0;
+               bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
        }
 }
 
@@ -80,8 +119,6 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
 
        BUG_ON(!ioapic);
 
-       bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
-
        entry.bits = 0;
        entry.fields.dest_id = (e->msi.address_lo &
                        MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;