KVM: Define a new interface kvm_intr_is_single_vcpu()
authorFeng Wu <feng.wu@intel.com>
Fri, 18 Sep 2015 14:29:47 +0000 (22:29 +0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 1 Oct 2015 13:06:49 +0000 (15:06 +0200)
This patch defines a new interface kvm_intr_is_single_vcpu(),
which can returns whether the interrupt is for single-CPU or not.

It is used by VT-d PI, since now we only support single-CPU
interrupts, For lowest-priority interrupts, if user configures
it via /proc/irq or uses irqbalance to make it single-CPU, we
can use PI to deliver the interrupts to it. Full functionality
of lowest-priority support will be added later.

Signed-off-by: Feng Wu <feng.wu@intel.com>
Reviewed-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/irq_comm.c
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h

index d064cb2e19e8f6c3e743a1d3f0020142d72a6fce..ba4e5673e604298eecdcd975c592f5f0fbd06e02 100644 (file)
@@ -1241,4 +1241,7 @@ int x86_set_memory_region(struct kvm *kvm,
 bool kvm_vcpu_is_reset_bsp(struct kvm_vcpu *vcpu);
 bool kvm_vcpu_is_bsp(struct kvm_vcpu *vcpu);
 
+bool kvm_intr_is_single_vcpu(struct kvm *kvm, struct kvm_lapic_irq *irq,
+                            struct kvm_vcpu **dest_vcpu);
+
 #endif /* _ASM_X86_KVM_HOST_H */
index 177460998bb0d192ff1b11cf208734ceef08fd4e..39f833f8132e33ebc4fba1d3654b90ca88a92daa 100644 (file)
@@ -297,6 +297,33 @@ out:
        return r;
 }
 
+bool kvm_intr_is_single_vcpu(struct kvm *kvm, struct kvm_lapic_irq *irq,
+                            struct kvm_vcpu **dest_vcpu)
+{
+       int i, r = 0;
+       struct kvm_vcpu *vcpu;
+
+       if (kvm_intr_is_single_vcpu_fast(kvm, irq, dest_vcpu))
+               return true;
+
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               if (!kvm_apic_present(vcpu))
+                       continue;
+
+               if (!kvm_apic_match_dest(vcpu, NULL, irq->shorthand,
+                                       irq->dest_id, irq->dest_mode))
+                       continue;
+
+               if (++r == 2)
+                       return false;
+
+               *dest_vcpu = vcpu;
+       }
+
+       return r == 1;
+}
+EXPORT_SYMBOL_GPL(kvm_intr_is_single_vcpu);
+
 #define IOAPIC_ROUTING_ENTRY(irq) \
        { .gsi = irq, .type = KVM_IRQ_ROUTING_IRQCHIP,  \
          .u.irqchip = { .irqchip = KVM_IRQCHIP_IOAPIC, .pin = (irq) } }
index 2f4c0d0cbe0a842df820a1cf5186b95f69bd00bc..944b38a569297f5b3feb8c00f768e06c766ddeb7 100644 (file)
@@ -755,6 +755,65 @@ out:
        return ret;
 }
 
+bool kvm_intr_is_single_vcpu_fast(struct kvm *kvm, struct kvm_lapic_irq *irq,
+                       struct kvm_vcpu **dest_vcpu)
+{
+       struct kvm_apic_map *map;
+       bool ret = false;
+       struct kvm_lapic *dst = NULL;
+
+       if (irq->shorthand)
+               return false;
+
+       rcu_read_lock();
+       map = rcu_dereference(kvm->arch.apic_map);
+
+       if (!map)
+               goto out;
+
+       if (irq->dest_mode == APIC_DEST_PHYSICAL) {
+               if (irq->dest_id == 0xFF)
+                       goto out;
+
+               if (irq->dest_id >= ARRAY_SIZE(map->phys_map))
+                       goto out;
+
+               dst = map->phys_map[irq->dest_id];
+               if (dst && kvm_apic_present(dst->vcpu))
+                       *dest_vcpu = dst->vcpu;
+               else
+                       goto out;
+       } else {
+               u16 cid;
+               unsigned long bitmap = 1;
+               int i, r = 0;
+
+               if (!kvm_apic_logical_map_valid(map))
+                       goto out;
+
+               apic_logical_id(map, irq->dest_id, &cid, (u16 *)&bitmap);
+
+               if (cid >= ARRAY_SIZE(map->logical_map))
+                       goto out;
+
+               for_each_set_bit(i, &bitmap, 16) {
+                       dst = map->logical_map[cid][i];
+                       if (++r == 2)
+                               goto out;
+               }
+
+               if (dst && kvm_apic_present(dst->vcpu))
+                       *dest_vcpu = dst->vcpu;
+               else
+                       goto out;
+       }
+
+       ret = true;
+out:
+       rcu_read_unlock();
+       return ret;
+}
+
 /*
  * Add a pending IRQ into lapic.
  * Return 1 if successfully added and 0 if discarded.
index 7259d272416f19f6b0b654db7b61892828a3c706..fde8e35d585050e7e2d26b9df326e7542b3d7f38 100644 (file)
@@ -168,4 +168,6 @@ bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
 
 void wait_lapic_expire(struct kvm_vcpu *vcpu);
 
+bool kvm_intr_is_single_vcpu_fast(struct kvm *kvm, struct kvm_lapic_irq *irq,
+                       struct kvm_vcpu **dest_vcpu);
 #endif