diff options
author | Gleb Natapov <gleb@redhat.com> | 2012-08-05 08:58:30 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2012-08-06 12:00:43 -0400 |
commit | c5cc421ba3219b90f11d151bc55f1608c12830fa (patch) | |
tree | fa21392981697bbc01ed14c8aab98653622c5a33 | |
parent | a181dc14ed23f7a499542ff4c78532b5f24bb18f (diff) |
KVM: use jump label to optimize checking for HW enabled APIC in APIC_BASE MSR
Usually all APICs are HW enabled so the check can be optimized out.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | arch/x86/kvm/lapic.c | 29 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 1 |
3 files changed, 30 insertions, 1 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index c3f14fe51e9b..5b46cab044a5 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <asm/current.h> | 34 | #include <asm/current.h> |
35 | #include <asm/apicdef.h> | 35 | #include <asm/apicdef.h> |
36 | #include <linux/atomic.h> | 36 | #include <linux/atomic.h> |
37 | #include <linux/jump_label.h> | ||
37 | #include "kvm_cache_regs.h" | 38 | #include "kvm_cache_regs.h" |
38 | #include "irq.h" | 39 | #include "irq.h" |
39 | #include "trace.h" | 40 | #include "trace.h" |
@@ -117,9 +118,13 @@ static inline int __apic_test_and_clear_vector(int vec, void *bitmap) | |||
117 | return __test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); | 118 | return __test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); |
118 | } | 119 | } |
119 | 120 | ||
121 | struct static_key_deferred apic_hw_disabled __read_mostly; | ||
122 | |||
120 | static inline int apic_hw_enabled(struct kvm_lapic *apic) | 123 | static inline int apic_hw_enabled(struct kvm_lapic *apic) |
121 | { | 124 | { |
122 | return (apic)->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE; | 125 | if (static_key_false(&apic_hw_disabled.key)) |
126 | return apic->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE; | ||
127 | return MSR_IA32_APICBASE_ENABLE; | ||
123 | } | 128 | } |
124 | 129 | ||
125 | static inline int apic_sw_enabled(struct kvm_lapic *apic) | 130 | static inline int apic_sw_enabled(struct kvm_lapic *apic) |
@@ -1055,6 +1060,9 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu) | |||
1055 | 1060 | ||
1056 | hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer); | 1061 | hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer); |
1057 | 1062 | ||
1063 | if (!(vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE)) | ||
1064 | static_key_slow_dec_deferred(&apic_hw_disabled); | ||
1065 | |||
1058 | if (vcpu->arch.apic->regs) | 1066 | if (vcpu->arch.apic->regs) |
1059 | free_page((unsigned long)vcpu->arch.apic->regs); | 1067 | free_page((unsigned long)vcpu->arch.apic->regs); |
1060 | 1068 | ||
@@ -1125,6 +1133,14 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value) | |||
1125 | return; | 1133 | return; |
1126 | } | 1134 | } |
1127 | 1135 | ||
1136 | /* update jump label if enable bit changes */ | ||
1137 | if ((vcpu->arch.apic_base ^ value) & MSR_IA32_APICBASE_ENABLE) { | ||
1138 | if (value & MSR_IA32_APICBASE_ENABLE) | ||
1139 | static_key_slow_dec_deferred(&apic_hw_disabled); | ||
1140 | else | ||
1141 | static_key_slow_inc(&apic_hw_disabled.key); | ||
1142 | } | ||
1143 | |||
1128 | if (!kvm_vcpu_is_bsp(apic->vcpu)) | 1144 | if (!kvm_vcpu_is_bsp(apic->vcpu)) |
1129 | value &= ~MSR_IA32_APICBASE_BSP; | 1145 | value &= ~MSR_IA32_APICBASE_BSP; |
1130 | 1146 | ||
@@ -1311,6 +1327,11 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu) | |||
1311 | HRTIMER_MODE_ABS); | 1327 | HRTIMER_MODE_ABS); |
1312 | apic->lapic_timer.timer.function = apic_timer_fn; | 1328 | apic->lapic_timer.timer.function = apic_timer_fn; |
1313 | 1329 | ||
1330 | /* | ||
1331 | * APIC is created enabled. This will prevent kvm_lapic_set_base from | ||
1332 | * thinking that APIC satet has changed. | ||
1333 | */ | ||
1334 | vcpu->arch.apic_base = MSR_IA32_APICBASE_ENABLE; | ||
1314 | kvm_lapic_set_base(vcpu, | 1335 | kvm_lapic_set_base(vcpu, |
1315 | APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE); | 1336 | APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE); |
1316 | 1337 | ||
@@ -1598,3 +1619,9 @@ int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data) | |||
1598 | return kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.pv_eoi.data, | 1619 | return kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.pv_eoi.data, |
1599 | addr); | 1620 | addr); |
1600 | } | 1621 | } |
1622 | |||
1623 | void kvm_lapic_init(void) | ||
1624 | { | ||
1625 | /* do not patch jump label more than once per second */ | ||
1626 | jump_label_rate_limit(&apic_hw_disabled, HZ); | ||
1627 | } | ||
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 166766fffd9f..73fa299b68e8 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h | |||
@@ -78,4 +78,5 @@ static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu) | |||
78 | } | 78 | } |
79 | 79 | ||
80 | int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data); | 80 | int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data); |
81 | void kvm_lapic_init(void); | ||
81 | #endif | 82 | #endif |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3cafbb12ae05..29fa18d27e6e 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -4903,6 +4903,7 @@ int kvm_arch_init(void *opaque) | |||
4903 | if (cpu_has_xsave) | 4903 | if (cpu_has_xsave) |
4904 | host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); | 4904 | host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK); |
4905 | 4905 | ||
4906 | kvm_lapic_init(); | ||
4906 | return 0; | 4907 | return 0; |
4907 | 4908 | ||
4908 | out: | 4909 | out: |