aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/lapic.c
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2009-07-05 10:39:35 -0400
committerAvi Kivity <avi@redhat.com>2009-09-10 01:33:07 -0400
commitfc61b800f9506ca47bf1439342a79847f2353562 (patch)
treeffb0f568dbb5e88604ceed93e8f1cf2fe544db03 /arch/x86/kvm/lapic.c
parentcb24772140e09cb2503af7a4736ae3e08e9ac7d3 (diff)
KVM: Add Directed EOI support to APIC emulation
Directed EOI is specified by x2APIC, but is available even when lapic is in xAPIC mode. Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r--arch/x86/kvm/lapic.c38
1 files changed, 30 insertions, 8 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 265a765f038f..62ea2abfd961 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -35,6 +35,7 @@
35#include "kvm_cache_regs.h" 35#include "kvm_cache_regs.h"
36#include "irq.h" 36#include "irq.h"
37#include "trace.h" 37#include "trace.h"
38#include "x86.h"
38 39
39#ifndef CONFIG_X86_64 40#ifndef CONFIG_X86_64
40#define mod_64(x, y) ((x) - (y) * div64_u64(x, y)) 41#define mod_64(x, y) ((x) - (y) * div64_u64(x, y))
@@ -142,6 +143,21 @@ static inline int apic_lvt_nmi_mode(u32 lvt_val)
142 return (lvt_val & (APIC_MODE_MASK | APIC_LVT_MASKED)) == APIC_DM_NMI; 143 return (lvt_val & (APIC_MODE_MASK | APIC_LVT_MASKED)) == APIC_DM_NMI;
143} 144}
144 145
146void kvm_apic_set_version(struct kvm_vcpu *vcpu)
147{
148 struct kvm_lapic *apic = vcpu->arch.apic;
149 struct kvm_cpuid_entry2 *feat;
150 u32 v = APIC_VERSION;
151
152 if (!irqchip_in_kernel(vcpu->kvm))
153 return;
154
155 feat = kvm_find_cpuid_entry(apic->vcpu, 0x1, 0);
156 if (feat && (feat->ecx & (1 << (X86_FEATURE_X2APIC & 31))))
157 v |= APIC_LVR_DIRECTED_EOI;
158 apic_set_reg(apic, APIC_LVR, v);
159}
160
145static unsigned int apic_lvt_mask[APIC_LVT_NUM] = { 161static unsigned int apic_lvt_mask[APIC_LVT_NUM] = {
146 LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */ 162 LVT_MASK | APIC_LVT_TIMER_PERIODIC, /* LVTT */
147 LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */ 163 LVT_MASK | APIC_MODE_MASK, /* LVTTHMR */
@@ -442,9 +458,11 @@ static void apic_set_eoi(struct kvm_lapic *apic)
442 trigger_mode = IOAPIC_LEVEL_TRIG; 458 trigger_mode = IOAPIC_LEVEL_TRIG;
443 else 459 else
444 trigger_mode = IOAPIC_EDGE_TRIG; 460 trigger_mode = IOAPIC_EDGE_TRIG;
445 mutex_lock(&apic->vcpu->kvm->irq_lock); 461 if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)) {
446 kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode); 462 mutex_lock(&apic->vcpu->kvm->irq_lock);
447 mutex_unlock(&apic->vcpu->kvm->irq_lock); 463 kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode);
464 mutex_unlock(&apic->vcpu->kvm->irq_lock);
465 }
448} 466}
449 467
450static void apic_send_ipi(struct kvm_lapic *apic) 468static void apic_send_ipi(struct kvm_lapic *apic)
@@ -694,8 +712,11 @@ static int apic_mmio_write(struct kvm_io_device *this,
694 apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF); 712 apic_set_reg(apic, APIC_DFR, val | 0x0FFFFFFF);
695 break; 713 break;
696 714
697 case APIC_SPIV: 715 case APIC_SPIV: {
698 apic_set_reg(apic, APIC_SPIV, val & 0x3ff); 716 u32 mask = 0x3ff;
717 if (apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI)
718 mask |= APIC_SPIV_DIRECTED_EOI;
719 apic_set_reg(apic, APIC_SPIV, val & mask);
699 if (!(val & APIC_SPIV_APIC_ENABLED)) { 720 if (!(val & APIC_SPIV_APIC_ENABLED)) {
700 int i; 721 int i;
701 u32 lvt_val; 722 u32 lvt_val;
@@ -710,7 +731,7 @@ static int apic_mmio_write(struct kvm_io_device *this,
710 731
711 } 732 }
712 break; 733 break;
713 734 }
714 case APIC_ICR: 735 case APIC_ICR:
715 /* No delay here, so we always clear the pending bit */ 736 /* No delay here, so we always clear the pending bit */
716 apic_set_reg(apic, APIC_ICR, val & ~(1 << 12)); 737 apic_set_reg(apic, APIC_ICR, val & ~(1 << 12));
@@ -837,7 +858,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
837 hrtimer_cancel(&apic->lapic_timer.timer); 858 hrtimer_cancel(&apic->lapic_timer.timer);
838 859
839 apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24); 860 apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24);
840 apic_set_reg(apic, APIC_LVR, APIC_VERSION); 861 kvm_apic_set_version(apic->vcpu);
841 862
842 for (i = 0; i < APIC_LVT_NUM; i++) 863 for (i = 0; i < APIC_LVT_NUM; i++)
843 apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED); 864 apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
@@ -1041,7 +1062,8 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
1041 1062
1042 apic->base_address = vcpu->arch.apic_base & 1063 apic->base_address = vcpu->arch.apic_base &
1043 MSR_IA32_APICBASE_BASE; 1064 MSR_IA32_APICBASE_BASE;
1044 apic_set_reg(apic, APIC_LVR, APIC_VERSION); 1065 kvm_apic_set_version(vcpu);
1066
1045 apic_update_ppr(apic); 1067 apic_update_ppr(apic);
1046 hrtimer_cancel(&apic->lapic_timer.timer); 1068 hrtimer_cancel(&apic->lapic_timer.timer);
1047 update_divide_count(apic); 1069 update_divide_count(apic);