Skip to content

Commit 7ee30bc

Browse files
Nitesh Narayan Lalbonzini
authored andcommitted
KVM: x86: deliver KVM IOAPIC scan request to target vCPUs
In IOAPIC fixed delivery mode instead of flushing the scan requests to all vCPUs, we should only send the requests to vCPUs specified within the destination field. This patch introduces kvm_get_dest_vcpus_mask() API which retrieves an array of target vCPUs by using kvm_apic_map_get_dest_lapic() and then based on the vcpus_idx, it sets the bit in a bitmap. However, if the above fails kvm_get_dest_vcpus_mask() finds the target vCPUs by traversing all available vCPUs. Followed by setting the bits in the bitmap. If we had different vCPUs in the previous request for the same redirection table entry then bits corresponding to these vCPUs are also set. This to done to keep ioapic_handled_vectors synchronized. This bitmap is then eventually passed on to kvm_make_vcpus_request_mask() to generate a masked request only for the target vCPUs. This would enable us to reduce the latency overhead on isolated vCPUs caused by the IPI to process due to KVM_REQ_IOAPIC_SCAN. Suggested-by: Marcelo Tosatti <[email protected]> Signed-off-by: Nitesh Narayan Lal <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 8750e72 commit 7ee30bc

File tree

6 files changed

+96
-2
lines changed

6 files changed

+96
-2
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,8 @@ bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip);
15881588

15891589
void kvm_make_mclock_inprogress_request(struct kvm *kvm);
15901590
void kvm_make_scan_ioapic_request(struct kvm *kvm);
1591+
void kvm_make_scan_ioapic_request_mask(struct kvm *kvm,
1592+
unsigned long *vcpu_bitmap);
15911593

15921594
void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
15931595
struct kvm_async_pf *work);

arch/x86/kvm/ioapic.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,9 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
271271
{
272272
unsigned index;
273273
bool mask_before, mask_after;
274-
int old_remote_irr, old_delivery_status;
275274
union kvm_ioapic_redirect_entry *e;
275+
unsigned long vcpu_bitmap;
276+
int old_remote_irr, old_delivery_status, old_dest_id, old_dest_mode;
276277

277278
switch (ioapic->ioregsel) {
278279
case IOAPIC_REG_VERSION:
@@ -296,6 +297,8 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
296297
/* Preserve read-only fields */
297298
old_remote_irr = e->fields.remote_irr;
298299
old_delivery_status = e->fields.delivery_status;
300+
old_dest_id = e->fields.dest_id;
301+
old_dest_mode = e->fields.dest_mode;
299302
if (ioapic->ioregsel & 1) {
300303
e->bits &= 0xffffffff;
301304
e->bits |= (u64) val << 32;
@@ -321,7 +324,33 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
321324
if (e->fields.trig_mode == IOAPIC_LEVEL_TRIG
322325
&& ioapic->irr & (1 << index))
323326
ioapic_service(ioapic, index, false);
324-
kvm_make_scan_ioapic_request(ioapic->kvm);
327+
if (e->fields.delivery_mode == APIC_DM_FIXED) {
328+
struct kvm_lapic_irq irq;
329+
330+
irq.shorthand = 0;
331+
irq.vector = e->fields.vector;
332+
irq.delivery_mode = e->fields.delivery_mode << 8;
333+
irq.dest_id = e->fields.dest_id;
334+
irq.dest_mode = e->fields.dest_mode;
335+
kvm_bitmap_or_dest_vcpus(ioapic->kvm, &irq,
336+
&vcpu_bitmap);
337+
if (old_dest_mode != e->fields.dest_mode ||
338+
old_dest_id != e->fields.dest_id) {
339+
/*
340+
* Update vcpu_bitmap with vcpus specified in
341+
* the previous request as well. This is done to
342+
* keep ioapic_handled_vectors synchronized.
343+
*/
344+
irq.dest_id = old_dest_id;
345+
irq.dest_mode = old_dest_mode;
346+
kvm_bitmap_or_dest_vcpus(ioapic->kvm, &irq,
347+
&vcpu_bitmap);
348+
}
349+
kvm_make_scan_ioapic_request_mask(ioapic->kvm,
350+
&vcpu_bitmap);
351+
} else {
352+
kvm_make_scan_ioapic_request(ioapic->kvm);
353+
}
325354
break;
326355
}
327356
}

arch/x86/kvm/lapic.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,50 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
11221122
return result;
11231123
}
11241124

