aboutsummaryrefslogtreecommitdiffstats
path: root/arch
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
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')
-rw-r--r--arch/x86/include/asm/apicdef.h2
-rw-r--r--arch/x86/kvm/lapic.c38
-rw-r--r--arch/x86/kvm/lapic.h1
-rw-r--r--arch/x86/kvm/x86.c4
-rw-r--r--arch/x86/kvm/x86.h4
5 files changed, 39 insertions, 10 deletions
diff --git a/arch/x86/include/asm/apicdef.h b/arch/x86/include/asm/apicdef.h
index 7ddb36ab933b..74ca38f6a4de 100644
--- a/arch/x86/include/asm/apicdef.h
+++ b/arch/x86/include/asm/apicdef.h
@@ -14,6 +14,7 @@
14 14
15#define APIC_LVR 0x30 15#define APIC_LVR 0x30
16#define APIC_LVR_MASK 0xFF00FF 16#define APIC_LVR_MASK 0xFF00FF
17#define APIC_LVR_DIRECTED_EOI (1 << 24)
17#define GET_APIC_VERSION(x) ((x) & 0xFFu) 18#define GET_APIC_VERSION(x) ((x) & 0xFFu)
18#define GET_APIC_MAXLVT(x) (((x) >> 16) & 0xFFu) 19#define GET_APIC_MAXLVT(x) (((x) >> 16) & 0xFFu)
19#ifdef CONFIG_X86_32 20#ifdef CONFIG_X86_32
@@ -40,6 +41,7 @@
40#define APIC_DFR_CLUSTER 0x0FFFFFFFul 41#define APIC_DFR_CLUSTER 0x0FFFFFFFul
41#define APIC_DFR_FLAT 0xFFFFFFFFul 42#define APIC_DFR_FLAT 0xFFFFFFFFul
42#define APIC_SPIV 0xF0 43#define APIC_SPIV 0xF0
44#define APIC_SPIV_DIRECTED_EOI (1 << 12)
43#define APIC_SPIV_FOCUS_DISABLED (1 << 9) 45#define APIC_SPIV_FOCUS_DISABLED (1 << 9)
44#define APIC_SPIV_APIC_ENABLED (1 << 8) 46#define APIC_SPIV_APIC_ENABLED (1 << 8)
45#define APIC_ISR 0x100 47#define APIC_ISR 0x100
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);
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 3f3ecc6edbf5..bc1c5243c865 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -29,6 +29,7 @@ u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
29void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); 29void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
30void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); 30void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
31u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu); 31u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
32void kvm_apic_set_version(struct kvm_vcpu *vcpu);
32 33
33int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest); 34int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
34int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); 35int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index d32e3c6d3175..086f93137e3c 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -79,8 +79,6 @@ static u64 __read_mostly efer_reserved_bits = 0xfffffffffffffffeULL;
79 79
80static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid, 80static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
81 struct kvm_cpuid_entry2 __user *entries); 81 struct kvm_cpuid_entry2 __user *entries);
82struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
83 u32 function, u32 index);
84 82
85struct kvm_x86_ops *kvm_x86_ops; 83struct kvm_x86_ops *kvm_x86_ops;
86EXPORT_SYMBOL_GPL(kvm_x86_ops); 84EXPORT_SYMBOL_GPL(kvm_x86_ops);
@@ -1373,6 +1371,7 @@ static int kvm_vcpu_ioctl_set_cpuid(struct kvm_vcpu *vcpu,
1373 vcpu->arch.cpuid_nent = cpuid->nent; 1371 vcpu->arch.cpuid_nent = cpuid->nent;
1374 cpuid_fix_nx_cap(vcpu); 1372 cpuid_fix_nx_cap(vcpu);
1375 r = 0; 1373 r = 0;
1374 kvm_apic_set_version(vcpu);
1376 1375
1377out_free: 1376out_free:
1378 vfree(cpuid_entries); 1377 vfree(cpuid_entries);
@@ -1394,6 +1393,7 @@ static int kvm_vcpu_ioctl_set_cpuid2(struct kvm_vcpu *vcpu,
1394 cpuid->nent * sizeof(struct kvm_cpuid_entry2))) 1393 cpuid->nent * sizeof(struct kvm_cpuid_entry2)))
1395 goto out; 1394 goto out;
1396 vcpu->arch.cpuid_nent = cpuid->nent; 1395 vcpu->arch.cpuid_nent = cpuid->nent;
1396 kvm_apic_set_version(vcpu);
1397 return 0; 1397 return 0;
1398 1398
1399out: 1399out:
diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h
index 4c8e10af78e8..5eadea585d2a 100644
--- a/arch/x86/kvm/x86.h
+++ b/arch/x86/kvm/x86.h
@@ -31,4 +31,8 @@ static inline bool kvm_exception_is_soft(unsigned int nr)
31{ 31{
32 return (nr == BP_VECTOR) || (nr == OF_VECTOR); 32 return (nr == BP_VECTOR) || (nr == OF_VECTOR);
33} 33}
34
35struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
36 u32 function, u32 index);
37
34#endif 38#endif