]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
svm: Introduces AVIC per-VM ID
authorSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Tue, 23 Aug 2016 18:52:41 +0000 (13:52 -0500)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 8 Sep 2016 10:57:20 +0000 (12:57 +0200)
Introduces per-VM AVIC ID and helper functions to manage the IDs.
Currently, the ID will be used to implement 32-bit AVIC IOMMU GA tag.

The ID is 24-bit one-based indexing value, and is managed via helper
functions to get the next ID, or to free an ID once a VM is destroyed.
There should be no ID conflict for any active VMs.

Reviewed-by: Radim Krčmář <rkrcmar@redhat.com>
Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/svm.c

index 33ae3a4d0159893cacdaf54bbcf3bcbf3be127fd..d36176bb1b6d0c247c9bdb2652f1cb44f5ccab99 100644 (file)
@@ -781,6 +781,7 @@ struct kvm_arch {
        bool disabled_lapic_found;
 
        /* Struct members for AVIC */
+       u32 avic_vm_id;
        u32 ldr_mode;
        struct page *avic_logical_id_table_page;
        struct page *avic_physical_id_table_page;
index af523d84d102fde15d9194010ef7335495680670..27e37d8044b3793d23f4aa8afe6625dfcdd6a65a 100644 (file)
@@ -96,6 +96,19 @@ MODULE_DEVICE_TABLE(x86cpu, svm_cpu_id);
 #define AVIC_UNACCEL_ACCESS_OFFSET_MASK                0xFF0
 #define AVIC_UNACCEL_ACCESS_VECTOR_MASK                0xFFFFFFFF
 
+/* AVIC GATAG is encoded using VM and VCPU IDs */
+#define AVIC_VCPU_ID_BITS              8
+#define AVIC_VCPU_ID_MASK              ((1 << AVIC_VCPU_ID_BITS) - 1)
+
+#define AVIC_VM_ID_BITS                        24
+#define AVIC_VM_ID_NR                  (1 << AVIC_VM_ID_BITS)
+#define AVIC_VM_ID_MASK                        ((1 << AVIC_VM_ID_BITS) - 1)
+
+#define AVIC_GATAG(x, y)               (((x & AVIC_VM_ID_MASK) << AVIC_VCPU_ID_BITS) | \
+                                               (y & AVIC_VCPU_ID_MASK))
+#define AVIC_GATAG_TO_VMID(x)          ((x >> AVIC_VCPU_ID_BITS) & AVIC_VM_ID_MASK)
+#define AVIC_GATAG_TO_VCPUID(x)                (x & AVIC_VCPU_ID_MASK)
+
 static bool erratum_383_found __read_mostly;
 
 static const u32 host_save_user_msrs[] = {
@@ -242,6 +255,10 @@ static int avic;
 module_param(avic, int, S_IRUGO);
 #endif
 
+/* AVIC VM ID bit masks and lock */
+static DECLARE_BITMAP(avic_vm_id_bitmap, AVIC_VM_ID_NR);
+static DEFINE_SPINLOCK(avic_vm_id_lock);
+
 static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
 static void svm_flush_tlb(struct kvm_vcpu *vcpu);
 static void svm_complete_interrupts(struct vcpu_svm *svm);
@@ -1280,10 +1297,40 @@ static int avic_init_backing_page(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+static inline int avic_get_next_vm_id(void)
+{
+       int id;
+
+       spin_lock(&avic_vm_id_lock);
+
+       /* AVIC VM ID is one-based. */
+       id = find_next_zero_bit(avic_vm_id_bitmap, AVIC_VM_ID_NR, 1);
+       if (id <= AVIC_VM_ID_MASK)
+               __set_bit(id, avic_vm_id_bitmap);
+       else
+               id = -EAGAIN;
+
+       spin_unlock(&avic_vm_id_lock);
+       return id;
+}
+
+static inline int avic_free_vm_id(int id)
+{
+       if (id <= 0 || id > AVIC_VM_ID_MASK)
+               return -EINVAL;
+
+       spin_lock(&avic_vm_id_lock);
+       __clear_bit(id, avic_vm_id_bitmap);
+       spin_unlock(&avic_vm_id_lock);
+       return 0;
+}
+
 static void avic_vm_destroy(struct kvm *kvm)
 {
        struct kvm_arch *vm_data = &kvm->arch;
 
+       avic_free_vm_id(vm_data->avic_vm_id);
+
        if (vm_data->avic_logical_id_table_page)
                __free_page(vm_data->avic_logical_id_table_page);
        if (vm_data->avic_physical_id_table_page)
@@ -1300,6 +1347,10 @@ static int avic_vm_init(struct kvm *kvm)
        if (!avic)
                return 0;
 
+       vm_data->avic_vm_id = avic_get_next_vm_id();
+       if (vm_data->avic_vm_id < 0)
+               return vm_data->avic_vm_id;
+
        /* Allocating physical APIC ID table (4KB) */
        p_page = alloc_page(GFP_KERNEL);
        if (!p_page)