Skip to content

Commit

Permalink
KVM: Define a new interface kvm_intr_is_single_vcpu()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Feng Wu authored and Paolo Bonzini committed Oct 1, 2015
1 parent ebbfc76 commit 8feb4a0
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 0 deletions.
3 changes: 3 additions & 0 deletions arch/x86/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
27 changes: 27 additions & 0 deletions arch/x86/kvm/irq_comm.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,33 @@ int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
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) } }
Expand Down
59 changes: 59 additions & 0 deletions arch/x86/kvm/lapic.c
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,65 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
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.
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/kvm/lapic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 8feb4a0

Please sign in to comment.