diff options
author | Gleb Natapov <gleb@redhat.com> | 2009-07-05 10:39:35 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-09-10 01:33:07 -0400 |
commit | fc61b800f9506ca47bf1439342a79847f2353562 (patch) | |
tree | ffb0f568dbb5e88604ceed93e8f1cf2fe544db03 /arch/x86/kvm/lapic.c | |
parent | cb24772140e09cb2503af7a4736ae3e08e9ac7d3 (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.c | 38 |
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 | ||
146 | void 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 | |||
145 | static unsigned int apic_lvt_mask[APIC_LVT_NUM] = { | 161 | static 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 | ||
450 | static void apic_send_ipi(struct kvm_lapic *apic) | 468 | static 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); |