Skip to content

Commit efc6440

Browse files
Feng Wubonzini
authored andcommitted
KVM: x86: Update IRTE for posted-interrupts
This patch adds the routine to update IRTE for posted-interrupts when guest changes the interrupt configuration. Signed-off-by: Feng Wu <[email protected]> Reviewed-by: Alex Williamson <[email protected]> Signed-off-by: Fengguang Wu <[email protected]> [Squashed in automatically generated patch from the build robot "KVM: x86: vcpu_to_pi_desc() can be static" - Paolo] Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 6d7425f commit efc6440

File tree

4 files changed

+121
-0
lines changed

4 files changed

+121
-0
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,9 @@ struct kvm_x86_ops {
897897
gfn_t offset, unsigned long mask);
898898
/* pmu operations of sub-arch */
899899
const struct kvm_pmu_ops *pmu_ops;
900+
901+
int (*update_pi_irte)(struct kvm *kvm, unsigned int host_irq,
902+
uint32_t guest_irq, bool set);
900903
};
901904

902905
struct kvm_arch_async_pf {

arch/x86/kvm/trace.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,39 @@ TRACE_EVENT(kvm_enter_smm,
992992
__entry->smbase)
993993
);
994994

995+
/*
996+
* Tracepoint for VT-d posted-interrupts.
997+
*/
998+
TRACE_EVENT(kvm_pi_irte_update,
999+
TP_PROTO(unsigned int vcpu_id, unsigned int gsi,
1000+
unsigned int gvec, u64 pi_desc_addr, bool set),
1001+
TP_ARGS(vcpu_id, gsi, gvec, pi_desc_addr, set),
1002+
1003+
TP_STRUCT__entry(
1004+
__field( unsigned int, vcpu_id )
1005+
__field( unsigned int, gsi )
1006+
__field( unsigned int, gvec )
1007+
__field( u64, pi_desc_addr )
1008+
__field( bool, set )
1009+
),
1010+
1011+
TP_fast_assign(
1012+
__entry->vcpu_id = vcpu_id;
1013+
__entry->gsi = gsi;
1014+
__entry->gvec = gvec;
1015+
__entry->pi_desc_addr = pi_desc_addr;
1016+
__entry->set = set;
1017+
),
1018+
1019+
TP_printk("VT-d PI is %s for this irq, vcpu %u, gsi: 0x%x, "
1020+
"gvec: 0x%x, pi_desc_addr: 0x%llx",
1021+
__entry->set ? "enabled and being updated" : "disabled",
1022+
__entry->vcpu_id,
1023+
__entry->gsi,
1024+
__entry->gvec,
1025+
__entry->pi_desc_addr)
1026+
);
1027+
9951028
#endif /* _TRACE_KVM_H */
9961029

9971030
#undef TRACE_INCLUDE_PATH

arch/x86/kvm/vmx.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include <asm/debugreg.h>
4646
#include <asm/kexec.h>
4747
#include <asm/apic.h>
48+
#include <asm/irq_remapping.h>
4849

4950
#include "trace.h"
5051
#include "pmu.h"
@@ -603,6 +604,11 @@ static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
603604
return container_of(vcpu, struct vcpu_vmx, vcpu);
604605
}
605606

607+
static struct pi_desc *vcpu_to_pi_desc(struct kvm_vcpu *vcpu)
608+
{
609+
return &(to_vmx(vcpu)->pi_desc);
610+
}
611+
606612
#define VMCS12_OFFSET(x) offsetof(struct vmcs12, x)
607613
#define FIELD(number, name) [number] = VMCS12_OFFSET(name)
608614
#define FIELD64(number, name) [number] = VMCS12_OFFSET(name), \
@@ -10345,6 +10351,81 @@ static void vmx_enable_log_dirty_pt_masked(struct kvm *kvm,
1034510351
kvm_mmu_clear_dirty_pt_masked(kvm, memslot, offset, mask);
1034610352
}
1034710353

