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 | |
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')
-rw-r--r-- | arch/x86/include/asm/apicdef.h | 2 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 38 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 4 | ||||
-rw-r--r-- | arch/x86/kvm/x86.h | 4 |
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 | ||
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); |
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); | |||
29 | void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); | 29 | void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8); |
30 | void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); | 30 | void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value); |
31 | u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu); | 31 | u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu); |
32 | void kvm_apic_set_version(struct kvm_vcpu *vcpu); | ||
32 | 33 | ||
33 | int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest); | 34 | int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest); |
34 | int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); | 35 | int 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 | ||
80 | static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid, | 80 | static 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); |
82 | struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, | ||
83 | u32 function, u32 index); | ||
84 | 82 | ||
85 | struct kvm_x86_ops *kvm_x86_ops; | 83 | struct kvm_x86_ops *kvm_x86_ops; |
86 | EXPORT_SYMBOL_GPL(kvm_x86_ops); | 84 | EXPORT_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 | ||
1377 | out_free: | 1376 | out_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 | ||
1399 | out: | 1399 | out: |
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 | |||
35 | struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu, | ||
36 | u32 function, u32 index); | ||
37 | |||
34 | #endif | 38 | #endif |