1125+
/*
1126+
* This routine identifies the destination vcpus mask meant to receive the
1127+
* IOAPIC interrupts. It either uses kvm_apic_map_get_dest_lapic() to find
1128+
* out the destination vcpus array and set the bitmap or it traverses to
1129+
* each available vcpu to identify the same.
1130+
*/
1131+
void kvm_bitmap_or_dest_vcpus(struct kvm *kvm, struct kvm_lapic_irq *irq,
1132+
unsigned long *vcpu_bitmap)
1133+
{
1134+
struct kvm_lapic **dest_vcpu = NULL;
1135+
struct kvm_lapic *src = NULL;
1136+
struct kvm_apic_map *map;
1137+
struct kvm_vcpu *vcpu;
1138+
unsigned long bitmap;
1139+
int i, vcpu_idx;
1140+
bool ret;
1141+
1142+
rcu_read_lock();
1143+
map = rcu_dereference(kvm->arch.apic_map);
1144+
1145+
ret = kvm_apic_map_get_dest_lapic(kvm, &src, irq, map, &dest_vcpu,
1146+
&bitmap);
1147+
if (ret) {
1148+
for_each_set_bit(i, &bitmap, 16) {
1149+
if (!dest_vcpu[i])
1150+
continue;
1151+
vcpu_idx = dest_vcpu[i]->vcpu->vcpu_idx;
1152+
__set_bit(vcpu_idx, vcpu_bitmap);
1153+
}
1154+
} else {
1155+
kvm_for_each_vcpu(i, vcpu, kvm) {
1156+
if (!kvm_apic_present(vcpu))
1157+
continue;
1158+
if (!kvm_apic_match_dest(vcpu, NULL,
1159+
irq->delivery_mode,
1160+
irq->dest_id,
1161+
irq->dest_mode))
1162+
continue;
1163+
__set_bit(i, vcpu_bitmap);
1164+
}
1165+
}
1166+
rcu_read_unlock();
1167+
}
1168+
11251169
int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
11261170
{
11271171
return vcpu1->arch.apic_arb_prio - vcpu2->arch.apic_arb_prio;

arch/x86/kvm/lapic.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
226226

227227
void kvm_wait_lapic_expire(struct kvm_vcpu *vcpu);
228228

229+
void kvm_bitmap_or_dest_vcpus(struct kvm *kvm, struct kvm_lapic_irq *irq,
230+
unsigned long *vcpu_bitmap);
231+
229232
bool kvm_intr_is_single_vcpu_fast(struct kvm *kvm, struct kvm_lapic_irq *irq,
230233
struct kvm_vcpu **dest_vcpu);
231234
int kvm_vector_to_index(u32 vector, u32 dest_vcpus,

arch/x86/kvm/x86.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7874,6 +7874,20 @@ static void process_smi(struct kvm_vcpu *vcpu)
78747874
kvm_make_request(KVM_REQ_EVENT, vcpu);
78757875
}
78767876

7877+
void kvm_make_scan_ioapic_request_mask(struct kvm *kvm,
7878+
unsigned long *vcpu_bitmap)
7879+
{
7880+
cpumask_var_t cpus;
7881+
bool called;
7882+
7883+
zalloc_cpumask_var(&cpus, GFP_ATOMIC);
7884+
7885+
called = kvm_make_vcpus_request_mask(kvm, KVM_REQ_SCAN_IOAPIC,
7886+
vcpu_bitmap, cpus);
7887+
7888+
free_cpumask_var(cpus);
7889+
}
7890+
78777891
void kvm_make_scan_ioapic_request(struct kvm *kvm)
78787892
{
78797893
kvm_make_all_cpus_request(kvm, KVM_REQ_SCAN_IOAPIC);

include/linux/kvm_host.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,8 @@ void kvm_reload_remote_mmus(struct kvm *kvm);
786786
bool kvm_make_vcpus_request_mask(struct kvm *kvm, unsigned int req,
787787
unsigned long *vcpu_bitmap, cpumask_var_t tmp);
788788
bool kvm_make_all_cpus_request(struct kvm *kvm, unsigned int req);
789+
bool kvm_make_cpus_request_mask(struct kvm *kvm, unsigned int req,
790+
unsigned long *vcpu_bitmap);
789791

790792
long kvm_arch_dev_ioctl(struct file *filp,
791793
unsigned int ioctl, unsigned long arg);

0 commit comments

Comments
 (0)