Merge branch 'kvm-lapic-fix-and-cleanup' into HEAD
[linux-2.6-microblaze.git] / arch / x86 / include / asm / kvm_host.h
index 8d0a0a7..4d2bc08 100644 (file)
@@ -1022,19 +1022,30 @@ struct kvm_arch_memory_slot {
 };
 
 /*
- * We use as the mode the number of bits allocated in the LDR for the
- * logical processor ID.  It happens that these are all powers of two.
- * This makes it is very easy to detect cases where the APICs are
- * configured for multiple modes; in that case, we cannot use the map and
- * hence cannot use kvm_irq_delivery_to_apic_fast either.
+ * Track the mode of the optimized logical map, as the rules for decoding the
+ * destination vary per mode.  Enabling the optimized logical map requires all
+ * software-enabled local APIs to be in the same mode, each addressable APIC to
+ * be mapped to only one MDA, and each MDA to map to at most one APIC.
  */
-#define KVM_APIC_MODE_XAPIC_CLUSTER          4
-#define KVM_APIC_MODE_XAPIC_FLAT             8
-#define KVM_APIC_MODE_X2APIC                16
+enum kvm_apic_logical_mode {
+       /* All local APICs are software disabled. */
+       KVM_APIC_MODE_SW_DISABLED,
+       /* All software enabled local APICs in xAPIC cluster addressing mode. */
+       KVM_APIC_MODE_XAPIC_CLUSTER,
+       /* All software enabled local APICs in xAPIC flat addressing mode. */
+       KVM_APIC_MODE_XAPIC_FLAT,
+       /* All software enabled local APICs in x2APIC mode. */
+       KVM_APIC_MODE_X2APIC,
+       /*
+        * Optimized map disabled, e.g. not all local APICs in the same logical
+        * mode, same logical ID assigned to multiple APICs, etc.
+        */
+       KVM_APIC_MODE_MAP_DISABLED,
+};
 
 struct kvm_apic_map {
        struct rcu_head rcu;
-       u8 mode;
+       enum kvm_apic_logical_mode logical_mode;
        u32 max_apic_id;
        union {
                struct kvm_lapic *xapic_flat_map[8];
@@ -1164,6 +1175,12 @@ enum kvm_apicv_inhibit {
         */
        APICV_INHIBIT_REASON_BLOCKIRQ,
 
+       /*
+        * APICv is disabled because not all vCPUs have a 1:1 mapping between
+        * APIC ID and vCPU, _and_ KVM is not applying its x2APIC hotplug hack.
+        */
+       APICV_INHIBIT_REASON_PHYSICAL_ID_ALIASED,
+
        /*
         * For simplicity, the APIC acceleration is inhibited
         * first time either APIC ID or APIC base are changed by the guest
@@ -1202,6 +1219,12 @@ enum kvm_apicv_inhibit {
         * AVIC is disabled because SEV doesn't support it.
         */
        APICV_INHIBIT_REASON_SEV,
+
+       /*
+        * AVIC is disabled because not all vCPUs with a valid LDR have a 1:1
+        * mapping between logical ID and vCPU.
+        */
+       APICV_INHIBIT_REASON_LOGICAL_ID_ALIASED,
 };
 
 struct kvm_arch {
@@ -1250,10 +1273,11 @@ struct kvm_arch {
        struct kvm_apic_map __rcu *apic_map;
        atomic_t apic_map_dirty;
 
-       /* Protects apic_access_memslot_enabled and apicv_inhibit_reasons */
-       struct rw_semaphore apicv_update_lock;
-
        bool apic_access_memslot_enabled;
+       bool apic_access_memslot_inhibited;
+
+       /* Protects apicv_inhibit_reasons */
+       struct rw_semaphore apicv_update_lock;
        unsigned long apicv_inhibit_reasons;
 
        gpa_t wall_clock;
@@ -1602,6 +1626,8 @@ struct kvm_x86_ops {
        void (*enable_irq_window)(struct kvm_vcpu *vcpu);
        void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
        bool (*check_apicv_inhibit_reasons)(enum kvm_apicv_inhibit reason);
+       const unsigned long required_apicv_inhibits;
+       bool allow_apicv_in_x2apic_without_x2apic_virtualization;
        void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu);
        void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
        void (*hwapic_isr_update)(int isr);
@@ -1976,7 +2002,7 @@ gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva,
 
 bool kvm_apicv_activated(struct kvm *kvm);
 bool kvm_vcpu_apicv_activated(struct kvm_vcpu *vcpu);
-void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu);
+void __kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu);
 void __kvm_set_or_clear_apicv_inhibit(struct kvm *kvm,
                                      enum kvm_apicv_inhibit reason, bool set);
 void kvm_set_or_clear_apicv_inhibit(struct kvm *kvm,