diff options
author | Paolo Bonzini <pbonzini@redhat.com> | 2017-06-06 06:57:06 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2017-09-27 07:45:42 -0400 |
commit | 31afb2ea2b10a7d17ce3db4cdb0a12b63b2fe08a (patch) | |
tree | 6b95d75fe5afe16e396968ba6d99f34e0868af37 | |
parent | 8b306e2f3c41939ea528e6174c88cfbfff893ce1 (diff) |
KVM: VMX: simplify and fix vmx_vcpu_pi_load
The simplify part: do not touch pi_desc.nv, we can set it when the
VCPU is first created. Likewise, pi_desc.sn is only handled by
vmx_vcpu_pi_load, do not touch it in __pi_post_block.
The fix part: do not check kvm_arch_has_assigned_device, instead
check the SN bit to figure out whether vmx_vcpu_pi_put ran before.
This matches what the previous patch did in pi_post_block.
Cc: Huangweidong <weidong.huang@huawei.com>
Cc: Gonglei <arei.gonglei@huawei.com>
Cc: wangxin <wangxinxin.wang@huawei.com>
Cc: Radim Krčmář <rkrcmar@redhat.com>
Tested-by: Longpeng (Mike) <longpeng2@huawei.com>
Cc: stable@vger.kernel.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r-- | arch/x86/kvm/vmx.c | 68 |
1 files changed, 35 insertions, 33 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 0bfe97e50a40..b9d2140eb212 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -2202,43 +2202,41 @@ static void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu) | |||
2202 | struct pi_desc old, new; | 2202 | struct pi_desc old, new; |
2203 | unsigned int dest; | 2203 | unsigned int dest; |
2204 | 2204 | ||
2205 | if (!kvm_arch_has_assigned_device(vcpu->kvm) || | 2205 | /* |
2206 | !irq_remapping_cap(IRQ_POSTING_CAP) || | 2206 | * In case of hot-plug or hot-unplug, we may have to undo |
2207 | !kvm_vcpu_apicv_active(vcpu)) | 2207 | * vmx_vcpu_pi_put even if there is no assigned device. And we |
2208 | * always keep PI.NDST up to date for simplicity: it makes the | ||
2209 | * code easier, and CPU migration is not a fast path. | ||
2210 | */ | ||
2211 | if (!pi_test_sn(pi_desc) && vcpu->cpu == cpu) | ||
2212 | return; | ||
2213 | |||
2214 | /* | ||
2215 | * First handle the simple case where no cmpxchg is necessary; just | ||
2216 | * allow posting non-urgent interrupts. | ||
2217 | * | ||
2218 | * If the 'nv' field is POSTED_INTR_WAKEUP_VECTOR, do not change | ||
2219 | * PI.NDST: pi_post_block will do it for us and the wakeup_handler | ||
2220 | * expects the VCPU to be on the blocked_vcpu_list that matches | ||
2221 | * PI.NDST. | ||
2222 | */ | ||
2223 | if (pi_desc->nv == POSTED_INTR_WAKEUP_VECTOR || | ||
2224 | vcpu->cpu == cpu) { | ||
2225 | pi_clear_sn(pi_desc); | ||
2208 | return; | 2226 | return; |
2227 | } | ||
2209 | 2228 | ||
2229 | /* The full case. */ | ||
2210 | do { | 2230 | do { |
2211 | old.control = new.control = pi_desc->control; | 2231 | old.control = new.control = pi_desc->control; |
2212 | 2232 | ||
2213 | /* | 2233 | dest = cpu_physical_id(cpu); |
2214 | * If 'nv' field is POSTED_INTR_WAKEUP_VECTOR, there | ||
2215 | * are two possible cases: | ||
2216 | * 1. After running 'pre_block', context switch | ||
2217 | * happened. For this case, 'sn' was set in | ||
2218 | * vmx_vcpu_put(), so we need to clear it here. | ||
2219 | * 2. After running 'pre_block', we were blocked, | ||
2220 | * and woken up by some other guy. For this case, | ||
2221 | * we don't need to do anything, 'pi_post_block' | ||
2222 | * will do everything for us. However, we cannot | ||
2223 | * check whether it is case #1 or case #2 here | ||
2224 | * (maybe, not needed), so we also clear sn here, | ||
2225 | * I think it is not a big deal. | ||
2226 | */ | ||
2227 | if (pi_desc->nv != POSTED_INTR_WAKEUP_VECTOR) { | ||
2228 | if (vcpu->cpu != cpu) { | ||
2229 | dest = cpu_physical_id(cpu); | ||
2230 | |||
2231 | if (x2apic_enabled()) | ||
2232 | new.ndst = dest; | ||
2233 | else | ||
2234 | new.ndst = (dest << 8) & 0xFF00; | ||
2235 | } | ||
2236 | 2234 | ||
2237 | /* set 'NV' to 'notification vector' */ | 2235 | if (x2apic_enabled()) |
2238 | new.nv = POSTED_INTR_VECTOR; | 2236 | new.ndst = dest; |
2239 | } | 2237 | else |
2238 | new.ndst = (dest << 8) & 0xFF00; | ||
2240 | 2239 | ||
2241 | /* Allow posting non-urgent interrupts */ | ||
2242 | new.sn = 0; | 2240 | new.sn = 0; |
2243 | } while (cmpxchg(&pi_desc->control, old.control, | 2241 | } while (cmpxchg(&pi_desc->control, old.control, |
2244 | new.control) != old.control); | 2242 | new.control) != old.control); |
@@ -9592,6 +9590,13 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id) | |||
9592 | 9590 | ||
9593 | vmx->msr_ia32_feature_control_valid_bits = FEATURE_CONTROL_LOCKED; | 9591 | vmx->msr_ia32_feature_control_valid_bits = FEATURE_CONTROL_LOCKED; |
9594 | 9592 | ||
9593 | /* | ||
9594 | * Enforce invariant: pi_desc.nv is always either POSTED_INTR_VECTOR | ||
9595 | * or POSTED_INTR_WAKEUP_VECTOR. | ||
9596 | */ | ||
9597 | vmx->pi_desc.nv = POSTED_INTR_VECTOR; | ||
9598 | vmx->pi_desc.sn = 1; | ||
9599 | |||
9595 | return &vmx->vcpu; | 9600 | return &vmx->vcpu; |
9596 | 9601 | ||
9597 | free_vmcs: | 9602 | free_vmcs: |
@@ -11723,9 +11728,6 @@ static void __pi_post_block(struct kvm_vcpu *vcpu) | |||
11723 | else | 11728 | else |
11724 | new.ndst = (dest << 8) & 0xFF00; | 11729 | new.ndst = (dest << 8) & 0xFF00; |
11725 | 11730 | ||
11726 | /* Allow posting non-urgent interrupts */ | ||
11727 | new.sn = 0; | ||
11728 | |||
11729 | /* set 'NV' to 'notification vector' */ | 11731 | /* set 'NV' to 'notification vector' */ |
11730 | new.nv = POSTED_INTR_VECTOR; | 11732 | new.nv = POSTED_INTR_VECTOR; |
11731 | } while (cmpxchg(&pi_desc->control, old.control, | 11733 | } while (cmpxchg(&pi_desc->control, old.control, |