From: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx> In case AVIC is enabled, during vcpu_load/unload, SVM needs to update IOMMU IRTE with appropriate host physical APIC ID. Also, when vcpu_blocking/unblocking, SVM needs to update the is-running bit in the IOMMU IRTE. Both are achieved via calling amd_iommu_update_ga(). However, if GA mode is not enabled for the pass-through device, IOMMU driver will simply just return when calling amd_iommu_update_ga. Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx> --- arch/x86/kvm/svm.c | 50 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 38fd7a3..3b9a0b2 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1397,11 +1397,24 @@ free_avic: return err; } +static inline int +avic_update_iommu(struct kvm_vcpu *vcpu, int cpu, phys_addr_t pa, bool r) +{ + struct kvm_arch *vm_data = &vcpu->kvm->arch; + + if (!kvm_arch_has_assigned_device(vcpu->kvm)) + return 0; + + return amd_iommu_update_ga(vcpu->vcpu_id, cpu, vm_data->avic_tag, + (pa & AVIC_HPA_MASK), r); +} + /** * This function is called during VCPU halt/unhalt. */ static int avic_set_running(struct kvm_vcpu *vcpu, bool is_run) { + int ret = 0; u64 entry; int h_physical_id = __default_cpu_present_to_apicid(vcpu->cpu); struct vcpu_svm *svm = to_svm(vcpu); @@ -1420,17 +1433,27 @@ static int avic_set_running(struct kvm_vcpu *vcpu, bool is_run) WARN_ON((entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) == 0); entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; - if (is_run) + if (is_run) { entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; - WRITE_ONCE(*(svm->avic_physical_id_cache), entry); + WRITE_ONCE(*(svm->avic_physical_id_cache), entry); - return 0; + ret = avic_update_iommu(vcpu, h_physical_id, + page_to_phys(svm->avic_backing_page), 1); + } else { + ret = avic_update_iommu(vcpu, h_physical_id, + page_to_phys(svm->avic_backing_page), 0); + + WRITE_ONCE(*(svm->avic_physical_id_cache), entry); + } + + return ret; } static int avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu, bool is_load) { - u64 entry; + int ret = 0; int h_physical_id = __default_cpu_present_to_apicid(cpu); + u64 entry; struct vcpu_svm *svm = to_svm(vcpu); if (!svm_vcpu_avic_enabled(svm)) @@ -1443,16 +1466,29 @@ static int avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu, bool is_load) entry = READ_ONCE(*(svm->avic_physical_id_cache)); WARN_ON(is_load && (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK)); - entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; if (is_load) { entry &= ~AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK; entry |= (h_physical_id & AVIC_PHYSICAL_ID_ENTRY_HOST_PHYSICAL_ID_MASK); + + entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; if (!svm->avic_is_blocking) entry |= AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; + WRITE_ONCE(*(svm->avic_physical_id_cache), entry); + + ret = avic_update_iommu(vcpu, h_physical_id, + page_to_phys(svm->avic_backing_page), + !svm->avic_is_blocking); + } else { + if (entry & AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK) { + ret = avic_update_iommu(vcpu, h_physical_id, + page_to_phys(svm->avic_backing_page), 0); + + entry &= ~AVIC_PHYSICAL_ID_ENTRY_IS_RUNNING_MASK; + WRITE_ONCE(*(svm->avic_physical_id_cache), entry); + } } - WRITE_ONCE(*(svm->avic_physical_id_cache), entry); - return 0; + return ret; } static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event) -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html