|
45 | 45 | #include <asm/debugreg.h> |
46 | 46 | #include <asm/kexec.h> |
47 | 47 | #include <asm/apic.h> |
| 48 | +#include <asm/irq_remapping.h> |
48 | 49 |
|
49 | 50 | #include "trace.h" |
50 | 51 | #include "pmu.h" |
@@ -603,6 +604,11 @@ static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu) |
603 | 604 | return container_of(vcpu, struct vcpu_vmx, vcpu); |
604 | 605 | } |
605 | 606 |
|
| 607 | +static struct pi_desc *vcpu_to_pi_desc(struct kvm_vcpu *vcpu) |
| 608 | +{ |
| 609 | + return &(to_vmx(vcpu)->pi_desc); |
| 610 | +} |
| 611 | + |
606 | 612 | #define VMCS12_OFFSET(x) offsetof(struct vmcs12, x) |
607 | 613 | #define FIELD(number, name) [number] = VMCS12_OFFSET(name) |
608 | 614 | #define FIELD64(number, name) [number] = VMCS12_OFFSET(name), \ |
@@ -10345,6 +10351,81 @@ static void vmx_enable_log_dirty_pt_masked(struct kvm *kvm, |
10345 | 10351 | kvm_mmu_clear_dirty_pt_masked(kvm, memslot, offset, mask); |
10346 | 10352 | } |
10347 | 10353 |
|
| 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 | + |
10348 | 10429 | static struct kvm_x86_ops vmx_x86_ops = { |
10349 | 10430 | .cpu_has_kvm_support = cpu_has_kvm_support, |
10350 | 10431 | .disabled_by_bios = vmx_disabled_by_bios, |
@@ -10462,6 +10543,8 @@ static struct kvm_x86_ops vmx_x86_ops = { |
10462 | 10543 | .enable_log_dirty_pt_masked = vmx_enable_log_dirty_pt_masked, |
10463 | 10544 |
|
10464 | 10545 | .pmu_ops = &intel_pmu_ops, |
| 10546 | + |
| 10547 | + .update_pi_irte = vmx_update_pi_irte, |
10465 | 10548 | }; |
10466 | 10549 |
|
10467 | 10550 | static int __init vmx_init(void) |
|
0 commit comments