10354+
/*
10355+
* vmx_update_pi_irte - set IRTE for Posted-Interrupts
10356+
*
10357+
* @kvm: kvm
10358+
* @host_irq: host irq of the interrupt
10359+
* @guest_irq: gsi of the interrupt
10360+
* @set: set or unset PI
10361+
* returns 0 on success, < 0 on failure
10362+
*/
10363+
static int vmx_update_pi_irte(struct kvm *kvm, unsigned int host_irq,
10364+
uint32_t guest_irq, bool set)
10365+
{
10366+
struct kvm_kernel_irq_routing_entry *e;
10367+
struct kvm_irq_routing_table *irq_rt;
10368+
struct kvm_lapic_irq irq;
10369+
struct kvm_vcpu *vcpu;
10370+
struct vcpu_data vcpu_info;
10371+
int idx, ret = -EINVAL;
10372+
10373+
if (!kvm_arch_has_assigned_device(kvm) ||
10374+
!irq_remapping_cap(IRQ_POSTING_CAP))
10375+
return 0;
10376+
10377+
idx = srcu_read_lock(&kvm->irq_srcu);
10378+
irq_rt = srcu_dereference(kvm->irq_routing, &kvm->irq_srcu);
10379+
BUG_ON(guest_irq >= irq_rt->nr_rt_entries);
10380+
10381+
hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) {
10382+
if (e->type != KVM_IRQ_ROUTING_MSI)
10383+
continue;
10384+
/*
10385+
* VT-d PI cannot support posting multicast/broadcast
10386+
* interrupts to a vCPU, we still use interrupt remapping
10387+
* for these kind of interrupts.
10388+
*
10389+
* For lowest-priority interrupts, we only support
10390+
* those with single CPU as the destination, e.g. user
10391+
* configures the interrupts via /proc/irq or uses
10392+
* irqbalance to make the interrupts single-CPU.
10393+
*
10394+
* We will support full lowest-priority interrupt later.
10395+
*/
10396+
10397+
kvm_set_msi_irq(e, &irq);
10398+
if (!kvm_intr_is_single_vcpu(kvm, &irq, &vcpu))
10399+
continue;
10400+
10401+
vcpu_info.pi_desc_addr = __pa(vcpu_to_pi_desc(vcpu));
10402+
vcpu_info.vector = irq.vector;
10403+
10404+
trace_kvm_pi_irte_update(vcpu->vcpu_id, e->gsi,
10405+
vcpu_info.vector, vcpu_info.pi_desc_addr, set);
10406+
10407+
if (set)
10408+
ret = irq_set_vcpu_affinity(host_irq, &vcpu_info);
10409+
else {
10410+
/* suppress notification event before unposting */
10411+
pi_set_sn(vcpu_to_pi_desc(vcpu));
10412+
ret = irq_set_vcpu_affinity(host_irq, NULL);
10413+
pi_clear_sn(vcpu_to_pi_desc(vcpu));
10414+
}
10415+
10416+
if (ret < 0) {
10417+
printk(KERN_INFO "%s: failed to update PI IRTE\n",
10418+
__func__);
10419+
goto out;
10420+
}
10421+
}
10422+
10423+
ret = 0;
10424+
out:
10425+
srcu_read_unlock(&kvm->irq_srcu, idx);
10426+
return ret;
10427+
}
10428+
1034810429
static struct kvm_x86_ops vmx_x86_ops = {
1034910430
.cpu_has_kvm_support = cpu_has_kvm_support,
1035010431
.disabled_by_bios = vmx_disabled_by_bios,
@@ -10462,6 +10543,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
1046210543
.enable_log_dirty_pt_masked = vmx_enable_log_dirty_pt_masked,
1046310544

1046410545
.pmu_ops = &intel_pmu_ops,
10546+
10547+
.update_pi_irte = vmx_update_pi_irte,
1046510548
};
1046610549

1046710550
static int __init vmx_init(void)

arch/x86/kvm/x86.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#include <asm/fpu/internal.h> /* Ugh! */
6565
#include <asm/pvclock.h>
6666
#include <asm/div64.h>
67+
#include <asm/irq_remapping.h>
6768

6869
#define MAX_IO_MSRS 256
6970
#define KVM_MAX_MCE_BANKS 32
@@ -8094,3 +8095,4 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_nested_intercepts);
80948095
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_write_tsc_offset);
80958096
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_ple_window);
80968097
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pml_full);
8098+
EXPORT_TRACEPOINT_SYMBOL_GPL(kvm_pi_irte_update);

0 commit comments

Comments
 (0)